import { config } from "@/config";
import { FindUserByEmailUseCase } from "@/contexts/auth/application/FindUserByEmail.useCase";
import { IServerError } from "@/contexts/common/domain/errors";
import { createCommonContext, ICommonContext } from "@/contexts/common/infrastructure";
import { PassportStrategyController } from "@/contexts/common/infrastructure/express";
import { ExtractJwt, Strategy as JWTStrategy, VerifiedCallback } from "passport-jwt";
import { IAuthContext } from "../../Auth.context";
import { registerAuthRepository } from "../../Auth.repository";

const strategyOpts = {
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // Extract the JWT from the Authorization header
  secretOrKey: config.jwt.secret_key,
};

class JWTStrategyController extends PassportStrategyController {
  private useCase: FindUserByEmailUseCase;
  private context: IAuthContext;

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

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

  public async verifyStrategy(payload: any, done: VerifiedCallback) {
    const { email } = payload;

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

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

export const initJWTStrategy = (context: ICommonContext) =>
  new JWTStrategy(strategyOpts, async (payload, done) => {
    const context = createCommonContext();
    registerAuthRepository(context as IAuthContext);
    return new JWTStrategyController(
      {
        useCase: new FindUserByEmailUseCase(context),
      },
      context
    ).verifyStrategy(payload, done);
  });
