<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\SelfPaced\Course;
use App\Models\SelfPaced\Enrollment;
use App\Models\SelfPaced\ExamAttempt;
use App\Models\SelfPaced\ExamQuestion;
use App\Models\SelfPaced\ExamResult;
use App\Models\SelfPaced\SelfPacedCertificate;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;

/**
 * SelfPacedResultSeeder
 *
 * Seeds sample exam attempts, results, and certificates for testing.
 * Creates:
 *   - A passing attempt + result + certificate for completed enrollments
 *   - A failing attempt + result (no certificate) for active enrollments
 * Depends on SelfPacedEnrollmentSeeder and SelfPacedExamSeeder having run first.
 *
 * Requirements: 15.6
 */
class SelfPacedResultSeeder extends Seeder
{
    public function run(): void
    {
        // Seed results for completed enrollments (passed)
        $completedEnrollments = Enrollment::where('status', 'completed')
            ->with(['course.examQuestions', 'user'])
            ->get();

        foreach ($completedEnrollments as $enrollment) {
            $this->seedPassingResult($enrollment);
        }

        // Seed a failing result for one active enrollment (health course, trainee 2)
        $activeEnrollment = Enrollment::where('status', 'active')
            ->whereHas('course', fn ($q) => $q->where('slug', 'health-sector-leadership-management'))
            ->with(['course.examQuestions', 'user'])
            ->first();

        if ($activeEnrollment) {
            $this->seedFailingResult($activeEnrollment);
        }

        $this->command->info('SelfPacedResultSeeder: Sample exam results and certificates seeded.');
    }

    private function seedPassingResult(Enrollment $enrollment): void
    {
        $course    = $enrollment->course;
        $questions = $course->examQuestions()->where('is_active', true)->get();

        if ($questions->isEmpty()) {
            return;
        }

        // Skip if an attempt already exists for this enrollment
        if (ExamAttempt::where('enrollment_id', $enrollment->id)->exists()) {
            return;
        }

        $questionIds = $questions->pluck('id')->take($course->exam_questions_per_attempt)->toArray();
        $total       = count($questionIds);

        // Build answers — answer all correctly (passing score)
        $answers = [];
        foreach ($questionIds as $qid) {
            $q = $questions->firstWhere('id', $qid);
            if ($q) {
                $answers[(string) $qid] = $q->correct_answer;
            }
        }

        $startedAt   = Carbon::now()->subDays(rand(5, 20))->subMinutes(rand(30, 55));
        $submittedAt = $startedAt->copy()->addMinutes(rand(25, 50));
        $expiresAt   = $startedAt->copy()->addMinutes($course->exam_time_limit);

        $attempt = ExamAttempt::create([
            'enrollment_id' => $enrollment->id,
            'user_id'       => $enrollment->user_id,
            'course_id'     => $course->id,
            'started_at'    => $startedAt,
            'submitted_at'  => $submittedAt,
            'expires_at'    => $expiresAt,
            'status'        => 'submitted',
            'answers'       => $answers,
            'question_ids'  => $questionIds,
            'created_at'    => $startedAt,
            'updated_at'    => $submittedAt,
        ]);

        // Calculate score — all correct
        $correct         = $total;
        $scorePercentage = round(($correct / $total) * 100, 2);
        $passed          = $scorePercentage >= $course->passing_score;

        $result = ExamResult::create([
            'attempt_id'        => $attempt->id,
            'enrollment_id'     => $enrollment->id,
            'user_id'           => $enrollment->user_id,
            'course_id'         => $course->id,
            'total_questions'   => $total,
            'correct_answers'   => $correct,
            'score_percentage'  => $scorePercentage,
            'passed'            => $passed,
            'passing_threshold' => $course->passing_score,
            'created_at'        => $submittedAt,
            'updated_at'        => $submittedAt,
        ]);

        // Generate certificate if passed
        if ($passed) {
            $this->seedCertificate($result, $enrollment, $submittedAt);
        }
    }

