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

/**
 * KPI 考核管理服务
 * 负责 KPI 分配、自评他评打分
 */
@Injectable()
export class KpiService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly usersService: UsersService,
  ) {}

  // ==================== KPI 分配 ====================

  async assignKpi(data: {
    cycleId: string;
    employeeId: string;
    weight: number;
    name?: string;
    description?: string;
    baseTarget?: string;
    stretchTarget?: string;
    unit?: string;
    targetValue?: number;
    dependencies?: { targetUserId: string; description?: string }[];
  }) {
    // 验证周期
    const cycle = await this.prisma.performanceCycle.findFirst({
      where: { id: data.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,
      );
    }

    // name 必填且不能是空白字符串
    if (!data.name || !data.name.trim()) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.message,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.code,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.httpStatus,
        { reason: 'name is required (name cannot be empty)' },
      );
    }

    // 同一周期同一员工不能有完全同名的 KPI
    const duplicate = await this.prisma.kpiAssignment.findFirst({
      where: {
        cycleId: data.cycleId,
        employeeId: data.employeeId,
        name: data.name.trim(),
        deletedAt: null,
      },
    });
    if (duplicate) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.message,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.code,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.httpStatus,
        { reason: `Duplicate KPI name: ${data.name}` },
      );
    }

    // 权重总和检查移到 submitAllKpi，草稿阶段允许权重不到 100%

    // 创建分配和考核记录
    const assignment = await this.prisma.kpiAssignment.create({
      data: {
        cycleId: data.cycleId,
        employeeId: data.employeeId,
        name: data.name,
        description: data.description,
        baseTarget: data.baseTarget,
        stretchTarget: data.stretchTarget,
        unit: data.unit,
        weight: data.weight,
        targetValue: data.targetValue,
        assessment: {
          create: {
            status: 'PENDING',
          },
        },
      },
      include: {
        assessment: true,
      },
    });

    // 批量创建依赖记录
    if (data.dependencies && data.dependencies.length > 0) {
      await this.prisma.kpiDependency.createMany({
        data: data.dependencies.map((dep) => ({
          sourceAssignmentId: assignment.id,
          targetUserId: dep.targetUserId,
          description: dep.description,
          status: 'PENDING' as const,
        })),
      });
    }

    return assignment;
  }

  async batchAssignKpi(
    cycleId: string,
    employeeIds: string[],
    assignments: {
      weight: number;
      name?: string;
      targetValue?: number;
    }[],
  ) {
    let created = 0;
    let failed = 0;
    for (const employeeId of employeeIds) {
      for (const assignment of assignments) {
        try {
          await this.assignKpi({
            cycleId,
            employeeId,
            ...assignment,
          });
          created += 1;
        } catch (error) {
          failed += 1;
        }
      }
    }
    return { created, failed };
  }

  async findAssignments(query: {
    cycleId?: string;
    employeeId?: string;
    page?: number;
    pageSize?: number;
  }) {
    const { cycleId, employeeId, page = 1, pageSize = 20 } = query;
    const skip = (page - 1) * pageSize;

    const where: Prisma.KpiAssignmentWhereInput = { deletedAt: null };
    if (cycleId) where.cycleId = cycleId;
    if (employeeId) where.employeeId = employeeId;

    const [items, total] = await Promise.all([
      this.prisma.kpiAssignment.findMany({
        where,
        skip,
        take: pageSize,
        orderBy: { createdAt: 'asc' },
      }),
      this.prisma.kpiAssignment.count({ where }),
    ]);

    const employeeIds = items.map((item) => item.employeeId);
    const users = await this.prisma.user.findMany({
      where: { id: { in: employeeIds } },
      select: { id: true, displayName: true },
    });
    const userMap = new Map(users.map((u) => [u.id, u.displayName]));

    return {
      items: items.map((item) => ({
        id: item.id,
        cycleId: item.cycleId,
        employeeId: item.employeeId,
        name: item.name,
        employeeName: userMap.get(item.employeeId),
        weight: item.weight,
        targetValue: item.targetValue,
        status: item.status,
        createdAt: item.createdAt,
        updatedAt: item.updatedAt,
      })),
      pagination: { page, pageSize, total, totalPages: Math.ceil(total / pageSize) },
    };
  }

  async findAssignmentById(id: string) {
    const assignment = await this.prisma.kpiAssignment.findFirst({
      where: { id, deletedAt: null },
    });
    if (!assignment) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_ASSIGNMENT_NOT_FOUND.message,
        PERFORMANCE_ERROR_CODES.KPI_ASSIGNMENT_NOT_FOUND.code,
        PERFORMANCE_ERROR_CODES.KPI_ASSIGNMENT_NOT_FOUND.httpStatus,
      );
    }
    return assignment;
  }

  async updateAssignment(
    id: string,
    data: {
      weight?: number;
      targetValue?: number;
      name?: string;
      description?: string;
      baseTarget?: string;
      stretchTarget?: string;
      dependentUserId?: string | null;
      dependencyDescription?: string | null;
    },
    userId?: string,
  ) {
    const assignment = await this.findAssignmentById(id);

    // 如果传了 userId，校验只能编辑自己的 KPI
    if (userId && assignment.employeeId !== userId) {
      throw new BusinessException(
        '只能编辑自己的 KPI',
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.code,
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.httpStatus,
      );
    }

    // 如果该员工有已提交的 KPI，任何修改都撤回整体提交
    const hasSubmitted = await this.prisma.kpiAssignment.count({
      where: {
        employeeId: assignment.employeeId,
        cycleId: assignment.cycleId,
        status: 'SUBMITTED' as any,
        deletedAt: null,
      },
    });
    if (hasSubmitted > 0) {
      await this.prisma.kpiAssignment.updateMany({
        where: {
          employeeId: assignment.employeeId,
          cycleId: assignment.cycleId,
          status: 'SUBMITTED' as any,
          deletedAt: null,
        },
        data: { status: 'DRAFT' as any },
      });
    }

    // 依赖人存在独立表 kpi_dependency，不能直接通过 assignment update 保存
    const { dependentUserId, dependencyDescription, ...assignmentData } = data;

    if (dependentUserId !== undefined) {
      // 事务保护：删除旧依赖 + 创建新依赖
      await this.prisma.$transaction(async (tx) => {
        await tx.kpiDependency.updateMany({
          where: { sourceAssignmentId: id, deletedAt: null },
          data: { deletedAt: new Date() },
        });

        if (dependentUserId) {
          await tx.kpiDependency.upsert({
            where: {
              sourceAssignmentId_targetUserId: {
                sourceAssignmentId: id,
                targetUserId: dependentUserId,
              },
            },
            update: {
              description: dependencyDescription || null,
              status: 'PENDING' as any,
              deletedAt: null,
            },
            create: {
              sourceAssignmentId: id,
              targetUserId: dependentUserId,
              description: dependencyDescription || null,
              status: 'PENDING' as any,
            },
          });
        }
      });
    } else if (dependencyDescription !== undefined) {
      await this.prisma.kpiDependency.updateMany({
        where: { sourceAssignmentId: id, deletedAt: null },
        data: { description: dependencyDescription },
      });
    }

    // 只有 assignment 本身的字段才 update
    const hasAssignmentFields = Object.keys(assignmentData).length > 0;
    if (hasAssignmentFields) {
      return this.prisma.kpiAssignment.update({
        where: { id },
        data: assignmentData,
        include: { assessment: true, outgoingDependencies: true },
      });
    }

    // 如果只改了依赖，返回最新的 assignment
    return this.prisma.kpiAssignment.findUniqueOrThrow({
      where: { id },
      include: { assessment: true, outgoingDependencies: true },
    });
  }

  async deleteAssignment(id: string, userId: string) {
    const assignment = await this.findAssignmentById(id);

    // 只能删除自己的且状态为 DRAFT 的 KPI
    if (assignment.employeeId !== userId) {
      throw new BusinessException(
        '只能删除自己的 KPI',
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.code,
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.httpStatus,
      );
    }
    if (assignment.status !== 'DRAFT' && assignment.status !== 'SUBMITTED') {
      throw new BusinessException(
        '已通过的 KPI 不能删除',
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.code,
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.httpStatus,
      );
    }

    // 如果有已提交的 KPI，删除后撤回同周期其他已提交 KPI 为草稿
    if (assignment.status === 'SUBMITTED') {
      await this.prisma.kpiAssignment.updateMany({
        where: {
          employeeId: assignment.employeeId,
          cycleId: assignment.cycleId,
          status: 'SUBMITTED' as any,
          id: { not: id },
          deletedAt: null,
        },
        data: { status: 'DRAFT' as any },
      });
    }

    // 软删除
    await this.prisma.kpiAssignment.update({
      where: { id },
      data: { deletedAt: new Date() },
    });
  }

  async findAssessmentById(id: string) {
    const assessment = await this.prisma.kpiAssessment.findFirst({
      where: { id, deletedAt: null },
      include: {
        assignment: {
          include: {
            cycle: true,
          },
        },
      },
    });
    if (!assessment) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_ASSESSMENT_NOT_FOUND.message,
        PERFORMANCE_ERROR_CODES.KPI_ASSESSMENT_NOT_FOUND.code,
        PERFORMANCE_ERROR_CODES.KPI_ASSESSMENT_NOT_FOUND.httpStatus,
      );
    }
    return assessment;
  }

  // ==================== 考核评分 ====================

  async selfEvaluate(
    assessmentId: string,
    userId: string,
    data: { score?: number; selfScore?: number; comment?: string; selfComment?: string; completionNote?: string },
  ) {
    const assessment = await this.findAssessmentById(assessmentId);

    if (assessment.assignment.employeeId !== userId) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.message,
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.code,
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.httpStatus,
      );
    }

    if (assessment.status !== 'PENDING') {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_SELF_EVAL_LOCKED.message,
        PERFORMANCE_ERROR_CODES.KPI_SELF_EVAL_LOCKED.code,
        PERFORMANCE_ERROR_CODES.KPI_SELF_EVAL_LOCKED.httpStatus,
      );
    }

    const score = data.score ?? data.selfScore;
    const comment = data.comment ?? data.selfComment;

    if (score == null || score < 0 || score > 100) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_SCORE_INVALID.message,
        PERFORMANCE_ERROR_CODES.KPI_SCORE_INVALID.code,
        PERFORMANCE_ERROR_CODES.KPI_SCORE_INVALID.httpStatus,
      );
    }

    const result = await this.prisma.kpiAssessment.update({
      where: { id: assessmentId },
      data: {
        selfScore: score,
        selfComment: comment,
        completionNote: data.completionNote,
        selfEvaluatedAt: new Date(),
        status: 'SELF_EVALUATED',
      },
    });

    // 检查该员工在该周期的所有 KPI 是否都已自评完成，如果是则自动启动其 360 评估
    await this.tryActivate360Evaluation(userId, assessment.assignment.cycleId);

    return result;
  }

  /**
   * 当员工所有 KPI 自评完成后，自动将其 DRAFT 状态的 360 评估转为 IN_PROGRESS
   */
  private async tryActivate360Evaluation(userId: string, cycleId: string) {
    // 查该员工在该周期还有未自评的 KPI
    const pendingCount = await this.prisma.kpiAssessment.count({
      where: {
        status: 'PENDING',
        assignment: {
          employeeId: userId,
          cycleId,
          deletedAt: null,
        },
      },
    });

    if (pendingCount > 0) return;

    // 全部自评完成，将该员工的 360 评估从 DRAFT 转为 IN_PROGRESS
    await this.prisma.evaluation360.updateMany({
      where: {
        targetId: userId,
        cycleId,
        status: 'DRAFT',
        deletedAt: null,
      },
      data: { status: 'IN_PROGRESS' },
    });
  }

  async managerEvaluate(
    assessmentId: string,
    managerId: string,
    data: { score?: number; managerScore?: number; comment?: string; managerComment?: string },
  ) {
    const assessment = await this.findAssessmentById(assessmentId);

    if (assessment.status !== 'SELF_EVALUATED') {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_SELF_EVAL_REQUIRED.message,
        PERFORMANCE_ERROR_CODES.KPI_SELF_EVAL_REQUIRED.code,
        PERFORMANCE_ERROR_CODES.KPI_SELF_EVAL_REQUIRED.httpStatus,
      );
    }

    const subordinates = await this.usersService.getSubordinates(managerId);
    const subordinateIds = subordinates.map((s: any) => s.id);
    if (!subordinateIds.includes(assessment.assignment.employeeId)) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_ONLY_MANAGER.message,
        PERFORMANCE_ERROR_CODES.KPI_ONLY_MANAGER.code,
        PERFORMANCE_ERROR_CODES.KPI_ONLY_MANAGER.httpStatus,
      );
    }

    const score = data.score ?? data.managerScore;
    const comment = data.comment ?? data.managerComment;

    if (score == null || score < 0 || score > 100) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_SCORE_INVALID.message,
        PERFORMANCE_ERROR_CODES.KPI_SCORE_INVALID.code,
        PERFORMANCE_ERROR_CODES.KPI_SCORE_INVALID.httpStatus,
      );
    }

    // 计算最终分数（可以按权重调整）
    const finalScore = score;

    return this.prisma.kpiAssessment.update({
      where: { id: assessmentId },
      data: {
        managerScore: score,
        managerComment: comment,
        managerId,
        managerEvaluatedAt: new Date(),
        finalScore,
        status: 'MANAGER_EVALUATED',
      },
    });
  }

  async confirmAssessment(assessmentId: string) {
    const assessment = await this.findAssessmentById(assessmentId);

    if (assessment.status !== 'MANAGER_EVALUATED') {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_STATUS_INVALID.message,
        PERFORMANCE_ERROR_CODES.KPI_STATUS_INVALID.code,
        PERFORMANCE_ERROR_CODES.KPI_STATUS_INVALID.httpStatus,
      );
    }

    return this.prisma.kpiAssessment.update({
      where: { id: assessmentId },
      data: {
        status: 'CONFIRMED',
      },
    });
  }

  async calculateFinalScore(assessmentId: string): Promise<number> {
    const assessment = await this.findAssessmentById(assessmentId);
    // 简单实现：取经理评分作为最终分数
    return Number(assessment.managerScore) || Number(assessment.selfScore) || 0;
  }

  // ==================== KPI 提交与审批 ====================

  async submitAllKpi(cycleId: string, employeeId: string) {
    const draftAssignments = await this.prisma.kpiAssignment.findMany({
      where: {
        cycleId,
        employeeId,
        status: 'DRAFT',
        deletedAt: null,
      },
    });

    if (draftAssignments.length === 0) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.message,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.code,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.httpStatus,
        { reason: 'no_draft_assignments' },
      );
    }

    // 验证权重总和为 100
    const totalWeight = draftAssignments.reduce((sum, a) => sum + Number(a.weight), 0);
    if (Math.abs(totalWeight - 100) > 0.01) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_WEIGHT_SUM_INVALID.message,
        PERFORMANCE_ERROR_CODES.KPI_WEIGHT_SUM_INVALID.code,
        PERFORMANCE_ERROR_CODES.KPI_WEIGHT_SUM_INVALID.httpStatus,
      );
    }

    // 检查所有有依赖的 KPI 是否已确认
    const unconfirmedDeps = await this.prisma.kpiDependency.count({
      where: {
        sourceAssignment: { cycleId, employeeId, deletedAt: null, status: 'DRAFT' },
        status: { not: 'CONFIRMED' },
        deletedAt: null,
      },
    });
    if (unconfirmedDeps > 0) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_DEPENDENCY_UNCONFIRMED.message,
        PERFORMANCE_ERROR_CODES.KPI_DEPENDENCY_UNCONFIRMED.code,
        PERFORMANCE_ERROR_CODES.KPI_DEPENDENCY_UNCONFIRMED.httpStatus,
      );
    }

    const { count: submitted } = await this.prisma.kpiAssignment.updateMany({
      where: { id: { in: draftAssignments.map((a) => a.id) } },
      data: { status: 'SUBMITTED' },
    });

    return { submitted };
  }

  async approveAssignment(assignmentId: string) {
    const assignment = await this.findAssignmentById(assignmentId);

    if (assignment.status !== 'SUBMITTED') {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_STATUS_INVALID.message,
        PERFORMANCE_ERROR_CODES.KPI_STATUS_INVALID.code,
        PERFORMANCE_ERROR_CODES.KPI_STATUS_INVALID.httpStatus,
      );
    }

    const updated = await this.prisma.kpiAssignment.update({
      where: { id: assignmentId },
      data: { status: 'APPROVED' },
    });

    return { id: updated.id, status: updated.status };
  }

  async rejectAssignment(assignmentId: string, reason: string) {
    const assignment = await this.findAssignmentById(assignmentId);

    if (assignment.status !== 'SUBMITTED') {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_STATUS_INVALID.message,
        PERFORMANCE_ERROR_CODES.KPI_STATUS_INVALID.code,
        PERFORMANCE_ERROR_CODES.KPI_STATUS_INVALID.httpStatus,
      );
    }

    const updated = await this.prisma.kpiAssignment.update({
      where: { id: assignmentId },
      data: {
        status: 'REJECTED',
      },
    });

    return { id: updated.id, status: updated.status };
  }

  // ==================== 跨部门依赖 ====================

  async confirmDependency(dependencyId: string, userId: string) {
    const dependency = await this.prisma.kpiDependency.findFirst({
      where: { id: dependencyId, deletedAt: null },
    });
    if (!dependency) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_DEPENDENCY_NOT_FOUND.message,
        PERFORMANCE_ERROR_CODES.KPI_DEPENDENCY_NOT_FOUND.code,
        PERFORMANCE_ERROR_CODES.KPI_DEPENDENCY_NOT_FOUND.httpStatus,
      );
    }

    if (dependency.targetUserId !== userId) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.message,
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.code,
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.httpStatus,
      );
    }

    const updated = await this.prisma.kpiDependency.update({
      where: { id: dependencyId },
      data: {
        status: 'CONFIRMED',
        confirmedAt: new Date(),
      },
      include: {
        sourceAssignment: {
          include: { cycle: { select: { id: true, name: true } } },
        },
      },
    });

    return updated;
  }

  async rejectDependency(dependencyId: string, userId: string, reason: string) {
    const dependency = await this.prisma.kpiDependency.findFirst({
      where: { id: dependencyId, deletedAt: null },
    });
    if (!dependency) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.KPI_DEPENDENCY_NOT_FOUND.message,
        PERFORMANCE_ERROR_CODES.KPI_DEPENDENCY_NOT_FOUND.code,
        PERFORMANCE_ERROR_CODES.KPI_DEPENDENCY_NOT_FOUND.httpStatus,
      );
    }

    if (dependency.targetUserId !== userId) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.message,
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.code,
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.httpStatus,
      );
    }

    const updated = await this.prisma.kpiDependency.update({
      where: { id: dependencyId },
      data: {
        status: 'REJECTED',
        rejectionReason: reason,
      },
    });

    return { id: updated.id, status: updated.status };
  }

  async getPendingDependencyConfirmations(userId: string) {
    const deps = await this.prisma.kpiDependency.findMany({
      where: {
        targetUserId: userId,
        status: 'PENDING',
        deletedAt: null,
      },
      include: {
        sourceAssignment: {
          include: {
            cycle: { select: { id: true, name: true } },
          },
        },
      },
      orderBy: { createdAt: 'desc' },
    });

    // 批量查询发起人信息
    const employeeIds = new Set(deps.map((d) => d.sourceAssignment?.employeeId).filter(Boolean) as string[]);
    const employees = employeeIds.size > 0
      ? await this.prisma.user.findMany({
          where: { id: { in: Array.from(employeeIds) } },
          select: { id: true, displayName: true },
        })
      : [];
    const empMap = new Map(employees.map((u) => [u.id, u]));

    return deps.map((dep) => ({
      ...dep,
      kpiName: dep.sourceAssignment?.name || null,
      dependencyDescription: dep.description || null,
      sourceEmployee: dep.sourceAssignment ? empMap.get(dep.sourceAssignment.employeeId) || null : null,
    }));
  }

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

  async validateWeightSum(
    cycleId: string,
    employeeId: string,
  ): Promise<{ valid: boolean; totalWeight: number }> {
    const assignments = await this.prisma.kpiAssignment.findMany({
      where: { cycleId, employeeId, deletedAt: null },
    });
    const totalWeight = assignments.reduce((sum, a) => sum + Number(a.weight), 0);
    return {
      valid: Math.abs(totalWeight - 100) < 0.01,
      totalWeight,
    };
  }

  async getMyAssessments(
    userId: string,
    query?: { cycleId?: string; page?: number; pageSize?: number },
  ) {
    const { cycleId, page = 1, pageSize = 20 } = query || {};
    const skip = (page - 1) * pageSize;
    const where: Prisma.KpiAssignmentWhereInput = {
      employeeId: userId,
      deletedAt: null,
    };
    if (cycleId) where.cycleId = cycleId;

    const [items, total] = await Promise.all([
      this.prisma.kpiAssignment.findMany({
        where,
        skip,
        take: pageSize,
        include: {
          assessment: true,
          outgoingDependencies: { where: { deletedAt: null } },
        },
        orderBy: { createdAt: 'asc' },
      }),
      this.prisma.kpiAssignment.count({ where }),
    ]);

    // 获取员工信息
    const user = await this.prisma.user.findUnique({
      where: { id: userId },
      select: { id: true, displayName: true },
    });

    // 收集所有依赖人 ID，批量查询 displayName
    const depUserIds = new Set<string>();
    for (const item of items) {
      for (const dep of (item as any).outgoingDependencies || []) {
        if (dep.targetUserId) depUserIds.add(dep.targetUserId);
      }
    }
    const depUsers = depUserIds.size > 0
      ? await this.prisma.user.findMany({
          where: { id: { in: Array.from(depUserIds) } },
          select: { id: true, displayName: true },
        })
      : [];
    const depUserMap = new Map(depUsers.map((u) => [u.id, u]));

    return {
      items: items.map((item) => ({
        id: item.id,
        cycleId: item.cycleId,
        employeeId: item.employeeId,
        name: item.name,
        weight: item.weight,
        targetValue: item.targetValue,
        baseTarget: item.baseTarget,
        stretchTarget: item.stretchTarget,
        status: item.status,
        dependencies: (item as any).outgoingDependencies,
        // 扁平化依赖字段（前端需要 dependentUserId/dependentUser/dependencyStatus/dependencyDescription）
        dependentUserId: (item as any).outgoingDependencies?.[0]?.targetUserId || null,
        dependentUser: (item as any).outgoingDependencies?.[0]?.targetUserId
          ? depUserMap.get((item as any).outgoingDependencies[0].targetUserId) || null
          : null,
        dependencyStatus: (item as any).outgoingDependencies?.[0]?.status || null,
        dependencyDescription: (item as any).outgoingDependencies?.[0]?.description || null,
        dependencyRejectionReason: (item as any).outgoingDependencies?.[0]?.rejectionReason || null,
        parentId: item.parentId,
        seq: item.seq,
        assessment: (item as any).assessment ? {
          id: (item as any).assessment.id,
          selfScore: (item as any).assessment.selfScore != null ? Number((item as any).assessment.selfScore) : undefined,
          managerScore: (item as any).assessment.managerScore != null ? Number((item as any).assessment.managerScore) : undefined,
          finalScore: (item as any).assessment.finalScore != null ? Number((item as any).assessment.finalScore) : undefined,
          selfComment: (item as any).assessment.selfComment,
          managerComment: (item as any).assessment.managerComment,
          status: (item as any).assessment.status,
        } : null,
        employee: user ? { id: user.id, displayName: user.displayName } : null,
        createdAt: item.createdAt,
        updatedAt: item.updatedAt,
      })),
      pagination: { page, pageSize, total, totalPages: Math.ceil(total / pageSize) },
    };
  }

  async getTeamAssessments(
    managerId: string,
    query?: { cycleId?: string; organizationId?: string },
  ) {
    const { cycleId, organizationId } = query || {};
    // 通过组织架构获取下属
    const subordinates = await this.usersService.getSubordinates(managerId);
    let subordinateIds = subordinates.map((s: any) => s.id);

    // 如果指定了组织，只保留该组织内的下属
    if (organizationId && subordinateIds.length > 0) {
      const orgMembers = await (this.prisma as any).userDepartment.findMany({
        where: { userId: { in: subordinateIds }, organizationId, leftAt: null },
        select: { userId: true },
      });
      const orgMemberIds = new Set(orgMembers.map((m: any) => m.userId));
      subordinateIds = subordinateIds.filter((id: string) => orgMemberIds.has(id));
    }

    if (subordinateIds.length === 0) {
      return { items: [], teamSize: 0, departments: [] };
    }

    const where: Prisma.KpiAssignmentWhereInput = {
      employeeId: { in: subordinateIds },
      deletedAt: null,
    };
    if (cycleId) where.cycleId = cycleId;

    const items = await this.prisma.kpiAssignment.findMany({
      where,
      include: {
        assessment: true,
      },
      orderBy: [{ employeeId: 'asc' }, { createdAt: 'asc' }],
    });

    // 获取员工信息
    const users = await this.prisma.user.findMany({
      where: { id: { in: subordinateIds }, deletedAt: null },
      select: { id: true, displayName: true, username: true, email: true, avatar: true },
    });
    const userMap = new Map(users.map((u) => [u.id, u]));

    // 获取员工部门信息
    const userDepts = await (this.prisma as any).userDepartment.findMany({
      where: {
        userId: { in: subordinateIds },
        leftAt: null,
        ...(organizationId ? { organizationId } : {}),
      },
      include: {
        department: { select: { id: true, name: true, code: true } },
        position: { select: { id: true, name: true } },
      },
    });
    const userDeptMap = new Map<string, any>();
    for (const ud of userDepts) {
      if (!userDeptMap.has(ud.userId) || ud.isPrimary) {
        userDeptMap.set(ud.userId, ud);
      }
    }

    // 收集部门列表
    const deptSet = new Map<string, { id: string; name: string }>();
    for (const ud of userDepts) {
      if (ud.department && !deptSet.has(ud.department.id)) {
        deptSet.set(ud.department.id, { id: ud.department.id, name: ud.department.name });
      }
    }

    // 获取下属的绩效结果（等级、分数）
    const resultWhere: any = { employeeId: { in: subordinateIds }, deletedAt: null };
    if (cycleId) resultWhere.cycleId = cycleId;
    const results = await this.prisma.performanceResult.findMany({
      where: resultWhere,
      select: { employeeId: true, gradeCode: true, gradeName: true, totalScore: true, isPublished: true, confirmStatus: true },
    });
    const resultByEmp = new Map(results.map((r) => [r.employeeId, r]));

    return {
      items: items.map((item) => {
        const user = userMap.get(item.employeeId);
        const ud = userDeptMap.get(item.employeeId);
        return {
          ...item,
          employee: user ? {
            id: user.id,
            displayName: user.displayName,
            username: user.username,
            email: user.email,
            avatar: user.avatar,
            department: ud?.department || null,
            position: ud?.position || null,
          } : null,
        };
      }),
      teamSize: subordinateIds.length,
      departments: Array.from(deptSet.values()),
      results: Object.fromEntries(resultByEmp),
    };
  }
}
