import { HttpException, Injectable, Logger } from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
import { ApiKeyRepository } from './repositories/api-key.repository';
import { CreateApiKeyDto } from './dto/api-create.dto';
import { ApiKeyResponseDto } from './dto/api-response.dto';
import { ApiKeyTier } from './entities/api-key.entity';

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

  constructor(private apiKeyRepository: ApiKeyRepository) {}

  async generateApiKey(userId: string, createApiKeyDto: CreateApiKeyDto): Promise<ApiKeyResponseDto> {
    try {
      const { name, permissions, tier } = createApiKeyDto;

      const limits = this.getRateLimitsByTier(tier);

      const apiKey = await this.apiKeyRepository.createApiKey(userId, name, permissions, tier, limits);

      return plainToInstance(
        ApiKeyResponseDto,
        {
          ...apiKey,
          key: apiKey.key, // Expose key only on creation
        },
        {
          excludeExtraneousValues: true,
        },
      );
    } catch (error) {
      this.logger.error(`Failed to generate API key: ${error.message}`);
      throw new HttpException('Failed to generate API key', 500);
    }
  }

  private getRateLimitsByTier(tier: ApiKeyTier) {
    switch (tier) {
      case ApiKeyTier.BUSINESS:
        return {
          minuteLimit: 500, // Higher per-minute limit for business
          dailyLimit: 5000, // Higher daily limit
          monthlyLimit: 50000, // 50k monthly limit as specified
        };
      case ApiKeyTier.FREE:
      default:
        return {
          minuteLimit: 100, // 100 per minute as specified
          dailyLimit: 1000, // 1000 per day as specified
          monthlyLimit: 10000, // 10k monthly limit as specified
        };
    }
  }

  async revokeApiKey(userId: string, apiKeyId: string): Promise<void> {
    try {
      await this.apiKeyRepository.update({ id: apiKeyId, userId }, { isActive: false });
      this.logger.log(`API key revoked: ${apiKeyId} for user ${userId}`);
    } catch (error) {
      this.logger.error(`Failed to revoke API key: ${error.message}`);
      throw error;
    }
  }

  async listApiKeys(userId: string): Promise<ApiKeyResponseDto[]> {
    const apiKeys = await this.apiKeyRepository.find({
      where: { userId, isActive: true },
      order: { createdAt: 'DESC' },
    });

    return plainToInstance(ApiKeyResponseDto, apiKeys, {
      excludeExtraneousValues: true,
    });
  }


  async findUserApiKey(userId: string, apiKeyId: string): Promise<any> {
    return this.apiKeyRepository.findOne({
      where: { id: apiKeyId, userId },
    });
  }
}
