import { Injectable, UnauthorizedException } from '@nestjs/common'
import { PassportStrategy } from '@nestjs/passport'
import { Request } from 'express'
import { ExtractJwt, Strategy } from 'passport-jwt'
import { User } from '@<%= npmScope %>/api/core/models'
import { AuthService } from '../auth.service';

function headerAndCookieExtractor(req: Request): string | null {
  const authHeaderToken = ExtractJwt.fromAuthHeaderAsBearerToken()(req)
  if (authHeaderToken) {
    return authHeaderToken
  }
  const cookieToken = cookieExtractor(req)
  if (cookieToken) {
    return cookieToken
  }
  return null
}

function cookieExtractor(req: Request): string | undefined {
  const name = process.env['API_COOKIE_NAME'] || '__session'
  return req?.cookies?.[name] ? req.cookies[name] : undefined
}

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly auth: AuthService) {
    const jwtSecret = process.env['JWT_SECRET'];
    if (!jwtSecret) {
      throw new Error('JWT_SECRET environment variable is not set');
    }

    super({
      jwtFromRequest: headerAndCookieExtractor,
      secretOrKey: jwtSecret,
      ignoreExpiration: false,
    })
  }

  async validate(payload: { userId: string }): Promise<User> {
    if (!payload || !payload.userId) {
      throw new UnauthorizedException('Invalid JWT payload.')
    }
    const user = await this.auth.validateUser(payload.userId)
    if (!user) {
      throw new UnauthorizedException('User from token not found or invalid.')
    }
    return user
  }
}
