import {
  Injectable,
  NotFoundException,
  BadRequestException,
  ConflictException,
} from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { AssignWorkDto } from './dto/assign-work.dto';
import { CreateScoreDto } from './dto/create-score.dto';

@Injectable()
export class ReviewsService {
  constructor(private prisma: PrismaService) {}

  async assignWork(
    assignWorkDto: AssignWorkDto,
    contestId: number,
    creatorId?: number,
  ) {
    // 验证作品是否存在
    const work = await this.prisma.contestWork.findUnique({
      where: { id: assignWorkDto.workId },
      include: {
        contest: true,
      },
    });

    if (!work) {
      throw new NotFoundException('作品不存在');
    }

    if (work.contestId !== contestId) {
      throw new BadRequestException('作品不属于该活动');
    }

    // 检查评审时间
    const now = new Date();
    if (
      now < work.contest.reviewStartTime ||
      now > work.contest.reviewEndTime
    ) {
      throw new BadRequestException('不在评审时间范围内');
    }

    // 验证评委是否存在且是该活动的评委
    const judges = await this.prisma.contestJudge.findMany({
      where: {
        contestId,
        judgeId: { in: assignWorkDto.judgeIds },
        validState: 1,
      },
    });

    if (judges.length !== assignWorkDto.judgeIds.length) {
      throw new BadRequestException('部分评委不存在或不是该活动的评委');
    }

    // 创建分配记录
    const assignments = [];
    for (const judgeId of assignWorkDto.judgeIds) {
      // 检查是否已分配
      const existing = await this.prisma.contestWorkJudgeAssignment.findFirst({
        where: {
          workId: assignWorkDto.workId,
          judgeId,
        },
      });

      if (existing) {
        continue; // 跳过已分配的
      }

      const assignment = await this.prisma.contestWorkJudgeAssignment.create({
        data: {
          contestId,
          workId: assignWorkDto.workId,
          judgeId,
          status: 'assigned',
          creator: creatorId,
        },
        include: {
          judge: {
            select: {
              id: true,
              username: true,
              nickname: true,
            },
          },
        },
      });

      assignments.push(assignment);
    }

    return assignments;
  }

  async score(
    createScoreDto: CreateScoreDto,
    judgeId: number,
    tenantId: number,
  ) {
    // 验证分配记录是否存在
    const assignment = await this.prisma.contestWorkJudgeAssignment.findFirst({
      where: {
        id: createScoreDto.assignmentId,
        judgeId,
      },
      include: {
        work: {
          include: {
            contest: true,
          },
        },
      },
    });

    if (!assignment) {
      throw new NotFoundException('分配记录不存在');
    }

    if (assignment.workId !== createScoreDto.workId) {
      throw new BadRequestException('作品ID不匹配');
    }

    // 检查评审时间
    const now = new Date();
    if (
      now < assignment.work.contest.reviewStartTime ||
      now > assignment.work.contest.reviewEndTime
    ) {
      throw new BadRequestException('不在评审时间范围内');
    }

    // 检查是否已评分
    const existingScore = await this.prisma.contestWorkScore.findFirst({
      where: {
        assignmentId: createScoreDto.assignmentId,
        validState: 1,
      },
    });

    if (existingScore) {
      throw new ConflictException('该作品已评分，请使用更新接口');
    }

    // 获取评委信息
    const judge = await this.prisma.user.findUnique({
      where: { id: judgeId },
    });

    // 创建评分记录
    const data: any = {
      tenantId,
      contestId: assignment.work.contestId,
      workId: createScoreDto.workId,
      assignmentId: createScoreDto.assignmentId,
      judgeId,
      judgeName: judge?.nickname || judge?.username || '',
      dimensionScores: createScoreDto.dimensionScores || [],
      totalScore: createScoreDto.totalScore,
      comments: createScoreDto.comments || '',
      scoreTime: new Date(),
      creator: judgeId,
    };

    const score = await this.prisma.contestWorkScore.create({
      data,
      include: {
        work: {
          select: {
            id: true,
            title: true,
            workNo: true,
          },
        },
        judge: {
          select: {
            id: true,
            username: true,
            nickname: true,
          },
        },
      },
    });

    // 更新分配状态
    await this.prisma.contestWorkJudgeAssignment.update({
      where: { id: createScoreDto.assignmentId },
      data: {
        status: 'completed',
      },
    });

    // 更新作品状态
    await this.prisma.contestWork.update({
      where: { id: createScoreDto.workId },
      data: {
        status: 'reviewing',
      },
    });

    return score;
  }

