import { RedisService } from '../../utils/RedisService';
import { logger } from '../../utils/logger';
import db from '../../config/database';

/**
 * [BIZ_KER_126] 租户静态文件存储配额控制 (S3 Quota)
 * @description 核心逻辑：监控各租户在 OSS/S3 上的静态文件占用情况。
 * 实现配额限制逻辑，当租户存储占用达到阈值（如 80%）时触发预警，达到 100% 时限制上传。
 * 遵循 Autocomplete-First (V31.5) 规范。
 */
export class S3QuotaManager {
  private static readonly QUOTA_TABLE = 'cf_tenant_s3_quotas';
  private static readonly CACHE_PREFIX = 's3_quota:';

  /**
   * 初始化存储配额表
   */
  static async initTable() {
    const hasTable = await db.schema.hasTable(this.QUOTA_TABLE);
    if (!hasTable) {
      logger.info(`📦 Creating ${this.QUOTA_TABLE} table...`);
      await db.schema.createTable(this.QUOTA_TABLE, (table) => {
        table.increments('id').primary();
        table.string('tenant_id', 64).notNullable().unique();
        table.bigInteger('max_bytes').defaultTo(1073741824); // 默认 1GB
        table.bigInteger('used_bytes').defaultTo(0);
        table.float('alert_threshold').defaultTo(0.8); // 80% 触发预警
        table.timestamp('updated_at').defaultTo(db.fn.now());
      });
      logger.info(`✅ Table ${this.QUOTA_TABLE} created`);
    }
  }

  /**
   * 检查租户是否还有存储配额
   * @param tenantId 租户 ID
   * @param uploadSizePending 准备上传的文件大小（字节）
   * @returns 是否允许上传
   */
  static async checkQuota(tenantId: string, uploadSizePending: number): Promise<boolean> {
    try {
      // 1. 从缓存获取配额信息
      const cacheKey = `${this.CACHE_PREFIX}${tenantId}`;
      let quota = await RedisService.get(cacheKey);

      if (!quota) {
        const dbQuota = await db(this.QUOTA_TABLE).where({ tenant_id: tenantId }).first();
        if (!dbQuota) return true; // 未配置配额则默认不限制
        quota = JSON.stringify(dbQuota);
        await RedisService.set(cacheKey, quota, 3600);
      }

      const { max_bytes, used_bytes, alert_threshold } = JSON.parse(quota);

      // 2. 校验硬限制
      if (used_bytes + uploadSizePending > max_bytes) {
        logger.warn(`[S3Quota] Tenant ${tenantId} exceeded storage quota.`);
        return false;
      }

      // 3. 校验预警阈值
      if ((used_bytes + uploadSizePending) / max_bytes >= alert_threshold) {
        logger.info(`[S3Quota] Tenant ${tenantId} storage usage reached alert threshold.`);
        // 实际场景应触发通知推送
      }

      return true;
    } catch (err: any) {
      logger.error(`[S3Quota] Quota check failed: ${err.message}`);
      return true; // 容错：校验失败允许上传 (Fail-Open)
    }
  }

  /**
   * 更新租户已使用存储空间
   * @param tenantId 租户 ID
   * @param bytesDelta 变化的大小（可正可负）
   */
  static async updateUsage(tenantId: string, bytesDelta: number) {
    try {
      await db(this.QUOTA_TABLE)
        .where({ tenant_id: tenantId })
        .increment('used_bytes', bytesDelta)
        .update({ updated_at: new Date() });
      
      // 清除缓存
      await RedisService.getClient().del(`${this.CACHE_PREFIX}${tenantId}`);
    } catch (err: any) {
      logger.error(`[S3Quota] Failed to update usage for ${tenantId}: ${err.message}`);
    }
  }
}
