// auth.middleware.ts

import {
  ForbiddenException,
  HttpStatus,
  Injectable,
  NestMiddleware,
  UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { NextFunction, Request, Response } from 'express';
import { AdminsService } from '@/modules/admins/services/admins.service';
import { AuthService } from '@/modules/auth/auth.service';
import { plainToClass } from 'class-transformer';
import Admin from '@/modules/admins/entities/admin.entity';
import AppResponse from '@/response/app-response';

@Injectable()
export class AuthenticationMiddleware implements NestMiddleware {
  constructor(
    private readonly jwtService: JwtService,
    private readonly adminService: AdminsService,
    private readonly authService: AuthService,
  ) {}

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

    if (!admin) {
      return next(
        new UnauthorizedException(
          AppResponse.toResponse(null, {
            message: 'User is invalid',
            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: 'Please login to app',
            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: 'Token is invalid',
              status_code: HttpStatus.FORBIDDEN,
            }),
          ),
        );
      }

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

      req['admin'] = plainToClass(Admin, admin);
      next();
    } catch (error) {
      try {
        const result = await this.jwtService.verify(refresh_token);
        const admin = (await this.validate(result, next)) as Admin;

        await this.authService.login(admin, res);
        req['admin'] = plainToClass(Admin, admin);
        next();
      } catch (error) {
        return next(
          new UnauthorizedException(
            AppResponse.toResponse(null, {
              message: 'Token is expired',
              status_code: HttpStatus.UNAUTHORIZED,
            }),
          ),
        );
      }
    }
  }
}