  async updateScore(
    scoreId: number,
    updateScoreDto: Partial<CreateScoreDto>,
    judgeId: number,
  ) {
    const score = await this.prisma.contestWorkScore.findFirst({
      where: {
        id: scoreId,
        judgeId,
        validState: 1,
      },
      include: {
        work: {
          include: {
            contest: true,
          },
        },
      },
    });

    if (!score) {
      throw new NotFoundException('评分记录不存在');
    }

    // 检查评审时间
    const now = new Date();
    if (
      now < score.work.contest.reviewStartTime ||
      now > score.work.contest.reviewEndTime
    ) {
      throw new BadRequestException('不在评审时间范围内');
    }

    const data: any = {};

    if (updateScoreDto.dimensionScores !== undefined) {
      data.dimensionScores = JSON.stringify(updateScoreDto.dimensionScores);
    }
    if (updateScoreDto.totalScore !== undefined) {
      data.totalScore = updateScoreDto.totalScore;
    }
    if (updateScoreDto.comments !== undefined) {
      data.comments = updateScoreDto.comments;
    }

    data.modifier = judgeId;
    data.scoreTime = new Date();

    return this.prisma.contestWorkScore.update({
      where: { id: scoreId },
      data,
      include: {
        work: {
          select: {
            id: true,
            title: true,
            workNo: true,
          },
        },
        judge: {
          select: {
            id: true,
            username: true,
            nickname: true,
          },
        },
      },
    });
  }

  async getAssignedWorks(judgeId: number, contestId?: number) {
    const where: any = {
      judgeId,
    };

    if (contestId) {
      where.contestId = contestId;
    }

    return this.prisma.contestWorkJudgeAssignment.findMany({
      where,
      include: {
        work: {
          include: {
            registration: {
              include: {
                user: {
                  select: {
                    id: true,
                    username: true,
                    nickname: true,
                  },
                },
              },
            },
            attachments: true,
          },
        },
        scores: {
          where: { validState: 1 },
        },
      },
      orderBy: {
        assignmentTime: 'desc',
      },
    });
  }

  // 获取评委参与的活动列表
  async getJudgeContests(judgeId: number) {
    console.log('getJudgeContests - judgeId:', judgeId);

    // 获取评委参与的所有活动（通过作品分配表）
    const assignments = await this.prisma.contestWorkJudgeAssignment.findMany({
      where: {
        judgeId,
      },
      select: {
        contestId: true,
      },
      distinct: ['contestId'],
    });

    console.log('getJudgeContests - assignments:', assignments);
    const contestIds = assignments.map((a) => a.contestId);

    if (contestIds.length === 0) {
      return [];
    }

    // 获取活动详情和评审统计
    const contests = await this.prisma.contest.findMany({
      where: {
        id: { in: contestIds },
        validState: 1,
      },
      include: {
        reviewRule: true,
      },
      orderBy: {
        createTime: 'desc',
      },
    });

    // 计算每个活动的评审进度
    const result = await Promise.all(
      contests.map(async (contest) => {
        // 获取分配给该评委的作品数量
        const totalAssigned = await this.prisma.contestWorkJudgeAssignment.count({
          where: {
            contestId: contest.id,
            judgeId,
          },
        });

        // 获取已评审的作品数量
        const reviewed = await this.prisma.contestWorkScore.count({
          where: {
            contestId: contest.id,
            judgeId,
            validState: 1,
          },
        });

        return {
          ...contest,
          totalAssigned,
          reviewed,
          pending: totalAssigned - reviewed,
        };
      }),
    );

    return result;
  }

