import * as argon2 from "argon2";
import { IsBoolean, IsEmail, IsOptional, IsPhoneNumber, IsString } from 'class-validator';
import { getConnectionManager } from 'typeorm';
import * as uuid from 'uuid';
import { config } from '../../config';
import { UsernameOrEmailNeededError } from '../../errors/UserErrors';
import { UserGroupNotFoundError } from '../../errors/UserGroupErrors';
import { User } from '../entities/User';
import { UserGroup } from '../entities/UserGroup';

/**
 * This classed is used to create a new User entity from a json body (post request).
 */
export class CreateUser {
    /**
     * The new user's first name.
     */
    @IsString()
    firstname: string;

    /**
     * The new user's middle name.
     */
    @IsString()
    @IsOptional()
    middlename?: string;

    /**
     * The new user's last name.
     */
    @IsString()
    lastname: string;

    /**
     * The new user's username.
     * You have to provide at least one of: {email, username}.
     */
    @IsOptional()
    @IsString()
    username?: string;

    /**
     * The new user's email address.
     * You have to provide at least one of: {email, username}.
     */
    @IsEmail()
    @IsString()
    @IsOptional()
    email?: string;

    /**
     * The new user's phone number.
     * This will be validated against the configured country phone numer syntax (default: international).
     */
    @IsPhoneNumber(config.phone_validation_countrycode)
    @IsOptional()
    phone?: string;

    /**
     * The new user's password.
     * This will of course not be saved in plaintext :)
     */
    @IsString()
    password: string;

    /**
     * Will the new user be enabled from the start?
     * Default: true
     */
    @IsBoolean()
    @IsOptional()
    enabled?: boolean = true;

    /**
     * The new user's groups' id(s).
     * You can provide either one groupId or an array of groupIDs.
     */
    @IsOptional()
    groups?: number[] | number

    //TODO: ProfilePics

    /**
     * Converts this to a User entity.
     */
    public async toUser(): Promise<User> {
        let newUser: User = new User();

        if (this.email === undefined && this.username === undefined) {
            throw new UsernameOrEmailNeededError();
        }

        newUser.email = this.email
        newUser.username = this.username
        newUser.firstname = this.firstname
        newUser.middlename = this.middlename
        newUser.lastname = this.lastname
        newUser.uuid = uuid.v4()
        newUser.phone = this.phone
        newUser.password = await argon2.hash(this.password + newUser.uuid);
        newUser.groups = await this.getGroups();
        newUser.enabled = this.enabled;
        //TODO: ProfilePics

        return newUser;
    }

    /**
     * Get's all groups for this user by their id's;
     */
    public async getGroups() {
        if (!this.groups) { return null; }
        let groups = new Array<UserGroup>();
        if (!Array.isArray(this.groups)) {
            this.groups = [this.groups]
        }
        for (let group of this.groups) {
            let found = await getConnectionManager().get().getRepository(UserGroup).findOne({ id: group });
            if (!found) { throw new UserGroupNotFoundError(); }
            groups.push(found);
        }
        return groups;
    }
}