import { Injectable } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { Evaluation360Status, EvaluationTaskStatus, RelationType, Prisma } from '@prisma/client';
import { PERFORMANCE_ERROR_CODES } from '../constants/error-codes';
import { PERFORMANCE_PERMISSIONS } from '../constants/permissions';
import { BusinessException } from '@common/exceptions/business.exception';

/**
 * 360 评估服务
 * 负责评估创建、任务分发、匿名反馈、结果汇总
 */
@Injectable()
export class Evaluation360Service {
  constructor(private readonly prisma: PrismaService) {}

  /** 获取周期结束日期（用于 deadline 默认值） */
  async getCycleEndDate(cycleId: string): Promise<Date | null> {
    const cycle = await this.prisma.performanceCycle.findFirst({
      where: { id: cycleId },
      select: { endDate: true },
    });
    return cycle?.endDate ?? null;
  }

  /** 判断用户是否有权查看某员工的 360 评估 */
  canView360(employeeId: string, userId: string, roles: string[], permissions: string[]): boolean {
    if (employeeId === userId) return true;
    if (roles?.some((r) => r.toUpperCase() === 'ADMINISTRATOR' || r.toUpperCase() === 'ADMIN')) return true;
    if (permissions?.includes(PERFORMANCE_PERMISSIONS.E360_VIEW_RESULTS)) return true;
    return false;
  }

  private readonly VALID_TRANSITIONS: Record<Evaluation360Status, Evaluation360Status[]> = {
    DRAFT: ['IN_PROGRESS'],
    IN_PROGRESS: ['COLLECTING', 'COMPLETED', 'CANCELLED'],
    COLLECTING: ['COMPLETED', 'CANCELLED'],
    COMPLETED: [],
    CANCELLED: [],
  };

  private getTemplateDimensions(dimensions: unknown): string[] {
    if (!Array.isArray(dimensions)) {
      return [];
    }

    return dimensions
      .map((item) => {
        if (typeof item === 'string') {
          return item;
        }
        if (item && typeof item === 'object') {
          const record = item as Record<string, unknown>;
          const key = record.key || record.name || record.dimension;
          return typeof key === 'string' ? key : undefined;
        }
        return undefined;
      })
      .filter((value): value is string => Boolean(value));
  }

  // ==================== 评估管理 ====================