  // 获取评委在某个活动下分配的作品列表（带分页和搜索）
  async getJudgeContestWorks(
    judgeId: number,
    contestId: number,
    query: {
      page?: number;
      pageSize?: number;
      workNo?: string;
      accountNo?: string;
      reviewStatus?: string; // 'reviewed' | 'pending'
    },
  ) {
    const { page = 1, pageSize = 10, workNo, accountNo, reviewStatus } = query;

    // 构建查询条件
    const where: any = {
      judgeId,
      contestId,
    };

    // 如果需要按评审状态筛选，需要特殊处理
    const allAssignments = await this.prisma.contestWorkJudgeAssignment.findMany({
      where,
      include: {
        work: {
          include: {
            registration: {
              include: {
                user: {
                  select: {
                    id: true,
                    username: true,
                    nickname: true,
                  },
                },
              },
            },
          },
        },
        scores: {
          where: { validState: 1 },
          orderBy: { scoreTime: 'desc' },
          take: 1,
        },
      },
      orderBy: {
        assignmentTime: 'desc',
      },
    });

    // 按 workId 去重，保留第一条（最新的）
    const workIdSet = new Set<number>();
    let assignments = allAssignments.filter((a) => {
      if (workIdSet.has(a.workId)) {
        return false;
      }
      workIdSet.add(a.workId);
      return true;
    });

    // 应用搜索条件
    if (workNo) {
      assignments = assignments.filter((a) =>
        a.work.workNo?.toLowerCase().includes(workNo.toLowerCase()),
      );
    }

    if (accountNo) {
      assignments = assignments.filter(
        (a) =>
          a.work.registration?.user?.username
            ?.toLowerCase()
            .includes(accountNo.toLowerCase()) ||
          a.work.submitterAccountNo
            ?.toLowerCase()
            .includes(accountNo.toLowerCase()),
      );
    }

    // 应用评审状态筛选
    if (reviewStatus === 'reviewed') {
      assignments = assignments.filter((a) => a.scores.length > 0);
    } else if (reviewStatus === 'pending') {
      assignments = assignments.filter((a) => a.scores.length === 0);
    }

    const total = assignments.length;

    // 分页
    const start = (page - 1) * pageSize;
    const paginatedAssignments = assignments.slice(start, start + pageSize);

    // 转换为前端期望的格式
    const list = paginatedAssignments.map((assignment) => {
      const latestScore = assignment.scores[0];
      return {
        id: assignment.id,
        workId: assignment.workId,
        workNo: assignment.work.workNo,
        accountNo:
          assignment.work.submitterAccountNo ||
          assignment.work.registration?.user?.username ||
          '-',
        nickname: assignment.work.registration?.user?.nickname || '-',
        score: latestScore?.totalScore ?? null,
        reviewStatus: latestScore ? 'reviewed' : 'pending',
        assignmentTime: assignment.assignmentTime,
        work: assignment.work,
      };
    });

    return {
      list,
      total,
      page,
      pageSize,
    };
  }

  async getWorkScores(workId: number) {
    // 获取分配给作品的所有评委及其评分记录
    const assignments = await this.prisma.contestWorkJudgeAssignment.findMany({
      where: {
        workId,
      },
      include: {
        judge: {
          select: {
            id: true,
            username: true,
            nickname: true,
            phone: true,
            tenant: {
              select: {
                id: true,
                name: true,
              },
            },
          },
        },
        scores: {
          where: {
            validState: 1,
          },
          orderBy: {
            scoreTime: 'desc',
          },
          take: 1, // 只取最新的有效评分
        },
      },
      orderBy: {
        assignmentTime: 'desc',
      },
    });

    // 转换为前端期望的格式
    return assignments.map((assignment) => {
      const latestScore = assignment.scores[0];
      return {
        id: assignment.id,
        assignmentId: assignment.id,
        workId: assignment.workId,
        judgeId: assignment.judgeId,
        judge: assignment.judge,
        totalScore: latestScore?.totalScore ?? null,
        dimensionScores: latestScore?.dimensionScores ?? null,
        scoreTime: latestScore?.scoreTime ?? null,
        comments: latestScore?.comments ?? null,
        status: assignment.status,
        assignmentTime: assignment.assignmentTime,
      };
    });
  }

