import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { SearchType } from '@prisma/client';
import * as crypto from 'crypto';

export interface MetricsOverview {
  // 搜索统计
  searchStats: {
    today: number;
    thisWeek: number;
    thisMonth: number;
    byType: { keyword: number; semantic: number; hybrid: number };
    avgResponseTime: number;
  };
  // AI 问答统计
  qaStats: {
    today: number;
    thisWeek: number;
    thisMonth: number;
    avgConfidence: number;
    feedbackRate: { positive: number; negative: number; none: number };
    avgResponseTime: number;
    totalCost: number;
  };
  // 文档统计
  documentStats: {
    totalDocuments: number;
    totalArticles: number;
    indexedDocuments: number;
    pendingSync: number;
    failedSync: number;
  };
  // 用户活跃度
  userStats: {
    activeUsersToday: number;
    activeUsersWeek: number;
    activeUsersMonth: number;
  };
}

export interface SearchLogData {
  query: string;
  resultCount: number;
  responseTimeMs: number;
  searchType: SearchType;
  filters?: Record<string, any>;
}

@Injectable()
export class MetricsService {
  private readonly logger = new Logger(MetricsService.name);

  constructor(private readonly prisma: PrismaService) {}

  /**
   * 记录搜索日志（用户 ID 脱敏）
   */
  async logSearch(userId: string, data: SearchLogData): Promise<void> {
    const userIdHash = this.hashUserId(userId);

    await this.prisma.searchLog.create({
      data: {
        userIdHash,
        query: this.sanitizeQuery(data.query),
        resultCount: data.resultCount,
        responseTimeMs: data.responseTimeMs,
        searchType: data.searchType,
        filters: data.filters,
      },
    });
  }

  /**
   * 获取度量概览
   */
  async getMetricsOverview(): Promise<MetricsOverview> {
    const now = new Date();
    const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    const weekStart = new Date(todayStart);
    weekStart.setDate(weekStart.getDate() - 7);
    const monthStart = new Date(todayStart);
    monthStart.setMonth(monthStart.getMonth() - 1);

    const [
      searchStats,
      qaStats,
      documentStats,
      userStats,
    ] = await Promise.all([
      this.getSearchStats(todayStart, weekStart, monthStart),
      this.getQAStats(todayStart, weekStart, monthStart),
      this.getDocumentStats(),
      this.getUserStats(todayStart, weekStart, monthStart),
    ]);

    return {
      searchStats,
      qaStats,
      documentStats,
      userStats,
    };
  }

  /**
   * 获取搜索热词
   */
  async getTopSearchQueries(days: number = 7, limit: number = 10): Promise<Array<{ query: string; count: number }>> {
    const since = new Date();
    since.setDate(since.getDate() - days);

    // 使用原生 SQL 进行聚合
    const results = await this.prisma.$queryRaw<Array<{ query: string; count: bigint }>>`
      SELECT query, COUNT(*) as count
      FROM platform_knowledge.search_logs
      WHERE created_at >= ${since}
      GROUP BY query
      ORDER BY count DESC
      LIMIT ${limit}
    `;

    return results.map(r => ({
      query: r.query,
      count: Number(r.count),
    }));
  }

  /**
   * 获取每日统计趋势
   */
  async getDailyTrend(days: number = 30): Promise<Array<{
    date: string;
    searches: number;
    qaQueries: number;
  }>> {
    const since = new Date();
    since.setDate(since.getDate() - days);

    // 搜索统计
    const searchTrend = await this.prisma.$queryRaw<Array<{ date: Date; count: bigint }>>`
      SELECT DATE(created_at) as date, COUNT(*) as count
      FROM platform_knowledge.search_logs
      WHERE created_at >= ${since}
      GROUP BY DATE(created_at)
      ORDER BY date
    `;

    // 问答统计
    const qaTrend = await this.prisma.$queryRaw<Array<{ date: Date; count: bigint }>>`
      SELECT DATE(created_at) as date, COUNT(*) as count
      FROM platform_knowledge.ai_qa_logs
      WHERE created_at >= ${since}
      GROUP BY DATE(created_at)
      ORDER BY date
    `;

    // 合并结果
    const dateMap = new Map<string, { searches: number; qaQueries: number }>();

    for (let i = 0; i < days; i++) {
      const d = new Date(since);
      d.setDate(d.getDate() + i);
      const dateStr = d.toISOString().split('T')[0];
      dateMap.set(dateStr, { searches: 0, qaQueries: 0 });
    }

    for (const row of searchTrend) {
      const dateStr = new Date(row.date).toISOString().split('T')[0];
      const entry = dateMap.get(dateStr);
      if (entry) {
        entry.searches = Number(row.count);
      }
    }

    for (const row of qaTrend) {
      const dateStr = new Date(row.date).toISOString().split('T')[0];
      const entry = dateMap.get(dateStr);
      if (entry) {
        entry.qaQueries = Number(row.count);
      }
    }

    return Array.from(dateMap.entries()).map(([date, data]) => ({
      date,
      ...data,
    }));
  }

