import { IsOptional, IsString } from 'class-validator';
import * as jsonwebtoken from 'jsonwebtoken';
import { getConnectionManager } from 'typeorm';
import { config } from '../../config';
import { IllegalJWTError, JwtNotProvidedError, RefreshTokenCountInvalidError, UserNotFoundError } from '../../errors/AuthError';
import { User } from '../entities/User';
import { Logout } from '../responses/ResponseLogout';

/**
 * This class handels a user logging out of the system.
 * Of course it check's the user's provided credential (token) before logging him out.
 */
export class HandleLogout {
    /**
     * A stringyfied jwt access token.
     * Will get checked for validity.
     */
    @IsString()
    @IsOptional()
    token?: string;

    /**
     * Logs the user out.
     * This gets achived by increasing the user's refresh token count, thereby invalidateing all currently existing jwts for that user.
     */
    public async logout(): Promise<Logout> {
        let logout: Logout = new Logout();
        if (!this.token || this.token === undefined) {
            throw new JwtNotProvidedError()
        }
        let decoded;
        try {
            decoded = jsonwebtoken.verify(this.token, config.jwt_secret)
        } catch (error) {
            throw new IllegalJWTError()
        }
        logout.timestamp = Math.floor(Date.now() / 1000)
        let found_user: User = await getConnectionManager().get().getRepository(User).findOne({ id: decoded["id"] });
        if (!found_user) {
            throw new UserNotFoundError()
        }
        if (found_user.refreshTokenCount !== decoded["refreshTokenCount"]) {
            throw new RefreshTokenCountInvalidError()
        }
        found_user.refreshTokenCount++;
        await getConnectionManager().get().getRepository(User).update({ id: found_user.id }, found_user)
        return logout;
    }
}