import { Injectable, UnauthorizedException, ForbiddenException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { ConfigService } from '@nestjs/config';
import { ClsService } from 'nestjs-cls';
import { AuthService, JwtPayload } from '../auth.service';
import { CLS_USER_ID, CLS_TENANT_ID } from '../../common/cls/cls.constants';

/**
 * JwtStrategy — validates JWT and stores user_id in CLS.
 *
 * Per CLAUDE.md:
 * - created_by and updated_by also read from ClsService automatically
 * - User context stored in CLS after JWT validation
 */
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(
    configService: ConfigService,
    private readonly authService: AuthService,
    private readonly cls: ClsService,
  ) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: configService.get<string>('JWT_SECRET')!,
    });
  }

  async validate(payload: JwtPayload) {
    const user = await this.authService.validateUserFromToken(payload);

    if (!user) {
      throw new UnauthorizedException('Invalid or expired session');
    }

    // SECURITY: Cross-verify JWT tenant_id matches CLS tenant_id (set by TenantMiddleware)
    // Prevents user from Tenant A sending X-Tenant-Id header for Tenant B
    const clsTenantId = this.cls.get<string>(CLS_TENANT_ID);
    if (!clsTenantId) {
      throw new ForbiddenException('Tenant context missing');
    }
    if (clsTenantId !== user.tenant_id) {
      throw new ForbiddenException('Tenant mismatch: your account does not belong to this tenant');
    }

    // Store user_id in CLS for automatic audit trail (created_by, updated_by)
    this.cls.set(CLS_USER_ID, user.id);

    return {
      id: user.id,
      email: user.email,
      name: user.name,
      tenant_id: user.tenant_id,
      role: user.role,
    };
  }
}