  async calculateFinalScore(workId: number) {
    const work = await this.prisma.contestWork.findUnique({
      where: { id: workId },
      include: {
        contest: {
          include: {
            reviewRule: true,
          },
        },
        scores: {
          where: { validState: 1 },
        },
      },
    });

    if (!work) {
      throw new NotFoundException('作品不存在');
    }

    if (!work.contest.reviewRule) {
      throw new BadRequestException('活动未配置评审规则');
    }

    if (work.scores.length === 0) {
      return {
        finalScore: 0,
        scoreCount: 0,
        calculationRule: work.contest.reviewRule.calculationRule,
      };
    }

    const scores = work.scores.map((s) => Number(s.totalScore));
    const calculationRule = work.contest.reviewRule.calculationRule;

    let finalScore = 0;

    switch (calculationRule) {
      case 'average':
        finalScore = scores.reduce((a, b) => a + b, 0) / scores.length;
        break;
      case 'max':
        finalScore = Math.max(...scores);
        break;
      case 'min':
        finalScore = Math.min(...scores);
        break;
      case 'weighted':
        // 加权平均需要从评委权重计算
        const judges = await this.prisma.contestJudge.findMany({
          where: {
            contestId: work.contestId,
            judgeId: { in: work.scores.map((s) => s.judgeId) },
            validState: 1,
          },
        });

        const judgeWeights = new Map<number, number>(
          judges.map((j) => [j.judgeId, Number(j.weight || 1)]),
        );

        let totalWeight = 0;
        let weightedSum = 0;

        work.scores.forEach((score) => {
          const weight = judgeWeights.get(score.judgeId) || 1;
          weightedSum += Number(score.totalScore) * weight;
          totalWeight += weight;
        });

        finalScore = totalWeight > 0 ? weightedSum / totalWeight : 0;
        break;
      default:
        finalScore = scores.reduce((a, b) => a + b, 0) / scores.length;
    }

    return {
      finalScore: Number(finalScore.toFixed(2)),
      scoreCount: scores.length,
      calculationRule,
    };
  }

