import { Injectable, Logger } from '@nestjs/common';
import { Repository } from 'typeorm';
import { ApiKey, ApiKeyTier } from '../entities/api-key.entity';
import * as crypto from 'crypto';
import { InjectRepository } from '@nestjs/typeorm';

@Injectable()
export class ApiKeyRepository extends Repository<ApiKey> {
  private readonly logger = new Logger(ApiKeyRepository.name);

  constructor(
    @InjectRepository(ApiKey)
    private readonly apiKeyRepo: Repository<ApiKey>,
  ) {
    super(apiKeyRepo.target, apiKeyRepo.manager, apiKeyRepo.queryRunner);
  }

  async createApiKey(
    userId: string,
    name: string,
    permissions: string[] = [],
    tier: ApiKeyTier = ApiKeyTier.FREE,
    limits: { minuteLimit: number; dailyLimit: number; monthlyLimit: number },
  ): Promise<ApiKey> {
    const key = this.generateApiKey();
    const apiKey = this.apiKeyRepo.create({
      key,
      name,
      permissions,
      userId,
      tier,
      minuteLimit: limits.minuteLimit,
      dailyLimit: limits.dailyLimit,
      monthlyLimit: limits.monthlyLimit,
      isActive: true,
      lastMinuteReset: new Date(),
      lastDailyReset: new Date(),
      lastMonthlyReset: new Date(),
    });

    this.logger.log(`Creating API key for user ${userId}`);
    return this.apiKeyRepo.save(apiKey);
  }

  private generateApiKey(): string {
    // Generate a random key with format: prefix_randomBytes
    const prefix = 'can';
    const randomBytes = crypto.randomBytes(24).toString('hex');
    return `${prefix}_${randomBytes}`;
  }


  async findByKey(key: string): Promise<ApiKey | null> {
    return this.findOne({
      where: { key, isActive: true },
      relations: ['user'],
      select: {
        id: true,
        key: true,
        name: true,
        permissions: true,
        isActive: true,
        usageCount: true,
        user: {
          id: true,
          email: true,
        },
      },
    });
  }

  async incrementUsage(id: string): Promise<void> {
    await this.createQueryBuilder()
      .update(ApiKey)
      .set({
        lastUsedAt: new Date(),
        usageCount: () => '"usageCount" + 1',
      })
      .where('id = :id', { id })
      .execute();
  }
}
