import { IsBoolean, IsEmail, IsInt, IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator';
import * as jsonwebtoken from "jsonwebtoken";
import { config } from './config';
import { Runner } from './models/entities/Runner';
import { User } from './models/entities/User';

/**
 * This class is responsible for all things JWT creation.
 */
export class JwtCreator {
    /**
     * Creates a new refresh token for a given user
     * @param user User entity that the refresh token shall be created for
     * @param expiry_timestamp Timestamp for the token expiry. Will be generated if not provided.
     */
    public static createRefresh(user: User, expiry_timestamp?: number) {
        if (!expiry_timestamp) { expiry_timestamp = Math.floor(Date.now() / 1000) + 10 * 36000; }
        return jsonwebtoken.sign({
            refreshTokenCount: user.refreshTokenCount,
            id: user.id,
            exp: expiry_timestamp
        }, config.jwt_secret)
    }

    /**
     * Creates a new access token for a given user
     * @param user User entity that the access token shall be created for
     * @param expiry_timestamp Timestamp for the token expiry. Will be generated if not provided.
     */
    public static createAccess(user: User, expiry_timestamp?: number) {
        if (!expiry_timestamp) { expiry_timestamp = Math.floor(Date.now() / 1000) + 10 * 36000; }
        return jsonwebtoken.sign({
            userdetails: new JwtUser(user),
            exp: expiry_timestamp
        }, config.jwt_secret)
    }

    /**
     * Creates a new selfservice token for a given runner.
     * @param runner Runner entity that the access token shall be created for.
     * @param expiry_timestamp Timestamp for the token expiry. Will be set about 9999 years if none provided.
     */
    public static createSelfService(runner: Runner, expiry_timestamp?: number) {
        if (!expiry_timestamp) { expiry_timestamp = Math.floor(Date.now() / 1000) + 36000 * 60 * 24 * 365 * 9999; }
        return jsonwebtoken.sign({
            id: runner.id,
            exp: expiry_timestamp
        }, config.jwt_secret)
    }

    /**
     * Creates a new password reset token for a given user.
     * The token is valid for 15 minutes or 1 use - whatever comes first.
     * @param user User entity that the password reset token shall be created for
     */
    public static createReset(user: User) {
        let expiry_timestamp = Math.floor(Date.now() / 1000) + 15 * 60;
        return jsonwebtoken.sign({
            id: user.id,
            refreshTokenCount: user.refreshTokenCount,
            exp: expiry_timestamp
        }, config.jwt_secret)
    }
}

/**
 * Special variant of the user class that 
 */
export class JwtUser {
    @IsInt()
    id: number;

    @IsUUID(4)
    uuid: string;

    @IsOptional()
    @IsEmail()
    email?: string;

    @IsOptional()
    @IsString()
    username?: string;

    @IsString()
    @IsNotEmpty()
    firstname: string;

    @IsString()
    @IsOptional()
    middlename?: string;

    @IsString()
    @IsNotEmpty()
    lastname: string;

    permissions: string[];

    @IsBoolean()
    enabled: boolean;

    @IsInt()
    @IsNotEmpty()
    refreshTokenCount?: number;

    @IsString()
    @IsOptional()
    profilePic?: string;

    /**
     * Creates a new instance of this class based on a provided user entity.
     * @param user User entity that shall be encapsulated in a jwt.
     */
    public constructor(user: User) {
        this.id = user.id;
        this.firstname = user.firstname;
        this.middlename = user.middlename;
        this.lastname = user.lastname;
        this.username = user.username;
        this.email = user.email;
        this.refreshTokenCount = user.refreshTokenCount;
        this.uuid = user.uuid;
        this.profilePic = user.profilePic;
        this.permissions = user.allPermissions;
    }
}