import { Injectable } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { PERFORMANCE_ERROR_CODES } from '../constants/error-codes';
import { BusinessException } from '@common/exceptions/business.exception';

/**
 * 统计分析服务
 * 提供绩效数据报表和分析功能
 */
@Injectable()
export class AnalyticsService {
  constructor(private readonly prisma: PrismaService) {}

  // ==================== 个人报表 ====================

  /**
   * 获取个人绩效概览
   */
  async getPersonalOverview(userId: string, cycleId?: string) {
    const cycle = cycleId
      ? await this.prisma.performanceCycle.findFirst({ where: { id: cycleId, deletedAt: null } })
      : await this.prisma.performanceCycle.findFirst({
          where: {
            deletedAt: null,
            status: { in: ['GOAL_SETTING', 'IN_PROGRESS', 'EVALUATING', 'CALIBRATING'] },
          },
          orderBy: { startDate: 'desc' },
        });

    if (!cycle) {
      return { avgScore: 0, gradeCode: '' };
    }

    const result = await this.prisma.performanceResult.findFirst({
      where: { cycleId: cycle.id, employeeId: userId, deletedAt: null },
    });

    if (!result) {
      return { avgScore: 0, gradeCode: '' };
    }

    return {
      avgScore: Number(result.totalScore),
      gradeCode: result.gradeCode,
    };
  }

  /**
   * 获取个人历史绩效趋势
   */
  async getPersonalTrend(userId: string, limit = 6) {
    const results = await this.prisma.performanceResult.findMany({
      where: { employeeId: userId, isPublished: true, deletedAt: null },
      orderBy: { cycle: { startDate: 'desc' } },
      take: limit,
      include: {
        cycle: {
          select: { name: true },
        },
      },
    });

    return results.map((r) => ({
      cycle: r.cycle.name,
      score: Number(r.totalScore),
    }));
  }

  // ==================== 团队报表 ====================

  /**
   * 获取团队绩效统计（仅 Manager）
   */
  async getTeamStatistics(managerId: string, cycleId?: string) {
    // 获取周期
    const cycle = cycleId
      ? await this.prisma.performanceCycle.findFirst({ where: { id: cycleId, deletedAt: null } })
      : await this.prisma.performanceCycle.findFirst({
          where: {
            deletedAt: null,
            status: { in: ['GOAL_SETTING', 'IN_PROGRESS', 'EVALUATING', 'CALIBRATING', 'COMPLETED'] },
          },
          orderBy: { startDate: 'desc' },
        });

    if (!cycle) {
      return { avgScore: 0, distribution: [] };
    }

    // 获取团队成员（通过组织结构中的汇报关系）
    const subordinateIds = await this.getSubordinateIds(managerId);

    if (subordinateIds.length === 0) {
      return { avgScore: 0, distribution: [] };
    }

    const stats = await this.prisma.performanceResult.aggregate({
      where: {
        cycleId: cycle.id,
        employeeId: { in: subordinateIds },
        deletedAt: null,
      },
      _avg: { totalScore: true },
    });

    const gradeDistribution = await this.prisma.performanceResult.groupBy({
      by: ['gradeCode'],
      where: {
        cycleId: cycle.id,
        employeeId: { in: subordinateIds },
        deletedAt: null,
      },
      _count: true,
    });

    return {
      avgScore: Number(stats._avg?.totalScore) || 0,
      distribution: gradeDistribution.map((g) => ({
        gradeCode: g.gradeCode,
        count: g._count,
      })),
    };
  }

  // ==================== 部门报表 ====================

