import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
import { PrismaService } from '../../infrastructure/database/prisma.service';
import { isValidQuestionType, gradeAnswer, type QuestionType } from './quiz-type.contract';

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

  async create(userId: string, dto: { knowledgeBaseId: string; title?: string; sourceType?: string; sourceId?: string; questionCount?: number }) {
    const count = dto.questionCount ?? 5;
    const kb = await this.prisma.knowledgeBase.findUnique({ where: { id: dto.knowledgeBaseId } });
    if (!kb || kb.deletedAt) throw new NotFoundException('知识库不存在');

    const quiz = await this.prisma.quiz.create({
      data: {
        userId, knowledgeBaseId: dto.knowledgeBaseId,
        title: dto.title || `${kb.title} - 自测`,
        sourceType: dto.sourceType ?? 'kb', sourceId: dto.sourceId ?? null,
        questionCount: count,
      },
    });

    // Generate questions from KB items
    const items = await this.prisma.knowledgeItem.findMany({
      where: { knowledgeBaseId: dto.knowledgeBaseId, deletedAt: null },
      orderBy: { updatedAt: 'desc' }, take: count * 2,
    });

    if (items.length === 0) throw new BadRequestException('知识库中没有知识点，无法生成测验');

    const shuffled = items.sort(() => Math.random() - 0.5).slice(0, count);
    const questions: any[] = [];

    for (let i = 0; i < shuffled.length; i++) {
      const item = shuffled[i];
      const otherItems = items.filter(x => x.id !== item.id);

      // Alternate question types
      const types = ['choice', 'fill', 'judge'];
      const qType = types[i % 3];

      let stem = '', options: string[] = [], answer = '';

      if (qType === 'choice') {
        stem = `${item.title} 是什么？`;
        const correct = item.content?.slice(0, 80) ?? '正确答案';
        options = [correct];
        for (const o of otherItems.slice(0, 3)) {
          options.push(o.content?.slice(0, 80) ?? '其他选项');
        }
        options = options.sort(() => Math.random() - 0.5);
        answer = String(options.indexOf(correct));
      } else if (qType === 'fill') {
        const words = (item.content ?? '').split(/[，。；\s]+/).filter(w => w.length >= 3);
        const blank = words.length > 0 ? words[Math.floor(Math.random() * words.length)] : '关键概念';
        stem = `${item.title}：请填写缺失的关键词。${(item.content ?? '').replace(blank, '____')}`;
        answer = blank;
      } else {
        const isCorrect = Math.random() > 0.5;
        stem = `关于「${item.title}」，以下说法是否正确？${isCorrect ? item.content?.slice(0, 100) ?? '正确描述' : '错误描述'}`;
        answer = String(isCorrect);
      }

      questions.push({
        quizId: quiz.id, type: qType, stem,
        options: options.length > 0 ? options : undefined,
        answer, explanation: item.content?.slice(0, 200) ?? '',
        orderIndex: i,
      });
    }

    await this.prisma.quizQuestion.createMany({ data: questions });

    return this.prisma.quiz.findUnique({ where: { id: quiz.id }, include: { questions: { orderBy: { orderIndex: 'asc' } } } });
  }

  async findAll(userId: string, kbId?: string) {
    return this.prisma.quiz.findMany({
      where: { userId, ...(kbId ? { knowledgeBaseId: kbId } : {}) },
      orderBy: { createdAt: 'desc' },
    });
  }

  async findOne(userId: string, id: string) {
    const quiz = await this.prisma.quiz.findUnique({
      where: { id, userId },
      // M-AI-07-06: 不 include questions（避免答案泄漏）
      // 客户端应使用 getAttemptQuestions 获取题目，submit 后通过 getResults 获取答案
    });
    if (!quiz) throw new NotFoundException('测验不存在');
    return quiz;
  }

  // M-QUIZ-01-01: 创建独立 Attempt（每次答题启动新 Attempt）
  async start(userId: string, quizId: string) {
    const quiz = await this.prisma.quiz.findUnique({ where: { id: quizId, userId } });
    if (!quiz) throw new NotFoundException('测验不存在');

    return this.prisma.quizAttempt.create({
      data: { quizId, userId, totalQuestions: quiz.questionCount },
    });
  }

  // M-QUIZ-01-01: 按 Attempt 加载题目，未提交前不返回 answer/explanation
  async getAttemptQuestions(userId: string, attemptId: string) {
    // N2：userId 进入查询条件，统一 404（与 getResults 一致）
    const attempt = await this.prisma.quizAttempt.findUnique({
      where: { id: attemptId, userId },
      select: { id: true, quizId: true, finishedAt: true },
    });
    if (!attempt) throw new NotFoundException('答题记录不存在');

    const isFinished = attempt.finishedAt !== null;

    return this.prisma.quizQuestion.findMany({
      where: { quizId: attempt.quizId },
      select: {
        id: true, type: true, stem: true, options: true,
        // M-QUIZ-01-01: 仅当前 Attempt 已提交后才返回 answer 和 explanation
        // 历史 Attempt 的完成状态不影响当前 Attempt 的答案可见性
        ...(isFinished ? { answer: true, explanation: true } : {}),
        sourceBlockIds: true, orderIndex: true,
      },
      orderBy: { orderIndex: 'asc' },
    });
  }

  async submit(userId: string, attemptId: string, answers: { questionId: string; answer: string }[]) {
    if (!answers || answers.length === 0) {
      throw new BadRequestException('至少需要提交一个答案');
    }

    // M-QUIZ-01-02: 原子提交 + 幂等控制
    return this.prisma.$transaction(async (tx) => {
      // N1 修复：使用 updateMany 写锁替代 findUnique 快照读
      // UPDATE ... WHERE finishedAt IS NULL 在 MySQL 中获取排他行锁，
      // 并发事务只有一个能匹配成功，彻底消除 REPEATABLE READ 下的竞态窗口
      const cas = await tx.quizAttempt.updateMany({
        where: { id: attemptId, userId, finishedAt: null },
        data: { finishedAt: new Date() },
      });

      if (cas.count === 0) {
        const attempt = await tx.quizAttempt.findUnique({ where: { id: attemptId } });
        if (!attempt || attempt.userId !== userId) throw new NotFoundException('答题记录不存在');
        throw new BadRequestException('已提交过答案');
      }

      // 服务端判分：比对正确答案，客户端传入的 isCorrect 不可信
      let correctCount = 0;
      const answerRecords: Array<{
        attemptId: string;
        questionId: string;
        userAnswer: string;
        isCorrect: boolean;
      }> = [];

      for (const a of answers) {
        const q = await tx.quizQuestion.findUnique({ where: { id: a.questionId } });
        if (!q) throw new BadRequestException(`题目 ${a.questionId} 不存在`);

        // M-QUIZ-01-04: 按题型分发判分逻辑（fill 使用规范化比较）
        if (!isValidQuestionType(q.type)) {
          throw new BadRequestException(`题目 ${a.questionId} 类型非法: ${q.type}`);
        }
        const isCorrect = gradeAnswer(q.type as QuestionType, a.answer, q.answer);
        if (isCorrect) correctCount++;
        answerRecords.push({
          attemptId,
          questionId: a.questionId,
          userAnswer: a.answer,
          isCorrect,
        });
      }

      // 批量原子写入 QuizAnswer
      if (answerRecords.length > 0) {
        await tx.quizAnswer.createMany({ data: answerRecords });
      }

      // 同一事务内结算最终分数（finishedAt 已由 CAS 占位）
      const score = Math.round((correctCount / answers.length) * 100);
      await tx.quizAttempt.update({
        where: { id: attemptId },
        data: { correctCount, score },
      });

      return { score, correctCount, totalQuestions: answers.length, finishedAt: new Date() };
    });
  }

  // M-QUIZ-01-01: 结果查询增加 userId 校验（与 submit 一致：userId 进入查询条件，避免 403 vs 404 暴露 attempt 存在性）
  async getResults(userId: string, attemptId: string) {
    const attempt = await this.prisma.quizAttempt.findUnique({
      where: { id: attemptId, userId },
      include: { answers: { include: { question: true } } },
    });
    if (!attempt) throw new NotFoundException('答题记录不存在');
    return attempt;
  }

  async getHistory(userId: string) {
    return this.prisma.quizAttempt.findMany({
      where: { userId }, orderBy: { startedAt: 'desc' }, take: 50,
      include: { quiz: { select: { title: true } } },
    });
  }
}
