import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

import { ApiKeysService } from '../api-keys/api-keys.service';
import { JwtAuthGuard } from './jwt-auth.guard';

/**
 * Combined Authentication Guard
 *
 * Replaces the global JwtAuthGuard to support two authentication methods:
 *
 * 1. **API Key** (`X-API-Key` header)
 *    - Validates the raw key against its stored SHA-256 hash
 *    - Checks the organisation subscription is GOLD or PLATINIUM in real-time
 *    - Sets request.user with full user/plan context
 *    - Available exclusively to Gold and Platinium subscribers
 *
 * 2. **JWT Bearer token** (`Authorization: Bearer <token>`)
 *    - Delegates to the existing Passport JWT strategy (unchanged behaviour)
 *    - Works for all subscription tiers (frontend access)
 *
 * Routes decorated with @Public() bypass both methods.
 *
 * Priority: API Key is checked first; if absent, falls back to JWT.
 */
@Injectable()
export class ApiKeyOrJwtGuard extends JwtAuthGuard {
  constructor(
    reflector: Reflector,
    private readonly apiKeysService: ApiKeysService
  ) {
    super(reflector);
  }

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest<Record<string, any>>();
    const rawApiKey: string | undefined = request.headers['x-api-key'];

    if (rawApiKey) {
      const userContext = await this.apiKeysService.validateAndGetUser(rawApiKey);

      if (!userContext) {
        throw new UnauthorizedException(
          "Clé API invalide, expirée ou votre abonnement ne permet plus l'accès API."
        );
      }

      request.user = userContext;
      return true;
    }

    // No API key header — use standard JWT flow (handles @Public() too)
    return super.canActivate(context) as Promise<boolean>;
  }
}
