import { config } from "@/config";
import { AuthUser } from "@/contexts/auth/domain";
import { IServerError } from "@/contexts/common/domain/errors";
import { InfrastructureError } from "@/contexts/common/infrastructure";
import { ExpressController } from "@/contexts/common/infrastructure/express";
import { ILogin_Response_DTO } from "@shared/contexts";
import { Request } from "express";
import JWT from "jsonwebtoken";
import { IAuthContext } from "../../../Auth.context";
import { ILoginPresenter, ILoginUser } from "./presenter";

interface AuthenticatedRequest extends Request {
  user?: AuthUser;
}

export class LoginController extends ExpressController {
  private presenter: ILoginPresenter;
  private context: IAuthContext;

  constructor(
    props: {
      presenter: ILoginPresenter;
    },
    context: IAuthContext
  ) {
    super();

    const { presenter } = props;
    this.presenter = presenter;
    this.context = context;
  }

  async executeImpl() {
    try {
      const req = this.req as AuthenticatedRequest;
      const user = <AuthUser>req.user;

      if (!user) {
        const errorMessage = "Unexpected missing user data";
        const infraError = InfrastructureError.create(
          InfrastructureError.UNEXCEPTED_ERROR,
          errorMessage
        );
        return this.internalServerError(errorMessage, infraError);
      }

      const loginUser: ILoginUser = {
        user,
        token: this._generateUserToken(user),
        refreshToken: this._generateUserRefreshToken(user),
      };

      return this.ok<ILogin_Response_DTO>(this.presenter.map(loginUser, this.context));
    } catch (e: unknown) {
      return this.fail(e as IServerError);
    }
  }

  private _generateUserToken(user: AuthUser) {
    return JWT.sign({ email: user.email.toString() }, config.jwt.secret_key, {
      expiresIn: config.jwt.token_expiration,
    });
  }

  private _generateUserRefreshToken(user: AuthUser) {
    return JWT.sign({ email: user.email.toString() }, config.jwt.refresh_secret_key, {
      expiresIn: config.jwt.refresh_token_expiration,
    });
  }
}