  /**
   * 获取部门绩效报表
   */
  async getDepartmentReport(departmentId: string, cycleId: string) {
    const cycle = await this.prisma.performanceCycle.findFirst({
      where: { id: cycleId, deletedAt: null },
    });

    if (!cycle) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.CYCLE_NOT_FOUND.message,
        PERFORMANCE_ERROR_CODES.CYCLE_NOT_FOUND.code,
        PERFORMANCE_ERROR_CODES.CYCLE_NOT_FOUND.httpStatus,
      );
    }

    // 获取部门员工 - 通过 UserDepartment 关联表
    const departmentMemberships = await this.prisma.userDepartment.findMany({
      where: { departmentId, leftAt: null },
      select: { userId: true },
    });
    const departmentUsers = departmentMemberships.map((m) => ({ id: m.userId }));

    const employeeIds = departmentUsers.map((u) => u.id);

    if (employeeIds.length === 0) {
      return { cycleId, cycleName: cycle.name, departmentId, employeeCount: 0, kpiStats: { total: 0, avgScore: 0, highest: 0, lowest: 0 }, e360Stats: { total: 0, byStatus: {} }, gradeDistribution: [], scoreDistribution: [] };
    }

    // KPI 评估统计
    const assessments = await this.prisma.kpiAssessment.findMany({
      where: { assignment: { cycleId, employeeId: { in: employeeIds }, deletedAt: null }, deletedAt: null },
      select: { managerScore: true, selfScore: true, status: true },
    });
    const scores = assessments.map((a) => Number(a.managerScore || a.selfScore || 0)).filter((s) => s > 0);
    const scoreStats = this.calculateScoreStats(scores);
    const kpiStats = { total: assessments.length, ...scoreStats };

    // 360 评估统计
    const e360s = await this.prisma.evaluation360.findMany({
      where: { cycleId, targetId: { in: employeeIds }, deletedAt: null },
      select: { status: true },
    });
    const byStatus: Record<string, number> = {};
    for (const e of e360s) { byStatus[e.status] = (byStatus[e.status] || 0) + 1; }

    // 等级分布（从 performanceResult 或 KPI 评估计算）
    const results = await this.prisma.performanceResult.findMany({
      where: { cycleId, employeeId: { in: employeeIds }, deletedAt: null, totalScore: { not: null } },
      select: { gradeCode: true, gradeName: true, totalScore: true },
    });

    const gradeMap = results.length > 0
      ? this.buildGradeMap(results)
      : this.buildGradeMapFromScores(scores);
    const gradeDistribution = this.formatGradeDistribution(gradeMap);

    // 分数分布（每 10 分一档）
    const scoreRanges = ['90-100', '80-89', '70-79', '60-69', '0-59'];
    const scoreDistribution = scoreRanges.map((range) => {
      const [min, max] = range.split('-').map(Number);
      return { range, count: scores.filter((s) => s >= min && s <= max).length };
    });

    return {
      cycleId, cycleName: cycle.name, departmentId, employeeCount: employeeIds.length,
      kpiStats, e360Stats: { total: e360s.length, byStatus },
      gradeDistribution, scoreDistribution,
    };
  }

  // ==================== 公司报表 ====================

  /**
   * 获取公司整体绩效报表
   */
  async getCompanyReport(cycleId: string) {
    const cycle = await this.prisma.performanceCycle.findFirst({
      where: { id: cycleId, deletedAt: null },
      include: { gradeConfig: true },
    });

    if (!cycle) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.CYCLE_NOT_FOUND.message,
        PERFORMANCE_ERROR_CODES.CYCLE_NOT_FOUND.code,
        PERFORMANCE_ERROR_CODES.CYCLE_NOT_FOUND.httpStatus,
      );
    }

    const orgId = (cycle as any).organizationId;

    // 所有员工
    const allEmployeeIds = orgId ? (await (this.prisma as any).userDepartment.findMany({
      where: { organizationId: orgId, leftAt: null },
      select: { userId: true },
      distinct: ['userId'],
    })).map((ud: any) => ud.userId) : [];

    // KPI 评估
    const assessments = await this.prisma.kpiAssessment.findMany({
      where: { assignment: { cycleId, deletedAt: null }, deletedAt: null },
      select: { managerScore: true, selfScore: true, assignment: { select: { employeeId: true } } },
    });
    const scores = assessments.map((a) => Number(a.managerScore || a.selfScore || 0)).filter((s) => s > 0);

    // 360 评估
    const e360Total = await this.prisma.evaluation360.count({ where: { cycleId, deletedAt: null } });
    const e360Completed = await this.prisma.evaluation360.count({ where: { cycleId, deletedAt: null, status: 'COMPLETED' } });

    // 等级分布（优先从 performanceResult，没有则从 KPI 评估反算）
    const results = await this.prisma.performanceResult.findMany({
      where: { cycleId, deletedAt: null, totalScore: { not: null } },
      select: { gradeCode: true, gradeName: true, totalScore: true, employeeId: true },
    });
    let gradeMap: Map<string, { name: string; count: number }>;
    if (results.length > 0) {
      gradeMap = this.buildGradeMap(results);
    } else {
      // 从 KPI 评估按员工加权平均反算等级
      const byEmp = new Map<string, { totalScore: number; totalWeight: number }>();
      const kpiAssignments = await this.prisma.kpiAssignment.findMany({
        where: { cycleId, deletedAt: null },
        include: { assessment: { where: { deletedAt: null } } },
      });
      for (const ka of kpiAssignments) {
        if (!ka.assessment) continue;
        const w = Number(ka.weight) || 0;
        const s = Number(ka.assessment.managerScore || ka.assessment.selfScore || 0);
        const emp = byEmp.get(ka.employeeId) || { totalScore: 0, totalWeight: 0 };
        emp.totalScore += s * w;
        emp.totalWeight += w;
        byEmp.set(ka.employeeId, emp);
      }
      const empAvgScores = Array.from(byEmp.values()).map((data) =>
        data.totalWeight > 0 ? data.totalScore / data.totalWeight : 0,
      );
      gradeMap = this.buildGradeMapFromScores(empAvgScores);
    }
    const gradeDistribution = this.formatGradeDistribution(gradeMap);

    // 部门排名
    const deptStats = orgId ? await this.prisma.$queryRaw<Array<{ dept_id: string; dept_name: string; emp_count: bigint; avg_score: number }>>`
      SELECT d.id AS dept_id, d.name AS dept_name, COUNT(DISTINCT ud.user_id) AS emp_count,
        COALESCE(AVG(CASE WHEN a.manager_score IS NOT NULL THEN a.manager_score ELSE a.self_score END), 0) AS avg_score
      FROM corp_hr.user_departments ud
      JOIN corp_hr.departments d ON d.id = ud.department_id
      LEFT JOIN platform_performance.kpi_assignment ka ON ka.employee_id = ud.user_id AND ka.cycle_id = ${cycleId}::uuid AND ka.deleted_at IS NULL
      LEFT JOIN platform_performance.kpi_assessment a ON a.assignment_id = ka.id AND a.deleted_at IS NULL
      WHERE ud.organization_id = ${orgId}::uuid AND ud.left_at IS NULL AND d.parent_id IS NOT NULL AND d.deleted_at IS NULL
      GROUP BY d.id, d.name ORDER BY avg_score DESC
    ` : [];

    const companyScoreStats = this.calculateScoreStats(scores);

    return {
      cycleId, cycleName: cycle.name, cycleStatus: cycle.status,
      summary: {
        totalEmployees: allEmployeeIds.length,
        avgScore: companyScoreStats.avgScore,
        avgKpiScore: companyScoreStats.avgScore,
        avgE360Score: 0,
        highestScore: companyScoreStats.highest,
        lowestScore: companyScoreStats.lowest,
      },
      gradeDistribution,
      departmentRanking: deptStats.map((d) => ({
        departmentId: d.dept_id, departmentName: d.dept_name,
        employeeCount: Number(d.emp_count), avgScore: Math.round(Number(d.avg_score) * 10) / 10,
      })),
      completion: {
        kpi: { total: assessments.length, evaluated: assessments.filter((a) => a.managerScore).length, completionRate: (assessments.length > 0 ? (assessments.filter((a) => a.managerScore).length / assessments.length * 100).toFixed(1) : '0') },
        e360: { total: e360Total, completed: e360Completed, completionRate: (e360Total > 0 ? (e360Completed / e360Total * 100).toFixed(1) : '0') },
      },
    };
  }

  // ==================== 等级分布报表 ====================

  /**
   * 获取等级分布报表
   */
  async getGradeDistributionReport(cycleId: string, departmentId?: string) {
    const cycle = await this.prisma.performanceCycle.findFirst({
      where: { id: cycleId, deletedAt: null },
    });

    if (!cycle) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.CYCLE_NOT_FOUND.message,
        PERFORMANCE_ERROR_CODES.CYCLE_NOT_FOUND.code,
        PERFORMANCE_ERROR_CODES.CYCLE_NOT_FOUND.httpStatus,
      );
    }

    // 构建查询条件
    const resultWhere: Record<string, unknown> = { cycleId, deletedAt: null };
    if (departmentId) {
      const departmentMemberships = await this.prisma.userDepartment.findMany({
        where: { departmentId, leftAt: null },
        select: { userId: true },
      });
      resultWhere.employeeId = { in: departmentMemberships.map((m) => m.userId) };
    }

    const distribution = await this.prisma.performanceResult.groupBy({
      by: ['gradeCode'],
      where: resultWhere,
      _count: true,
    });

    return {
      distribution: distribution.map((item) => ({
        gradeCode: item.gradeCode,
        count: item._count,
      })),
    };
  }

  // ==================== 周期对比 ====================

  /**
   * 获取周期对比数据
   */
  async getCycleComparison(cycleIds: string[]) {
    const cycles = await this.prisma.performanceCycle.findMany({
      where: { id: { in: cycleIds }, deletedAt: null },
      orderBy: { startDate: 'asc' },
    });

    const comparisons = await Promise.all(
      cycles.map(async (cycle) => {
        const stats = await this.prisma.performanceResult.aggregate({
          where: { cycleId: cycle.id, deletedAt: null },
          _avg: { totalScore: true },
        });

        return {
          cycle: cycle.name,
          avgScore: Number(stats._avg?.totalScore) || 0,
        };
      }),
    );

    return comparisons;
  }

  // ==================== 辅助方法 ====================

  /**
   * 获取下属 ID 列表
   */
  private async getSubordinateIds(managerId: string): Promise<string[]> {
    const subordinates = await this.prisma.userDepartment.findMany({
      where: { managerId, leftAt: null },
      select: { userId: true },
    });
    return subordinates.map((s) => s.userId);
  }

  /**
   * 从绩效结果构建等级分布 Map
   */
  private buildGradeMap(results: { gradeCode: string | null; gradeName?: string | null }[]): Map<string, { name: string; count: number }> {
    const gradeMap = new Map<string, { name: string; count: number }>();
    for (const r of results) {
      if (r.gradeCode) {
        const g = gradeMap.get(r.gradeCode) || { name: r.gradeName || '', count: 0 };
        g.count++;
        gradeMap.set(r.gradeCode, g);
      }
    }
    return gradeMap;
  }

  /**
   * 从分数反算等级分布 Map（无正式结果时的降级路径）
   */
  private buildGradeMapFromScores(scores: number[]): Map<string, { name: string; count: number }> {
    const gradeMap = new Map<string, { name: string; count: number }>();
    for (const s of scores) {
      const code = s >= 90 ? 'S' : s >= 80 ? 'A' : s >= 70 ? 'B' : s >= 60 ? 'C' : 'D';
      const name = s >= 90 ? '卓越' : s >= 80 ? '优秀' : s >= 70 ? '良好' : s >= 60 ? '待改进' : '不合格';
      const g = gradeMap.get(code) || { name, count: 0 };
      g.count++;
      gradeMap.set(code, g);
    }
    return gradeMap;
  }

  /**
   * 将 gradeMap 格式化为标准等级分布数组
   */
  private formatGradeDistribution(gradeMap: Map<string, { name: string; count: number }>): { grade: string; gradeName: string; count: number; percentage: string }[] {
    const total = Math.max(1, Array.from(gradeMap.values()).reduce((s, g) => s + g.count, 0));
    return ['S', 'A', 'B', 'C', 'D'].map((code) => {
      const g = gradeMap.get(code);
      return { grade: code, gradeName: g?.name || code, count: g?.count || 0, percentage: ((g?.count || 0) / total * 100).toFixed(1) };
    });
  }

  /**
   * 计算分数统计（平均、最高、最低）
   */
  private calculateScoreStats(scores: number[]): { avgScore: number; highest: number; lowest: number } {
    if (scores.length === 0) return { avgScore: 0, highest: 0, lowest: 0 };
    return {
      avgScore: Math.round(scores.reduce((s, v) => s + v, 0) / scores.length * 10) / 10,
      highest: Math.max(...scores),
      lowest: Math.min(...scores),
    };
  }
}
