import { BadRequestException, ForbiddenException, Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { ProgressService } from '../progress/progress.service';
import { MilestonesService } from '../milestones/milestones.service';
import { CardsService } from '../cards/cards.service';
import { AchievementsService } from '../achievements/achievements.service';

@Injectable()
export class QuestionsService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly progress: ProgressService,
    private readonly milestones: MilestonesService,
    private readonly cards: CardsService,
    private readonly achievements: AchievementsService,
  ) {}

  /** Returns this attempt's 7 questions WITHOUT the correct option — never trust the client to not read it. */
  async getActiveQuestionsForChapter(userId: string, chapterId: string) {
    const unlocked = await this.progress.isChapterUnlocked(userId, chapterId);
    if (!unlocked) throw new ForbiddenException('هذا الفصل غير مفتوح بعد.');

    const activeIds = await this.progress.getActiveQuestionIds(userId, chapterId);
    if (activeIds.length === 0) {
      throw new NotFoundException('لا توجد أسئلة لهذا الفصل.');
    }

    const questions = await this.prisma.question.findMany({
      where: { id: { in: activeIds } },
      include: { options: { orderBy: { optionIndex: 'asc' } } },
    });

    // Preserve the originally-picked random order, not DB insertion order.
    const byId = new Map(questions.map((q) => [q.id, q]));
    return activeIds
      .map((id) => byId.get(id))
      .filter((q): q is NonNullable<typeof q> => !!q)
      .map((q) => ({
        id: q.id,
        text: q.text,
        points: q.points,
        options: q.options.map((o) => ({ optionIndex: o.optionIndex, optionText: o.optionText })),
        // isCorrect intentionally omitted — this is the security boundary.
      }));
  }

  /**
   * Server-side answer validation — the correct option is fetched fresh
   * from the DB on every request and is NEVER present in any prior
   * response the client could have inspected. Mirrors
   * raseedna_ajax_submit_answer() in inc/quiz-handler.php.
   */
  async submitAnswer(userId: string, questionId: string, selectedOptionIndex: number) {
    const question = await this.prisma.question.findUnique({
      where: { id: questionId },
      include: { options: true },
    });
    if (!question) throw new NotFoundException('السؤال غير موجود.');

    const unlocked = await this.progress.isChapterUnlocked(userId, question.chapterId);
    if (!unlocked) throw new ForbiddenException('هذا الفصل غير مفتوح بعد.');

    const selected = question.options.find((o) => o.optionIndex === selectedOptionIndex);
    if (!selected) throw new BadRequestException('طلب غير صالح.');

    const correctOption = question.options.find((o) => o.isCorrect);
    const isCorrect = selected.isCorrect;

    await this.prisma.userAnswer.create({
      data: {
        userId,
        questionId,
        selectedOptionIndex,
        isCorrect,
      },
    });

    const response = {
      correct: isCorrect,
      explanation: isCorrect ? undefined : question.explanation,
      pointsAwarded: 0,
      alreadyCompleted: false,
      chapterJustCompleted: false,
      newlyUnlockedChapterId: null as string | null,
    };

    if (isCorrect) {
      const result = await this.progress.markQuestionCorrect(
        userId,
        questionId,
        question.chapterId,
        question.points,
      );
      response.pointsAwarded = result.points;
      response.alreadyCompleted = result.already_completed_question;
      response.chapterJustCompleted = result.chapter_just_completed;
      response.newlyUnlockedChapterId = result.newly_unlocked_chapter_id;

      await this.achievements.evaluateUnlocks(userId);

      if (result.chapter_just_completed) {
        await this.milestones.maybeAwardMilestones(userId);
        await this.cards.evaluateUnlocks(userId);
        await this.achievements.evaluateUnlocks(userId);
      }
    }

    void correctOption; // never serialized — kept only to make the security boundary explicit at a glance
    return response;
  }
}
