import { logger } from '../../utils/logger';
import db from '../../config/database';
import { TurboGateway } from '../gateway/TurboGateway';
import { FeatureGovernanceService } from '../governance/FeatureGovernanceService';

export interface QuotaConfig {
  tenantId: string;
  resourceType: 'API_REQUEST' | 'AI_TOKEN' | 'STORAGE_MB' | 'NODE_COUNT';
  softLimit: number; // 软限制：触发预警
  hardLimit: number; // 硬限制：直接熔断
  windowMs: number; // 统计周期
}

export interface QuotaUsage {
  currentUsage: number;
  resetAt: Date;
  isThrottled: boolean;
  isBroken: boolean; // 是否处于熔断状态
}

/**
 * [BIZ_GOV_07] 租户配额超支自动限流与熔断策略 (Quota Circuit Breaker)
 * @description 核心逻辑：基于 Redis 实时统计租户资源消耗，支持软限制预警与硬限制熔断。
 * 集成 [TurboGateway] 的限流能力与 [FeatureGovernanceService] 的全局开关。
 */
export class QuotaGovernanceService {
  private static readonly QUOTA_CONFIG_TABLE = 'cf_tenant_quotas';
  private static readonly QUOTA_LOG_TABLE = 'cf_quota_violations';

  /**
   * 初始化数据库表
   */
  static async initTable() {
    const hasConfigTable = await db.schema.hasTable(this.QUOTA_CONFIG_TABLE);
    if (!hasConfigTable) {
      logger.info(`📦 Creating ${this.QUOTA_CONFIG_TABLE} table...`);
      await db.schema.createTable(this.QUOTA_CONFIG_TABLE, (table) => {
        table.increments('id').primary();
        table.string('tenant_id', 64).notNullable().index();
        table.string('resource_type', 32).notNullable();
        table.bigInteger('soft_limit').defaultTo(1000);
        table.bigInteger('hard_limit').defaultTo(2000);
        table.integer('window_ms').defaultTo(3600000); // 默认 1 小时
        table.timestamps(true, true);
        table.unique(['tenant_id', 'resource_type']);
      });
    }

    const hasLogTable = await db.schema.hasTable(this.QUOTA_LOG_TABLE);
    if (!hasLogTable) {
      logger.info(`📦 Creating ${this.QUOTA_LOG_TABLE} table...`);
      await db.schema.createTable(this.QUOTA_LOG_TABLE, (table) => {
        table.increments('id').primary();
        table.string('tenant_id', 64).notNullable();
        table.string('resource_type', 32).notNullable();
        table.string('violation_type', 32).notNullable(); // SOFT_LIMIT, HARD_LIMIT
        table.bigInteger('usage_at_violation');
        table.timestamp('created_at').defaultTo(db.fn.now());
      });
    }
  }

  /**
   * 检查并扣减配额 (核心熔断逻辑)
   */
  static async checkAndConsume(params: {
    tenantId: string;
    resourceType: QuotaConfig['resourceType'];
    amount?: number;
  }): Promise<{ allowed: boolean; reason?: string }> {
    const { tenantId, resourceType, amount = 1 } = params;

    // 1. 全局开关检查
    if (!(await FeatureGovernanceService.isEnabled('BIZ_GOV_QUOTA_BREAKER', tenantId))) {
      return { allowed: true };
    }

    try {
      // 2. 获取租户配额配置 (带缓存)
      const config = await this.getQuotaConfig(tenantId, resourceType);
      if (!config) return { allowed: true }; // 未配置配额则不限流

      // 3. Redis 实时计数
      const redisKey = `quota:${tenantId}:${resourceType}`;
      const currentUsage = await TurboGateway.increment(redisKey, config.windowMs, amount);

      // 4. 硬限制熔断检查
      if (currentUsage >= config.hardLimit) {
        await this.logViolation(tenantId, resourceType, 'HARD_LIMIT', currentUsage);
        logger.error(`[QuotaBreaker] HARD LIMIT BROKEN for ${tenantId} on ${resourceType}: ${currentUsage}/${config.hardLimit}`);
        return { allowed: false, reason: 'HARD_LIMIT_EXCEEDED' };
      }

      // 5. 软限制预警检查
      if (currentUsage >= config.softLimit) {
        await this.logViolation(tenantId, resourceType, 'SOFT_LIMIT', currentUsage);
        logger.warn(`[QuotaBreaker] SOFT LIMIT REACHED for ${tenantId} on ${resourceType}: ${currentUsage}/${config.softLimit}`);
        // 软限制不阻断，但可以触发降级逻辑或预警通知
      }

      return { allowed: true };
    } catch (err: any) {
      logger.error(`[QuotaBreaker] Check failed: ${err.message}`);
      return { allowed: true }; // 故障回退：允许通过
    }
  }

  /**
   * 获取配额配置 (L2 缓存优化)
   */
  private static async getQuotaConfig(tenantId: string, resourceType: string): Promise<QuotaConfig | null> {
    const cacheKey = `quota:config:${tenantId}:${resourceType}`;
    let config = await TurboGateway.getL2(cacheKey);

    if (!config) {
      const dbConfig = await db(this.QUOTA_CONFIG_TABLE)
        .where({ tenant_id: tenantId, resource_type: resourceType })
        .first();
      
      if (dbConfig) {
        config = {
          tenantId: dbConfig.tenant_id,
          resourceType: dbConfig.resource_type as any,
          softLimit: dbConfig.soft_limit,
          hardLimit: dbConfig.hard_limit,
          windowMs: dbConfig.window_ms
        };
        await TurboGateway.setL2(cacheKey, config, 3600); // 缓存 1 小时
      }
    }

    return config;
  }

  /**
   * 记录违规记录
   */
  private static async logViolation(tenantId: string, resourceType: string, type: string, usage: number) {
    // 限制写频率，同一租户同一类型 1 分钟内只写一次日志
    const throttleKey = `quota:violation_log_lock:${tenantId}:${resourceType}:${type}`;
    const isLocked = await TurboGateway.getL2(throttleKey);
    if (isLocked) return;

    await db(this.QUOTA_LOG_TABLE).insert({
      tenant_id: tenantId,
      resource_type: resourceType,
      violation_type: type,
      usage_at_violation: usage,
      created_at: new Date()
    });

    await TurboGateway.setL2(throttleKey, true, 60);
  }
}
