// auth.middleware.ts

import Auth from '@/entities/core/auth';

import AppResponse from '@/system/response/ktq-response';
import { classToPlain } from '@nestjs/class-transformer';
import {
  ForbiddenException,
  HttpStatus,
  NestMiddleware,
  UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { NextFunction, Request, Response } from 'express';
import { Repository } from 'typeorm';
import { AuthService } from '../services/auth.service';
import { Constant } from '../../../ultils/constant';
import { SystemLang } from '@/system/lang/system.lang';

export class AuthenticationMiddleware<T extends Auth>
  implements NestMiddleware
{
  constructor(
    protected readonly jwtService: JwtService,
    protected readonly authRepo: Repository<T>,
    protected readonly authService: AuthService<T>,
  ) {}

  async validate(result: Record<string, any>, next: NextFunction) {
    const admin = await this.authRepo.findOne({
      where: { id: result?._id, is_login_enabled: true, active: true } as any,
    });

    if (!admin) {
      return next(
        new UnauthorizedException(
          AppResponse.toResponse(null, {
            message: SystemLang.getText('messages', 'unauthorized'),
            status_code: HttpStatus.UNAUTHORIZED,
            bonus: { redirect: true },
          }),
        ),
      );
    }

    return admin;
  }
  async use(req: Request, res: Response, next: NextFunction) {
    const { access_token, refresh_token }: Record<string, any> = req.cookies;

    if (!access_token && !refresh_token) {
      return next(
        new UnauthorizedException(
          AppResponse.toResponse(false, {
            message: SystemLang.getText('messages', 'unauthorized'),
            status_code: HttpStatus.UNAUTHORIZED,
            bonus: { redirect: true },
          }),
        ),
      );
    }

    const resultValidToken = await this.authService.isValidTokens({
      refresh_token,
      access_token,
    });

    if (!resultValidToken) {
      return next(
        new UnauthorizedException(
          AppResponse.toResponse(false, {
            message: SystemLang.getText('messages', 'unauthorized'),
            status_code: HttpStatus.UNAUTHORIZED,
            bonus: { redirect: true },
          }),
        ),
      );
    }

    try {
      const result = await this.jwtService.verify(access_token);

      if (result.refresh_key || !result?._id) {
        return next(
          new ForbiddenException(
            AppResponse.toResponse(null, {
              message: SystemLang.getText('messages', 'forbidden'),
              status_code: HttpStatus.FORBIDDEN,
            }),
          ),
        );
      }

      const user = await this.validate(result, next);

      req[Constant.ATTR_REQ_DATA] = classToPlain(user);
      next();
    } catch (error) {
      try {
        const result = await this.jwtService.verify(refresh_token);
        const user = (await this.validate(result, next)) as T;

        await this.authService.login(user, res);
        req[Constant.ATTR_REQ_DATA] = classToPlain(user);
        next();
      } catch (error) {
        await this.authService.logout(req, res);
        return next(
          new UnauthorizedException(
            AppResponse.toResponse(null, {
              message: SystemLang.getText('messages', 'unauthorized'),
              status_code: HttpStatus.UNAUTHORIZED,
            }),
          ),
        );
      }
    }
  }
}
