import { Request, Response } from "express";
import { JWTHelper } from "../helpers/jwtHelper";
import { JWTToken } from "../type/jwtTypes";
import InternalException from "../exceptions/internalException";
import RefreshCommandHandler from "../command/refreshCommandHandler";
import { CreateRefreshCommand, DeleteRefreshCommand } from "../command/refreshCommand";
import UserService from "../service/user/userService";
import speakeasy from "speakeasy";
import UnauthorizedRequestException from "../exceptions/unauthorizedRequestException";
import RefreshService from "../service/refreshService";
import UserPermissionService from "../service/user/userPermissionService";
import PermissionHelper from "../helpers/permissionHelper";
import RolePermissionService from "../service/user/rolePermissionService";

/**
 * @description Check authentication status by token
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function login(req: Request, res: Response): Promise<any> {
  let username = req.body.username;
  let totp = req.body.totp;

  let { id, secret } = await UserService.getByUsername(username);

  let valid = speakeasy.totp.verify({
    secret: secret,
    encoding: "base32",
    token: totp,
    window: 2,
  });

  if (!valid) {
    throw new UnauthorizedRequestException("Token not valid or expired");
  }

  let accessToken = await JWTHelper.buildToken(id);

  let refreshCommand: CreateRefreshCommand = {
    userId: id,
  };
  let refreshToken = await RefreshCommandHandler.create(refreshCommand);

  res.json({
    accessToken,
    refreshToken,
  });
}

/**
 * @description logout user by token (invalidate refresh token)
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function logout(req: Request, res: Response): Promise<any> {}

/**
 * @description refresh expired token
 * @param req {Request} Express req object
 * @param res {Response} Express res object
 * @returns {Promise<*>}
 */
export async function refresh(req: Request, res: Response): Promise<any> {
  let token = req.body.accessToken;
  let refresh = req.body.refreshToken;

  const tokenUser = await JWTHelper.decode(token);
  if (typeof tokenUser == "string" || !tokenUser) {
    throw new InternalException("process failed");
  }

  let tokenUserId = (tokenUser as JWTToken).userId;

  let { user } = await RefreshService.getByToken(refresh);

  if (tokenUserId != user.id) {
    throw new UnauthorizedRequestException("user not identified with token and refresh");
  }

  let accessToken = await JWTHelper.buildToken(tokenUserId);

  let refreshCommand: CreateRefreshCommand = {
    userId: tokenUserId,
  };
  let refreshToken = await RefreshCommandHandler.create(refreshCommand);

  let removeToken: DeleteRefreshCommand = {
    userId: tokenUserId,
    token: refresh,
  };
  await RefreshCommandHandler.deleteByToken(removeToken);

  res.json({
    accessToken,
    refreshToken,
  });
}