  /**
   * 获取活动评审进度统计
   */
  async getReviewProgress(contestId: number) {
    // 获取活动信息
    const contest = await this.prisma.contest.findUnique({
      where: { id: contestId },
      include: {
        reviewRule: true,
      },
    });

    if (!contest) {
      throw new NotFoundException('活动不存在');
    }

    // 获取所有作品
    const totalWorks = await this.prisma.contestWork.count({
      where: {
        contestId,
        validState: 1,
      },
    });

    // 获取已分配的作品数（去重）
    const assignedWorkIds = await this.prisma.contestWorkJudgeAssignment.findMany({
      where: { contestId },
      select: { workId: true },
      distinct: ['workId'],
    });
    const assignedWorksCount = assignedWorkIds.length;

    // 获取已完成评审的作品数（每个作品被至少一个评委评分）
    const scoredWorkIds = await this.prisma.contestWorkScore.findMany({
      where: {
        contestId,
        validState: 1,
      },
      select: { workId: true },
      distinct: ['workId'],
    });
    const scoredWorksCount = scoredWorkIds.length;

    // 获取评委总数
    const totalJudges = await this.prisma.contestJudge.count({
      where: {
        contestId,
        validState: 1,
      },
    });

    // 获取总分配数和总评分数
    const totalAssignments = await this.prisma.contestWorkJudgeAssignment.count({
      where: { contestId },
    });

    const totalScores = await this.prisma.contestWorkScore.count({
      where: {
        contestId,
        validState: 1,
      },
    });

    // 计算评审进度百分比
    const assignmentProgress = totalWorks > 0 ? Math.round((assignedWorksCount / totalWorks) * 100) : 0;
    const scoringProgress = totalAssignments > 0 ? Math.round((totalScores / totalAssignments) * 100) : 0;
    const overallProgress = totalWorks > 0 ? Math.round((scoredWorksCount / totalWorks) * 100) : 0;

    // 获取每个评委的进度
    const judges = await this.prisma.contestJudge.findMany({
      where: {
        contestId,
        validState: 1,
      },
      include: {
        judge: {
          select: {
            id: true,
            username: true,
            nickname: true,
          },
        },
      },
    });

    const judgeProgress = await Promise.all(
      judges.map(async (judge) => {
        const assigned = await this.prisma.contestWorkJudgeAssignment.count({
          where: {
            contestId,
            judgeId: judge.judgeId,
          },
        });

        const scored = await this.prisma.contestWorkScore.count({
          where: {
            contestId,
            judgeId: judge.judgeId,
            validState: 1,
          },
        });

        const pending = assigned - scored;
        const progress = assigned > 0 ? Math.round((scored / assigned) * 100) : 0;

        return {
          judgeId: judge.judgeId,
          judgeName: judge.judge?.nickname || judge.judge?.username || '',
          specialty: judge.specialty,
          weight: judge.weight,
          assignedCount: assigned,
          scoredCount: scored,
          pendingCount: pending,
          progress,
        };
      }),
    );

    // 获取待分配作品列表（未分配给任何评委的作品）
    const unassignedWorks = await this.prisma.contestWork.findMany({
      where: {
        contestId,
        validState: 1,
        id: {
          notIn: assignedWorkIds.map((w) => w.workId),
        },
      },
      select: {
        id: true,
        workNo: true,
        title: true,
        createTime: true,
        registration: {
          select: {
            user: {
              select: {
                id: true,
                nickname: true,
                username: true,
              },
            },
            team: {
              select: {
                id: true,
                teamName: true,
              },
            },
          },
        },
      },
      take: 10,
      orderBy: { createTime: 'asc' },
    });

    // 获取待评审分配（已分配但未评分的）
    const pendingAssignments = await this.prisma.contestWorkJudgeAssignment.findMany({
      where: {
        contestId,
        status: { not: 'completed' },
      },
      include: {
        work: {
          select: {
            id: true,
            workNo: true,
            title: true,
          },
        },
        judge: {
          select: {
            id: true,
            nickname: true,
            username: true,
          },
        },
      },
      take: 10,
      orderBy: { assignmentTime: 'asc' },
    });

    return {
      contest: {
        id: contest.id,
        contestName: contest.contestName,
        reviewStartTime: contest.reviewStartTime,
        reviewEndTime: contest.reviewEndTime,
        reviewRule: contest.reviewRule,
      },
      summary: {
        totalWorks,
        assignedWorksCount,
        scoredWorksCount,
        unassignedWorksCount: totalWorks - assignedWorksCount,
        totalJudges,
        totalAssignments,
        totalScores,
        pendingScoresCount: totalAssignments - totalScores,
      },
      progress: {
        assignmentProgress,
        scoringProgress,
        overallProgress,
      },
      judgeProgress,
      unassignedWorks,
      pendingAssignments: pendingAssignments.map((a) => ({
        id: a.id,
        workId: a.work?.id,
        workNo: a.work?.workNo,
        workTitle: a.work?.title,
        judgeId: a.judge?.id,
        judgeName: a.judge?.nickname || a.judge?.username,
        status: a.status,
        assignmentTime: a.assignmentTime,
      })),
    };
  }

  /**
   * 获取作品评审状态统计（按状态分组）
   */
  async getWorkStatusStats(contestId: number) {
    const statusGroups = await this.prisma.contestWork.groupBy({
      by: ['status'],
      where: {
        contestId,
        validState: 1,
      },
      _count: {
        id: true,
      },
    });

    const statusMap: Record<string, number> = {};
    statusGroups.forEach((g) => {
      statusMap[g.status] = g._count.id;
    });

    return {
      submitted: statusMap['submitted'] || 0,
      reviewing: statusMap['reviewing'] || 0,
      reviewed: statusMap['reviewed'] || 0,
      awarded: statusMap['awarded'] || 0,
      total: Object.values(statusMap).reduce((a, b) => a + b, 0),
    };
  }

