import { IServerError } from "@/contexts/common/domain/errors";
import { PassportStrategyController } from "@/contexts/common/infrastructure/express";
import { ensureLogin_DTOIsValid } from "@shared/contexts";
import { Strategy as EmailStrategy, IVerifyOptions } from "passport-local";

import { LoginUseCase } from "@/contexts/auth/application";
import { AuthUser } from "@/contexts/auth/domain";
import { ICommonContext } from "@/contexts/common/infrastructure";
import { IAuthContext } from "../../Auth.context";
import { registerAuthRepository } from "../../Auth.repository";

const strategyOpts = {
  usernameField: "email", // Campo utilizado para el email en el formulario
  passwordField: "password",
};

class EmailStrategyController extends PassportStrategyController {
  private useCase: LoginUseCase;
  private context: IAuthContext;

  constructor(
    props: {
      useCase: LoginUseCase;
    },
    context: any
  ) {
    super();

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

  public async verifyStrategy(
    email: string,
    password: string,
    done: (error: any, user?: AuthUser | false, options?: IVerifyOptions) => void
  ) {
    const loginDTOOrError = ensureLogin_DTOIsValid({ email, password });

    if (loginDTOOrError.isFailure) {
      return done(null, false);
    }

    try {
      const result = await this.useCase.execute({ email, password });
      if (result.isFailure) {
        return done(null, false);
      }

      return done(null, result.object);
    } catch (e: unknown) {
      return done(e as IServerError);
    }
  }
}

export const initEmailStrategy = (context: ICommonContext) =>
  new EmailStrategy(strategyOpts, async (username, password, done) => {
    registerAuthRepository(context as IAuthContext);
    return new EmailStrategyController(
      {
        useCase: new LoginUseCase(context),
      },
      context
    ).verifyStrategy(username, password, done);
  });
