import { CanActivate, ExecutionContext, Injectable, Logger, HttpException, HttpStatus } from '@nestjs/common';
import { Request } from 'express';
import { RateLimitService } from 'modules/feature/api-key/rate-limit/rate-limit.service';
import { ApiKeyRepository } from 'modules/feature/api-key/repositories/api-key.repository';

@Injectable()
export class ApiKeyGuard implements CanActivate {
  private readonly logger = new Logger(ApiKeyGuard.name);

  constructor(
    private apiKeyRepository: ApiKeyRepository,
    private rateLimitService: RateLimitService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    this.logger.log('Checking API key');
    const request = context.switchToHttp().getRequest<Request>();
    this.logger.debug(request.headers);
    const apiKey = this.extractApiKey(request);

    if (!apiKey) {
      throw new HttpException('API key is required', HttpStatus.UNAUTHORIZED);
    }

    // Find the API key in the database
    const apiKeyEntity = await this.apiKeyRepository.findOne({
      where: { key: apiKey, isActive: true },
      relations: ['user'],
    });

    if (!apiKeyEntity) {
      throw new HttpException('Invalid API key', HttpStatus.UNAUTHORIZED);
    }

    // Check if the key has the required permissions
    // You can implement this based on your route metadata
    // const requiredPermissions = this.reflector.get<string[]>('permissions', context.getHandler());
    // if (requiredPermissions && !this.hasPermissions(apiKeyEntity.permissions, requiredPermissions)) {
    //   throw new HttpException('Insufficient permissions', HttpStatus.FORBIDDEN);
    // }

    // Update usage statistics and check rate limits
    const isWithinLimits = await this.rateLimitService.checkAndIncrementUsage(apiKeyEntity.id);
    if (!isWithinLimits) {
      throw new HttpException('Rate limit exceeded', HttpStatus.TOO_MANY_REQUESTS);
    }

    // Add user and API key to request for controllers to use
    request['user'] = apiKeyEntity.user;
    request['apiKey'] = apiKeyEntity;

    return true;
  }

  private extractApiKey(request: Request): string | null {
    // Check in Authorization header (Bearer token)
    const authHeader = request.headers.authorization;
    this.logger.log('Checking Authorization header', authHeader);
    if (authHeader && authHeader.split(' ')[0] === 'Bearer') {
      this.logger.log('Found API key in Authorization header');
      return authHeader.split(' ')[1];
    }

    // Check in x-api-key header
    const apiKeyHeader = request.headers['x-api-key'];
    this.logger.log('Checking x-api-key header', apiKeyHeader);
    if (apiKeyHeader) {
      return Array.isArray(apiKeyHeader) ? apiKeyHeader[0] : apiKeyHeader;
    }

    // Check in query parameters
    this.logger.log('Checking query parameters', request.query);
    if (request.query.apiKey) {
      return request.query.apiKey as string;
    }
    return null;
  }
}