  /**
   * 批量分配作品给评委
   */
  async batchAssignWorks(
    contestId: number,
    workIds: number[],
    judgeIds: number[],
    creatorId?: number,
  ) {
    // 验证活动
    const contest = await this.prisma.contest.findUnique({
      where: { id: contestId },
    });

    if (!contest) {
      throw new NotFoundException('活动不存在');
    }

    // 验证评委
    const judges = await this.prisma.contestJudge.findMany({
      where: {
        contestId,
        judgeId: { in: judgeIds },
        validState: 1,
      },
    });

    if (judges.length !== judgeIds.length) {
      throw new BadRequestException('部分评委不存在或不是该活动的评委');
    }

    // 验证作品
    const works = await this.prisma.contestWork.findMany({
      where: {
        id: { in: workIds },
        contestId,
        validState: 1,
      },
    });

    if (works.length !== workIds.length) {
      throw new BadRequestException('部分作品不存在或不属于该活动');
    }

    // 批量创建分配
    const assignments = [];
    for (const workId of workIds) {
      for (const judgeId of judgeIds) {
        // 检查是否已分配
        const existing = await this.prisma.contestWorkJudgeAssignment.findFirst({
          where: { workId, judgeId },
        });

        if (existing) {
          continue;
        }

        const assignment = await this.prisma.contestWorkJudgeAssignment.create({
          data: {
            contestId,
            workId,
            judgeId,
            status: 'assigned',
            creator: creatorId,
          },
        });

        assignments.push(assignment);
      }
    }

    return {
      created: assignments.length,
      skipped: workIds.length * judgeIds.length - assignments.length,
      assignments,
    };
  }

  /**
   * 自动分配作品给评委（平均分配）
   */
  async autoAssignWorks(contestId: number, creatorId?: number) {
    // 获取未分配的作品
    const assignedWorkIds = await this.prisma.contestWorkJudgeAssignment.findMany({
      where: { contestId },
      select: { workId: true },
      distinct: ['workId'],
    });

    const unassignedWorks = await this.prisma.contestWork.findMany({
      where: {
        contestId,
        validState: 1,
        id: {
          notIn: assignedWorkIds.map((w) => w.workId),
        },
      },
    });

    if (unassignedWorks.length === 0) {
      return {
        message: '没有待分配的作品',
        created: 0,
      };
    }

    // 获取评委
    const judges = await this.prisma.contestJudge.findMany({
      where: {
        contestId,
        validState: 1,
      },
    });

    if (judges.length === 0) {
      throw new BadRequestException('该活动没有评委');
    }

    // 获取活动的评审规则
    const contest = await this.prisma.contest.findUnique({
      where: { id: contestId },
      include: { reviewRule: true },
    });

    // 每个作品分配的评委数量，默认3个
    // 注意：judgesPerWork 字段在数据库模型中不存在，使用默认值
    const judgesPerWork = 3;

    // 平均分配：每个作品分配给指定数量的评委
    const assignments = [];
    let judgeIndex = 0;

    for (const work of unassignedWorks) {
      const assignedJudges = new Set<number>();
      let attempts = 0;

      while (assignedJudges.size < Math.min(judgesPerWork, judges.length) && attempts < judges.length * 2) {
        const judge = judges[judgeIndex % judges.length];

        if (!assignedJudges.has(judge.judgeId)) {
          assignedJudges.add(judge.judgeId);

          const assignment = await this.prisma.contestWorkJudgeAssignment.create({
            data: {
              contestId,
              workId: work.id,
              judgeId: judge.judgeId,
              status: 'assigned',
              creator: creatorId,
            },
          });

          assignments.push(assignment);
        }

        judgeIndex++;
        attempts++;
      }
    }

    return {
      message: `成功分配 ${unassignedWorks.length} 个作品`,
      worksCount: unassignedWorks.length,
      created: assignments.length,
      judgesPerWork: Math.min(judgesPerWork, judges.length),
    };
  }
}
