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

export interface MetricEvent {
  metricName: string;
  tenantId: string;
  value: number;
  tags?: Record<string, string>;
  timestamp?: number;
}

/**
 * [CORE_DEV_22] 基于流计算的毫秒级业务指标聚合 (Real-time Metrics)
 * @description 核心逻辑：提供高性能的指标上报与实时聚合能力。
 * 采用“内存窗口 + Redis 暂存 + 异步落库”的架构，支持千万级并发下的毫秒级业务指标聚合。
 * 扩展：增加 Redis 窗口计数器支持，增强 flush 逻辑。
 */
export class RealTimeMetricsService {
  private static readonly METRIC_WINDOW_MS = 1000; // 1秒窗口
  private static aggregationBuffer: Map<string, number> = new Map();
  private static flushTimer: NodeJS.Timeout | null = null;

  /**
   * 初始化表结构
   */
  static async initTable() {
    const hasTable = await db.schema.hasTable('cf_realtime_metrics');
    if (!hasTable) {
      logger.info('📦 Creating cf_realtime_metrics table...');
      await db.schema.createTable('cf_realtime_metrics', (table) => {
        table.increments('id').primary();
        table.string('tenant_id', 64).notNullable();
        table.string('metric_name', 128).notNullable();
        table.float('aggregated_value');
        table.string('window_type', 16).defaultTo('1S');
        table.json('tags');
        table.timestamp('bucket_time').index();
        table.timestamps(true, true);
        table.index(['tenant_id', 'metric_name', 'bucket_time']);
      });
      logger.info('✅ Table cf_realtime_metrics created');
    }

    // 启动定时刷盘
    if (!this.flushTimer) {
      this.flushTimer = setInterval(() => this.flushBuffer(), 5000); // 每5秒强制刷盘一次
    }
  }

  /**
   * 上报指标事件
   */
  static async recordMetric(event: MetricEvent) {
    const { metricName, tenantId, value, tags } = event;
    
    // 1. 全局开关检查
    if (!(await FeatureGovernanceService.isEnabled('CORE_DEV_REALTIME_METRICS', tenantId))) {
      return;
    }

    // 2. 快速写入 Redis 进行秒级聚合 (L2 计数器)
    const secondBucket = Math.floor(Date.now() / 1000);
    const redisKey = `metrics:${tenantId}:${metricName}:${secondBucket}`;
    try {
      await TurboGateway.increment(redisKey, 60000, value); // 1分钟过期
    } catch (err) {
      logger.error(`[RealTimeMetrics] Redis recording failed: ${err}`);
    }

    // 3. 内存缓冲区聚合 (L1 聚合)
    const bufferKey = `${tenantId}:${metricName}`;
    const current = this.aggregationBuffer.get(bufferKey) || 0;
    this.aggregationBuffer.set(bufferKey, current + value);

    // 4. 阈值触发刷盘
    if (this.aggregationBuffer.size > 500) {
      await this.flushBuffer();
    }
  }

  /**
   * 刷盘缓冲区到数据库
   */
  private static async flushBuffer() {
    if (this.aggregationBuffer.size === 0) return;

    const entries = Array.from(this.aggregationBuffer.entries());
    this.aggregationBuffer.clear();

    const timestamp = new Date();
    const records = entries.map(([key, value]) => {
      const lastColonIndex = key.lastIndexOf(':');
      // 注意：这里需要正确拆分 tenantId 和 metricName
      // 假设 key 是 tenantId:metricName
      const separatorIndex = key.indexOf(':');
      const tenantId = key.substring(0, separatorIndex);
      const metricName = key.substring(separatorIndex + 1);

      return {
        tenant_id: tenantId,
        metric_name: metricName,
        aggregated_value: value,
        bucket_time: timestamp,
        window_type: '1S'
      };
    });

    try {
      if (records.length > 0) {
        // 使用批量插入优化性能
        await db.batchInsert('cf_realtime_metrics', records, 100);
        logger.debug(`[RealTimeMetrics] Flushed ${records.length} aggregated metrics to DB`);
      }
    } catch (err: any) {
      logger.error(`[RealTimeMetrics] Flush failed: ${err.message}`);
      // 失败后尝试回填缓冲区 (简单处理)
      records.forEach(r => {
        const key = `${r.tenant_id}:${r.metric_name}`;
        this.aggregationBuffer.set(key, (this.aggregationBuffer.get(key) || 0) + r.aggregated_value);
      });
    }
  }

  /**
   * 查询实时指标
   */
  static async getLiveMetric(tenantId: string, metricName: string, minutes: number = 5): Promise<any[]> {
    return await db('cf_realtime_metrics')
      .where({ tenant_id: tenantId, metric_name: metricName })
      .andWhere('bucket_time', '>', new Date(Date.now() - minutes * 60 * 1000))
      .orderBy('bucket_time', 'asc');
  }

  /**
   * 获取租户实时 GMV (示例聚合查询)
   */
  static async getTenantGMV(tenantId: string, period: '1H' | '24H' = '1H'): Promise<number> {
    const minutes = period === '1H' ? 60 : 1440;
    const result = await db('cf_realtime_metrics')
      .where({ tenant_id: tenantId, metric_name: 'ORDER_GMV' })
      .andWhere('bucket_time', '>', new Date(Date.now() - minutes * 60 * 1000))
      .sum('aggregated_value as total');
    
    return result[0]?.total || 0;
  }
}