  private async getSearchStats(
    todayStart: Date,
    weekStart: Date,
    monthStart: Date,
  ): Promise<MetricsOverview['searchStats']> {
    const [today, thisWeek, thisMonth, byType, avgResponse] = await Promise.all([
      this.prisma.searchLog.count({ where: { createdAt: { gte: todayStart } } }),
      this.prisma.searchLog.count({ where: { createdAt: { gte: weekStart } } }),
      this.prisma.searchLog.count({ where: { createdAt: { gte: monthStart } } }),
      this.prisma.searchLog.groupBy({
        by: ['searchType'],
        _count: true,
        where: { createdAt: { gte: monthStart } },
      }),
      this.prisma.searchLog.aggregate({
        _avg: { responseTimeMs: true },
        where: { createdAt: { gte: monthStart } },
      }),
    ]);

    const typeMap = { keyword: 0, semantic: 0, hybrid: 0 };
    for (const row of byType) {
      const key = row.searchType.toLowerCase() as keyof typeof typeMap;
      if (key in typeMap) {
        typeMap[key] = row._count;
      }
    }

    return {
      today,
      thisWeek,
      thisMonth,
      byType: typeMap,
      avgResponseTime: Math.round(avgResponse._avg.responseTimeMs ?? 0),
    };
  }

  private async getQAStats(
    todayStart: Date,
    weekStart: Date,
    monthStart: Date,
  ): Promise<MetricsOverview['qaStats']> {
    const [today, thisWeek, thisMonth, feedbackCounts, aggregates] = await Promise.all([
      this.prisma.aIQALog.count({ where: { createdAt: { gte: todayStart } } }),
      this.prisma.aIQALog.count({ where: { createdAt: { gte: weekStart } } }),
      this.prisma.aIQALog.count({ where: { createdAt: { gte: monthStart } } }),
      this.prisma.aIQALog.groupBy({
        by: ['feedback'],
        _count: true,
        where: { createdAt: { gte: monthStart } },
      }),
      this.prisma.aIQALog.aggregate({
        _avg: { confidence: true, responseTimeMs: true },
        _sum: { cost: true },
        where: { createdAt: { gte: monthStart } },
      }),
    ]);

    const feedbackRate = { positive: 0, negative: 0, none: 0 };
    for (const row of feedbackCounts) {
      if (row.feedback === 'THUMBS_UP') {
        feedbackRate.positive = row._count;
      } else if (row.feedback === 'THUMBS_DOWN') {
        feedbackRate.negative = row._count;
      } else {
        feedbackRate.none = row._count;
      }
    }

    return {
      today,
      thisWeek,
      thisMonth,
      avgConfidence: aggregates._avg.confidence ?? 0,
      feedbackRate,
      avgResponseTime: Math.round(aggregates._avg.responseTimeMs ?? 0),
      totalCost: aggregates._sum.cost ?? 0,
    };
  }

  private async getDocumentStats(): Promise<MetricsOverview['documentStats']> {
    const [totalDocuments, totalArticles, statusCounts] = await Promise.all([
      this.prisma.sPDocumentIndex.count(),
      this.prisma.knowledgeArticle.count({ where: { deletedAt: null } }),
      this.prisma.ragflowDocument.groupBy({
        by: ['status'],
        _count: true,
      }),
    ]);

    let indexed = 0, pending = 0, failed = 0;
    for (const row of statusCounts) {
      if (row.status === 'COMPLETED') {
        indexed = row._count;
      } else if (row.status === 'PENDING') {
        pending = row._count;
      } else if (row.status === 'FAILED') {
        failed = row._count;
      }
    }

    return {
      totalDocuments,
      totalArticles,
      indexedDocuments: indexed,
      pendingSync: pending,
      failedSync: failed,
    };
  }

  private async getUserStats(
    todayStart: Date,
    weekStart: Date,
    monthStart: Date,
  ): Promise<MetricsOverview['userStats']> {
    // 基于搜索日志和问答日志计算活跃用户
    const [searchUsersToday, searchUsersWeek, searchUsersMonth] = await Promise.all([
      this.prisma.$queryRaw<[{ count: bigint }]>`
        SELECT COUNT(DISTINCT user_id_hash) as count
        FROM platform_knowledge.search_logs
        WHERE created_at >= ${todayStart}
      `,
      this.prisma.$queryRaw<[{ count: bigint }]>`
        SELECT COUNT(DISTINCT user_id_hash) as count
        FROM platform_knowledge.search_logs
        WHERE created_at >= ${weekStart}
      `,
      this.prisma.$queryRaw<[{ count: bigint }]>`
        SELECT COUNT(DISTINCT user_id_hash) as count
        FROM platform_knowledge.search_logs
        WHERE created_at >= ${monthStart}
      `,
    ]);

    return {
      activeUsersToday: Number(searchUsersToday[0]?.count ?? 0),
      activeUsersWeek: Number(searchUsersWeek[0]?.count ?? 0),
      activeUsersMonth: Number(searchUsersMonth[0]?.count ?? 0),
    };
  }

  /**
   * 用户 ID 哈希（隐私保护）
   */
  private hashUserId(userId: string): string {
    return crypto.createHash('sha256').update(userId).digest('hex').substring(0, 64);
  }

  /**
   * 清理查询内容（脱敏）
   */
  private sanitizeQuery(query: string): string {
    // 移除可能的敏感信息模式
    return query
      .replace(/\d{11}/g, '[PHONE]') // 手机号
      .replace(/\d{15,18}/g, '[ID]') // 身份证号
      .replace(/[\w.-]+@[\w.-]+\.\w+/g, '[EMAIL]') // 邮箱
      .replace(/密码|password|pwd/gi, '[PASSWORD]') // 密码关键词
      .substring(0, 500); // 限制长度
  }
}
