import db from '../../config/database';
import { AIService } from '../../services/AIService';
import { logger } from '../../utils/logger';
import { FeatureGovernanceService } from '../governance/FeatureGovernanceService';

export interface LogCluster {
  pattern: string;
  count: number;
  lastSeenAt: Date;
  severity: 'INFO' | 'WARN' | 'ERROR';
}

/**
 * [CORE_LOG_03] 语义日志搜索与异常聚类 (Semantic Log)
 * @description 利用向量搜索与 AI 聚类能力，支持自然语言查询系统日志并自动归纳异常模式。
 */
export class SemanticLogService {
  private static readonly TABLE_NAME = 'cf_semantic_logs';

  /**
   * 初始化数据库表
   */
  static async initTable() {
    const hasTable = await db.schema.hasTable(this.TABLE_NAME);
    if (!hasTable) {
      logger.info(`📦 Creating ${this.TABLE_NAME} table...`);
      await db.schema.createTable(this.TABLE_NAME, (table) => {
        table.increments('id').primary();
        table.text('content').notNullable();
        table.string('level', 20);
        table.string('source', 50); // e.g., 'PIPELINE', 'AUTH', 'DB'
        table.text('vector_embedding'); // 存储日志内容的向量
        table.timestamps(true, true);
        table.index(['level', 'created_at']);
      });
    }
  }

  /**
   * 记录语义日志
   */
  static async logSemantic(content: string, level: string = 'INFO', source: string = 'SYSTEM') {
    // [BIZ_GOV_06] 功能开关校验
    if (!(await FeatureGovernanceService.isEnabled('CORE_LOG_SEMANTIC'))) {
      return;
    }

    try {
      // 1. 生成向量嵌入 (CORE_DEV_08)
      const embedding = await AIService.generateEmbedding(content);
      
      // 2. 写入数据库
      await db(this.TABLE_NAME).insert({
        content,
        level,
        source,
        vector_embedding: JSON.stringify(embedding),
        created_at: new Date(),
        updated_at: new Date()
      });
    } catch (err: any) {
      logger.error(`[SemanticLog] Failed to log: ${err.message}`);
    }
  }

  /**
   * 语义搜索日志
   * @description 通过自然语言查询语义最接近的系统日志
   */
  static async searchLogs(query: string, limit: number = 10) {
    try {
      const queryVector = await AIService.generateEmbedding(query);
      
      // 1. 获取近期日志候选集 (模拟向量检索，实际应使用 pgvector)
      const candidates = await db(this.TABLE_NAME)
        .orderBy('created_at', 'desc')
        .limit(100);

      // 2. 内存中计算相似度排序
      const results = candidates.map(log => {
        const logVector = JSON.parse(log.vector_embedding as string);
        const score = this.cosineSimilarity(queryVector, logVector);
        return { ...log, score };
      });

      return results
        .sort((a, b) => b.score - a.score)
        .slice(0, limit);
    } catch (err: any) {
      logger.error(`[SemanticLog] Search failed: ${err.message}`);
      return [];
    }
  }

  /**
   * 异常聚类：自动将相似报错归为一类 (CORE_LOG_03)
   * @description 基于向量距离进行聚类，返回模式及其发生次数
   */
  static async clusterAnomalies(limit: number = 20): Promise<LogCluster[]> {
    try {
      // 1. 获取近期 WARN/ERROR 级别的日志
      const logs = await db(this.TABLE_NAME)
        .whereIn('level', ['WARN', 'ERROR'])
        .orderBy('created_at', 'desc')
        .limit(200);

      if (logs.length === 0) return [];

      const clusters: LogCluster[] = [];

      for (const log of logs) {
        const logVector = JSON.parse(log.vector_embedding as string);
        let foundCluster = false;

        for (const cluster of clusters) {
          // 模拟聚类：如果相似度 > 0.85，归为同一类
          // 实际生产应使用 DBSCAN 或 K-Means 预聚合结果
          const similarity = this.cosineSimilarity(logVector, (cluster as any).centroid);
          if (similarity > 0.85) {
            cluster.count++;
            cluster.lastSeenAt = log.created_at > cluster.lastSeenAt ? log.created_at : cluster.lastSeenAt;
            foundCluster = true;
            break;
          }
        }

        if (!foundCluster) {
          clusters.push({
            pattern: log.content.substring(0, 100) + '...', // 提取特征模式
            count: 1,
            lastSeenAt: log.created_at,
            severity: log.level as any,
            centroid: logVector // 存储质心向量以便后续匹配
          } as any);
        }
      }

      return clusters.sort((a, b) => b.count - a.count).slice(0, limit);
    } catch (err: any) {
      logger.error(`[SemanticLog] Clustering failed: ${err.message}`);
      return [];
    }
  }

  private static cosineSimilarity(v1: number[], v2: number[]): number {
    if (!v1 || !v2 || v1.length !== v2.length) return 0;
    let dotProduct = 0;
    let mag1 = 0;
    let mag2 = 0;
    for (let i = 0; i < v1.length; i++) {
      dotProduct += v1[i] * v2[i];
      mag1 += v1[i] * v1[i];
      mag2 += v2[i] * v2[i];
    }
    const mag = Math.sqrt(mag1) * Math.sqrt(mag2);
    return mag === 0 ? 0 : dotProduct / mag;
  }
}