  async create(data: {
    cycleId: string;
    targetId: string;
    templateId?: string;
    deadline: Date;
    minEvaluators?: number;
    createdBy: string;
    evaluators?: { evaluatorId: string; relationType: RelationType; isAnonymous?: boolean }[];
  }) {
    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,
      );
    }

    return this.prisma.evaluation360.create({
      data: {
        cycleId: data.cycleId,
        targetId: data.targetId,
        templateId: data.templateId,
        deadline: data.deadline,
        minEvaluators: data.minEvaluators,
        status: 'DRAFT',
        createdBy: data.createdBy,
        tasks: data.evaluators
          ? {
              create: data.evaluators.map((e) => ({
                evaluatorId: e.evaluatorId,
                relationType: e.relationType,
                isAnonymous: e.isAnonymous ?? true,
                status: 'PENDING',
              })),
            }
          : undefined,
      },
      include: {
        tasks: true,
        template: true,
      },
    });
  }

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

    const where: Prisma.Evaluation360WhereInput = { deletedAt: null };
    if (cycleId) where.cycleId = cycleId;
    if (status) where.status = status;

    const [items, total] = await Promise.all([
      this.prisma.evaluation360.findMany({
        where,
        skip,
        take: pageSize,
        orderBy: { createdAt: 'desc' },
        include: {
          tasks: { where: { deletedAt: null }, select: { id: true, status: true } },
          template: { select: { id: true, name: true } },
        },
      }),
      this.prisma.evaluation360.count({ where }),
    ]);

    // 添加任务统计 + evaluateeId 别名（前端使用 evaluateeId）
    const itemsWithStats = items.map((item) => ({
      ...item,
      evaluateeId: item.targetId,
      taskStats: {
        total: item.tasks.length,
        pending: item.tasks.filter((t) => t.status === 'PENDING').length,
        submitted: item.tasks.filter((t) => t.status === 'SUBMITTED').length,
      },
    }));

    return {
      items: itemsWithStats,
      pagination: { page, pageSize, total, totalPages: Math.ceil(total / pageSize) },
    };
  }

  async findById(id: string) {
    const evaluation = await this.prisma.evaluation360.findFirst({
      where: { id, deletedAt: null },
      include: {
        tasks: {
          include: {
            responses: { where: { deletedAt: null } },
          },
          where: { deletedAt: null },
        },
        template: true,
        cycle: { select: { id: true, name: true, status: true } },
      },
    });

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

    // 添加 evaluateeId 别名（前端使用 evaluateeId）
    return { ...evaluation, evaluateeId: evaluation.targetId };
  }

  async update(
    id: string,
    data: { templateId?: string; deadline?: Date; minEvaluators?: number },
  ) {
    const evaluation = await this.findById(id);
    if (evaluation.status !== 'DRAFT') {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.message,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.code,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.httpStatus,
      );
    }

    return this.prisma.evaluation360.update({
      where: { id },
      data,
    });
  }

  async delete(id: string) {
    const evaluation = await this.findById(id);
    if (evaluation.status !== 'DRAFT') {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.message,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.code,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.httpStatus,
      );
    }

    await this.prisma.$transaction([
      this.prisma.evaluation360.update({
        where: { id },
        data: { deletedAt: new Date() },
      }),
      this.prisma.evaluationTask.updateMany({
        where: { evaluationId: id, deletedAt: null },
        data: { deletedAt: new Date() },
      }),
      this.prisma.evaluationResponse.updateMany({
        where: { task: { evaluationId: id }, deletedAt: null },
        data: { deletedAt: new Date() },
      }),
    ]);
    return { success: true };
  }

  // ==================== 状态流转 ====================

  async start(id: string) {
    const evaluation = await this.findById(id);

    if (evaluation.status !== 'DRAFT') {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.message,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.code,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.httpStatus,
      );
    }

    if (!evaluation.templateId) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.E360_TEMPLATE_REQUIRED.message,
        PERFORMANCE_ERROR_CODES.E360_TEMPLATE_REQUIRED.code,
        PERFORMANCE_ERROR_CODES.E360_TEMPLATE_REQUIRED.httpStatus,
      );
    }

    if (evaluation.tasks.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: 'evaluators_required' },
      );
    }

    const peerCount = evaluation.tasks.filter((task) => task.relationType === 'PEER').length;
    const minPeers = evaluation.minEvaluators ?? 3;
    if (peerCount < minPeers) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.E360_MIN_EVALUATORS_NOT_MET.message,
        PERFORMANCE_ERROR_CODES.E360_MIN_EVALUATORS_NOT_MET.code,
        PERFORMANCE_ERROR_CODES.E360_MIN_EVALUATORS_NOT_MET.httpStatus,
      );
    }

    return this.prisma.evaluation360.update({
      where: { id },
      data: { status: 'IN_PROGRESS' },
    });
  }

  async complete(id: string) {
    const evaluation = await this.findById(id);

    if (!['IN_PROGRESS', 'COLLECTING'].includes(evaluation.status)) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.message,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.code,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.httpStatus,
      );
    }

    if (evaluation.minEvaluators) {
      const submittedCount = evaluation.tasks.filter((task) => task.status === 'SUBMITTED').length;
      if (submittedCount < evaluation.minEvaluators) {
        throw new BusinessException(
          PERFORMANCE_ERROR_CODES.E360_RESULT_MINIMUM_NOT_MET.message,
          PERFORMANCE_ERROR_CODES.E360_RESULT_MINIMUM_NOT_MET.code,
          PERFORMANCE_ERROR_CODES.E360_RESULT_MINIMUM_NOT_MET.httpStatus,
        );
      }
    }

    return this.prisma.evaluation360.update({
      where: { id },
      data: { status: 'COMPLETED' },
    });
  }

  // ==================== 任务管理 ====================

  async addEvaluators(
    evaluationId: string,
    evaluators: { evaluatorId: string; relationType: RelationType; isAnonymous?: boolean }[],
  ) {
    const evaluation = await this.findById(evaluationId);

    if (!['DRAFT', 'IN_PROGRESS'].includes(evaluation.status)) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.message,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.code,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.httpStatus,
      );
    }

    const existingEvaluatorIds = evaluation.tasks.map((t) => t.evaluatorId);
    const newEvaluators = evaluators.filter((e) => !existingEvaluatorIds.includes(e.evaluatorId));

    if (newEvaluators.length === 0) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.E360_RELATION_DUPLICATE.message,
        PERFORMANCE_ERROR_CODES.E360_RELATION_DUPLICATE.code,
        PERFORMANCE_ERROR_CODES.E360_RELATION_DUPLICATE.httpStatus,
      );
    }

    await this.prisma.evaluationTask.createMany({
      data: newEvaluators.map((e) => ({
        evaluationId,
        evaluatorId: e.evaluatorId,
        relationType: e.relationType,
        isAnonymous: e.isAnonymous ?? true,
        status: 'PENDING',
      })),
    });

    return this.findById(evaluationId);
  }

  async removeEvaluator(evaluationId: string, evaluatorId: string) {
    const evaluation = await this.findById(evaluationId);

    if (evaluation.status !== 'DRAFT') {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.message,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.code,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.httpStatus,
      );
    }

    await this.prisma.evaluationTask.updateMany({
      where: { evaluationId, evaluatorId, deletedAt: null },
      data: { deletedAt: new Date() },
    });

    return { success: true };
  }

  async findTasks(query: {
    evaluationId?: string;
    evaluatorId?: string;
    status?: EvaluationTaskStatus;
  }) {
    const { evaluationId, evaluatorId, status } = query;

    const where: Prisma.EvaluationTaskWhereInput = {
      deletedAt: null,
      evaluation: { deletedAt: null },
    };
    if (evaluationId) where.evaluationId = evaluationId;
    if (evaluatorId) where.evaluatorId = evaluatorId;
    if (status) where.status = status;

    return this.prisma.evaluationTask.findMany({
      where,
      orderBy: { createdAt: 'desc' },
      include: {
        evaluation: {
          select: { id: true, targetId: true, deadline: true, status: true },
        },
      },
    });
  }

  async findMyTasks(userId: string) {
    const tasks = await this.prisma.evaluationTask.findMany({
      where: {
        evaluatorId: userId,
        status: 'PENDING',
        deletedAt: null,
        evaluation: {
          deletedAt: null,
          status: { in: ['IN_PROGRESS', 'COLLECTING'] },
        },
      },
      include: {
        evaluation: {
          select: { id: true, targetId: true, status: true, deadline: true, template: true },
        },
      },
      orderBy: { createdAt: 'asc' },
    });

    // 查询目标用户信息，供前端显示
    const targetIds = [...new Set(tasks.map((t) => t.evaluation.targetId))];
    const targetUsers = targetIds.length > 0
      ? await this.prisma.$queryRaw<{ id: string; username: string; display_name: string }[]>`
          SELECT id, username, display_name FROM platform_iam.users WHERE id = ANY(${targetIds}::uuid[])
        `
      : [];
    const targetUserMap = new Map(targetUsers.map((u) => [u.id, u]));

    return tasks.map((task) => {
      const targetUser = targetUserMap.get(task.evaluation.targetId);
      return {
        ...task,
        relationship: task.relationType,
        evaluation: {
          ...task.evaluation,
          targetUser: targetUser
            ? { id: targetUser.id, username: targetUser.username, displayName: targetUser.display_name }
            : null,
        },
      };
    });
  }

  // ==================== 反馈处理 ====================

  async submitFeedback(
    taskId: string,
    responses: { dimension: string; score: number; comment?: string }[],
    currentUserId: string,
  ) {
    const task = await this.prisma.evaluationTask.findFirst({
      where: { id: taskId, deletedAt: null },
      include: { evaluation: { include: { template: true } } },
    });

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

    if (task.evaluatorId !== currentUserId) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.message,
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.code,
        PERFORMANCE_ERROR_CODES.COMMON_FORBIDDEN.httpStatus,
      );
    }

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

    if (!['IN_PROGRESS', 'COLLECTING'].includes(task.evaluation.status)) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.message,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.code,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.httpStatus,
      );
    }

    if (task.evaluation.deadline && new Date() > task.evaluation.deadline) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.E360_DEADLINE_PASSED.message,
        PERFORMANCE_ERROR_CODES.E360_DEADLINE_PASSED.code,
        PERFORMANCE_ERROR_CODES.E360_DEADLINE_PASSED.httpStatus,
      );
    }

    const templateDimensions = this.getTemplateDimensions(task.evaluation.template?.dimensions);
    if (templateDimensions.length > 0) {
      const responseDimensions = responses.map((r) => r.dimension);
      const missing = templateDimensions.filter((d) => !responseDimensions.includes(d));
      if (missing.length > 0) {
        throw new BusinessException(
          PERFORMANCE_ERROR_CODES.E360_REQUIRED_DIMENSION_MISSING.message,
          PERFORMANCE_ERROR_CODES.E360_REQUIRED_DIMENSION_MISSING.code,
          PERFORMANCE_ERROR_CODES.E360_REQUIRED_DIMENSION_MISSING.httpStatus,
          { missing },
        );
      }
    }

    // 验证分数范围
    for (const r of responses) {
      if (r.score < 1 || r.score > 5) {
        throw new BusinessException(
          PERFORMANCE_ERROR_CODES.E360_SCORE_INVALID.message,
          PERFORMANCE_ERROR_CODES.E360_SCORE_INVALID.code,
          PERFORMANCE_ERROR_CODES.E360_SCORE_INVALID.httpStatus,
          { dimension: r.dimension },
        );
      }
    }

    await this.prisma.$transaction([
      this.prisma.evaluationResponse.createMany({
        data: responses.map((r) => ({
          taskId,
          dimension: r.dimension,
          score: r.score,
          comment: r.comment,
        })),
      }),
      this.prisma.evaluationTask.update({
        where: { id: taskId },
        data: {
          status: 'SUBMITTED',
          submittedAt: new Date(),
        },
      }),
    ]);

    // 检查是否所有 task 都已提交，如果是则自动完成评估
    const remainingTasks = await this.prisma.evaluationTask.count({
      where: {
        evaluationId: task.evaluationId,
        deletedAt: null,
        status: 'PENDING',
      },
    });

    if (remainingTasks === 0) {
      await this.prisma.evaluation360.update({
        where: { id: task.evaluationId },
        data: { status: 'COMPLETED' },
      });
    }

    return { success: true };
  }

  // ==================== 结果汇总 ====================

  async getResults(evaluationId: string) {
    const evaluation = await this.findById(evaluationId);

    if (evaluation.status !== 'COMPLETED') {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.message,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.code,
        PERFORMANCE_ERROR_CODES.E360_STATUS_INVALID.httpStatus,
      );
    }

    const submittedTasks = evaluation.tasks.filter((t) => t.status === 'SUBMITTED');

    // 按维度汇总
    const dimensionMap = new Map<string, { scores: number[]; comments: string[] }>();

    for (const task of submittedTasks) {
      for (const response of task.responses) {
        if (!dimensionMap.has(response.dimension)) {
          dimensionMap.set(response.dimension, { scores: [], comments: [] });
        }
        const entry = dimensionMap.get(response.dimension)!;
        entry.scores.push(Number(response.score));
        if (response.comment) entry.comments.push(response.comment);
      }
    }

    const dimensionScores = Array.from(dimensionMap.entries()).map(([dimension, data]) => ({
      dimension,
      avgScore: data.scores.reduce((a, b) => a + b, 0) / data.scores.length,
      responseCount: data.scores.length,
    }));

    // 按关系类型汇总
    const relationMap = new Map<RelationType, number[]>();
    for (const task of submittedTasks) {
      if (!relationMap.has(task.relationType)) {
        relationMap.set(task.relationType, []);
      }
      const taskAvg =
        task.responses.reduce((sum, r) => sum + Number(r.score), 0) / (task.responses.length || 1);
      relationMap.get(task.relationType)!.push(taskAvg);
    }

    const relationBreakdown = Array.from(relationMap.entries()).map(([relationType, scores]) => ({
      relationType,
      avgScore: scores.reduce((a, b) => a + b, 0) / scores.length,
      count: scores.length,
    }));

    // 计算总体平均分
    const overallScore = dimensionScores.length > 0
      ? dimensionScores.reduce((sum, d) => sum + d.avgScore, 0) / dimensionScores.length
      : 0;

    return {
      evaluationId,
      targetId: evaluation.targetId,
      overallScore,
      dimensionScores,
      relationBreakdown,
      completedTasks: submittedTasks.length,
      totalTasks: evaluation.tasks.length,
    };
  }

  async calculateAggregateScore(evaluationId: string): Promise<number> {
    const results = await this.getResults(evaluationId);
    return results.overallScore;
  }

  /**
   * 获取员工 360 评估汇总（按 cycleId + employeeId 查询）
   */
  async getEmployee360Summary(cycleId: string, employeeId: string) {
    const evaluation = await this.prisma.evaluation360.findFirst({
      where: {
        cycleId,
        targetId: employeeId,
        deletedAt: null,
      },
      include: {
        tasks: {
          where: { deletedAt: null },
          include: { responses: true },
        },
      },
    });

    if (!evaluation) return null;

    // 只要有已提交的任务就计算实时汇总（评完即可见）
    const submittedTasks = evaluation.tasks.filter((t) => t.status === 'SUBMITTED');

    if (submittedTasks.length === 0) {
      return {
        evaluationId: evaluation.id,
        status: evaluation.status,
        completedCount: 0,
        totalCount: evaluation.tasks.length,
      };
    }

    // 计算维度得分汇总
    const dimensionMap = new Map<string, { total: number; count: number }>();
    const relationMap = new Map<string, { total: number; count: number; taskCount: number }>();

    for (const task of submittedTasks) {
      const rel = task.relationType;
      if (!relationMap.has(rel)) relationMap.set(rel, { total: 0, count: 0, taskCount: 0 });
      const relStats = relationMap.get(rel)!;
      relStats.taskCount++;

      for (const resp of task.responses) {
        // 维度汇总
        if (!dimensionMap.has(resp.dimension)) dimensionMap.set(resp.dimension, { total: 0, count: 0 });
        const dimStats = dimensionMap.get(resp.dimension)!;
        dimStats.total += Number(resp.score);
        dimStats.count++;

        // 关系类型汇总
        relStats.total += Number(resp.score);
        relStats.count++;
      }
    }

    const dimensionScores = Array.from(dimensionMap.entries()).map(([dim, stats]) => ({
      dimension: dim,
      avgScore: Math.round(stats.total / stats.count * 10) / 10,
      count: stats.count,
    }));

    const allScores = submittedTasks.flatMap((t) => t.responses.map((r) => Number(r.score)));
    const aggregateScore = allScores.length > 0
      ? Math.round(allScores.reduce((s, v) => s + v, 0) / allScores.length * 10) / 10
      : 0;

    const scoresByRelationship = Array.from(relationMap.entries()).map(([rel, stats]) => ({
      relationship: rel,
      avgScore: stats.count > 0 ? Math.round(stats.total / stats.count * 10) / 10 : 0,
      count: stats.taskCount,
    }));

    return {
      evaluationId: evaluation.id,
      status: evaluation.status,
      completedCount: submittedTasks.length,
      totalCount: evaluation.tasks.length,
      aggregateScore,
      dimensionScores,
      scoresByRelationship,
    };
  }

  /**
   * 获取员工的 360 评估实体（按 cycleId + employeeId 查询）
   */
  async getEmployee360Evaluation(cycleId: string, employeeId: string) {
    const evaluation = await this.prisma.evaluation360.findFirst({
      where: {
        cycleId,
        targetId: employeeId,
        deletedAt: null,
      },
      include: {
        tasks: {
          where: { deletedAt: null },
          include: {
            responses: true,
          },
        },
      },
    });

    if (!evaluation) return null;

    // 补充 evaluator 用户信息
    const evaluatorIds = evaluation.tasks.map((t) => t.evaluatorId);
    const evaluators = evaluatorIds.length > 0
      ? await this.prisma.user.findMany({
          where: { id: { in: evaluatorIds } },
          select: { id: true, displayName: true, username: true, email: true, avatar: true },
        })
      : [];
    const evaluatorMap = new Map(evaluators.map((u) => [u.id, u]));

    return {
      ...evaluation,
      tasks: evaluation.tasks.map((t) => ({
        ...t,
        evaluator: evaluatorMap.get(t.evaluatorId) || null,
      })),
    };
  }
}