    private function seedFailingResult(Enrollment $enrollment): void
    {
        $course    = $enrollment->course;
        $questions = $course->examQuestions()->where('is_active', true)->get();

        if ($questions->isEmpty()) {
            return;
        }

        // Skip if a failing attempt already exists
        if (ExamAttempt::where('enrollment_id', $enrollment->id)->where('status', 'submitted')->exists()) {
            return;
        }

        $questionIds = $questions->pluck('id')->take($course->exam_questions_per_attempt)->toArray();
        $total       = count($questionIds);

        // Answer only 30% correctly — guaranteed fail
        $correctCount = (int) floor($total * 0.3);
        $answers      = [];
        foreach ($questionIds as $index => $qid) {
            $q = $questions->firstWhere('id', $qid);
            if (!$q) {
                continue;
            }
            if ($index < $correctCount) {
                $answers[(string) $qid] = $q->correct_answer;
            } else {
                // Pick a wrong answer
                $wrong = collect(['A', 'B', 'C', 'D'])
                    ->reject(fn ($opt) => $opt === $q->correct_answer)
                    ->first();
                $answers[(string) $qid] = $wrong;
            }
        }

        $startedAt   = Carbon::now()->subDays(rand(2, 5))->subMinutes(rand(20, 40));
        $submittedAt = $startedAt->copy()->addMinutes(rand(20, 40));
        $expiresAt   = $startedAt->copy()->addMinutes($course->exam_time_limit);

        $attempt = ExamAttempt::create([
            'enrollment_id' => $enrollment->id,
            'user_id'       => $enrollment->user_id,
            'course_id'     => $course->id,
            'started_at'    => $startedAt,
            'submitted_at'  => $submittedAt,
            'expires_at'    => $expiresAt,
            'status'        => 'submitted',
            'answers'       => $answers,
            'question_ids'  => $questionIds,
            'created_at'    => $startedAt,
            'updated_at'    => $submittedAt,
        ]);

        $correct         = $correctCount;
        $scorePercentage = round(($correct / $total) * 100, 2);
        $passed          = $scorePercentage >= $course->passing_score;

        ExamResult::create([
            'attempt_id'        => $attempt->id,
            'enrollment_id'     => $enrollment->id,
            'user_id'           => $enrollment->user_id,
            'course_id'         => $course->id,
            'total_questions'   => $total,
            'correct_answers'   => $correct,
            'score_percentage'  => $scorePercentage,
            'passed'            => $passed,
            'passing_threshold' => $course->passing_score,
            'created_at'        => $submittedAt,
            'updated_at'        => $submittedAt,
        ]);
        // No certificate — failed
    }

    private function seedCertificate(ExamResult $result, Enrollment $enrollment, Carbon $issueDate): void
    {
        // Skip if certificate already exists for this result
        if (SelfPacedCertificate::where('result_id', $result->id)->exists()) {
            return;
        }

        $year   = $issueDate->format('Y');
        $certNo = 'SP-CERT-' . $year . '-' . strtoupper(Str::random(8));
        $code   = strtoupper(Str::random(16));

        // Ensure uniqueness
        while (SelfPacedCertificate::where('certificate_number', $certNo)->exists()) {
            $certNo = 'SP-CERT-' . $year . '-' . strtoupper(Str::random(8));
        }
        while (SelfPacedCertificate::where('verification_code', $code)->exists()) {
            $code = strtoupper(Str::random(16));
        }

        SelfPacedCertificate::create([
            'user_id'            => $result->user_id,
            'course_id'          => $result->course_id,
            'enrollment_id'      => $enrollment->id,
            'result_id'          => $result->id,
            'certificate_number' => $certNo,
            'verification_code'  => $code,
            'issue_date'         => $issueDate->toDateString(),
            'is_revoked'         => false,
            'pdf_path'           => null,
            'verification_count' => 0,
            'generated_by'       => $result->user_id,
            'created_at'         => $issueDate,
            'updated_at'         => $issueDate,
        ]);
    }
}
