import { Injectable, UnauthorizedException } from '@nestjs/common';
import { ContextIdFactory, ModuleRef } from '@nestjs/core';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { AuthService } from '../auth.service';
import { User, UsersService } from '../../users/users.service';
import { Request } from 'express';

@Injectable()
export class AccessTokenStrategy extends PassportStrategy(Strategy, 'accessToken') {
  constructor(
    private authService: AuthService,
    private moduleRef: ModuleRef
  ) {
    super({
      jwtFromRequest: ExtractJwt.fromExtractors([
        //ExtractJwt.fromAuthHeaderAsBearerToken(),
        function doubleSubmitCookieWithBearerExtractor(req) {
          return this.authService.parseReqToken(req);
        }
      ]),
      ignoreExpiration: false,
      secretOrKey: process.env.JWT_ACCESS_TOKEN_SECRET,
      // to access req from validate()
      passReqToCallback: true,
    });
  }

  async validate(
    req: Request,
    payload: {
      sub: number;
      username: string;
    }
  ): Promise<User | UnauthorizedException> {
    const { sub: user_id } = payload

    // "UserService" is a request-scoped provider
    // https://docs.nestjs.com/recipes/passport#request-scoped-strategies
    const contextId = ContextIdFactory.getByRequest(req);
    const usersService = await this.moduleRef.resolve(UsersService, contextId);

    // Get the user and their roles
    const user = await usersService.findByIdWithRoles(user_id);
    if (!user) throw new UnauthorizedException();

    // Add the user meta data to req.user
    return user;
  }
}
