<?php

namespace App\Http\Controllers\SelfPaced\Learner;

use App\Http\Controllers\Controller;
use App\Models\SelfPaced\Course;
use App\Models\SelfPaced\Enrollment;
use App\Models\SelfPaced\ExamAttempt;
use App\Models\SelfPaced\ExamQuestion;
use App\Services\ExamService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;

class ExamAttemptController extends Controller
{
    public function __construct(protected ExamService $examService)
    {
        //
    }

    // =========================================================================
    // PHASE 3 — Exam
    // =========================================================================

    /**
     * Show the exam confirmation screen (Phase 3 entry).
     * Validates: exam unlocked, not exhausted
     *
     * Requirement: 8.1, 6.2, 6.3
     */
    public function confirm(Course $course)
    {
        try {
            $enrollment = $this->getActiveEnrollment($course);

            // Validate exam is unlocked
            $this->examService->validateExamUnlocked($enrollment);

            // Check for an existing in-progress attempt (resume scenario)
            $activeAttempt = $enrollment->getActiveAttempt();

            if ($activeAttempt && !$activeAttempt->isExpired()) {
                // Resume directly into the exam
                return redirect()->route('self-paced.learn.exam.take', [$course, $activeAttempt]);
            }

            $remainingAttempts  = $enrollment->getRemainingAttempts();
            $progressPercentage = $enrollment->getProgressPercentage();
            $questionCount      = $course->examQuestions()->where('is_active', true)->count();

            return view('self-paced.learner.exam.confirm', compact(
                'course', 'enrollment', 'remainingAttempts', 'progressPercentage', 'questionCount'
            ));
        } catch (\RuntimeException $e) {
            return redirect()->route('self-paced.learn.overview', $course)
                ->with('error', $e->getMessage());
        } catch (\Throwable $e) {
            Log::error('Exam confirm error', ['exception' => $e, 'user' => auth()->id()]);
            return redirect()->route('self-paced.learn.overview', $course)
                ->with('error', 'Something went wrong. Please try again or contact support.');
        }
    }

    /**
     * Start a new exam attempt.
     * Validates: exam unlocked, not exhausted, remaining attempts > 0
     *
     * Requirement: 8.2, 6.2, 6.3, 18.6
     */
    public function start(Request $request, Course $course)
    {
        try {
            $enrollment = $this->getActiveEnrollment($course);

            // Validate exam is unlocked (all topics complete)
            $this->examService->validateExamUnlocked($enrollment);

            // Validate exam not exhausted
            if ($enrollment->isExamExhausted()) {
                return redirect()->route('self-paced.learn.exam.confirm', $course)
                    ->with('error', 'You have exhausted your exam attempts. Contact support to purchase a re-sit.');
            }

            $attempt = $this->examService->createAttempt($enrollment);
            return redirect()->route('self-paced.learn.exam.take', [$course, $attempt]);
        } catch (\RuntimeException $e) {
            return redirect()->route('self-paced.learn.exam.confirm', $course)
                ->with('error', $e->getMessage());
        } catch (\Throwable $e) {
            Log::error('Exam start error', ['exception' => $e, 'user' => auth()->id()]);
            return redirect()->route('self-paced.learn.overview', $course)
                ->with('error', 'Something went wrong. Please try again or contact support.');
        }
    }

    /**
     * Show the exam question view (one question at a time).
     * Requirement 8.3, 8.4, 8.6, 8.7, 8.8
     */
    public function take(Course $course, ExamAttempt $attempt)
    {
        try {
            $enrollment = $this->getActiveEnrollment($course);
            abort_unless($attempt->enrollment_id === $enrollment->id, 403, 'You do not have access to this exam.');
            abort_if($attempt->user_id !== auth()->id(), 403, 'You do not have access to this exam.');

            // Server-side expiry check — auto-submit if expired
            if ($attempt->isExpired() && $attempt->isInProgress()) {
                $result = $this->examService->submitAttempt($attempt, 'timed_out');
                return redirect()->route('self-paced.learn.results', [$course, $result])
                    ->with('warning', 'Your exam time expired and was automatically submitted.');
            }

            // If already submitted, redirect to results
            if ($attempt->isSubmitted()) {
                $result = $attempt->result;
                if ($result) {
                    return redirect()->route('self-paced.learn.results', [$course, $result]);
                }
            }

            $questionIds = $attempt->question_ids ?? [];
            $answers     = $attempt->answers ?? [];

            // Determine current question index (resume from last answered)
            $lastIndex    = $attempt->getLastAnsweredIndex();
            $currentIndex = max(0, $lastIndex);
            $currentIndex = min($currentIndex, count($questionIds) - 1);

            $currentQuestionId = $questionIds[$currentIndex] ?? null;
            $currentQuestion   = $currentQuestionId
                ? ExamQuestion::find($currentQuestionId)
                : null;

            $remainingSeconds   = $attempt->getRemainingSeconds();
            $progressPercentage = $enrollment->getProgressPercentage();
            $totalQuestions     = count($questionIds);
            $answeredCount      = count($answers);
            $topicGroups        = $attempt->topic_groups ?? [];

            return view('self-paced.learner.exam.take', compact(
                'course', 'enrollment', 'attempt',
                'currentQuestion', 'currentIndex', 'totalQuestions',
                'answeredCount', 'remainingSeconds', 'progressPercentage',
                'questionIds', 'answers', 'topicGroups'
            ));
        } catch (\RuntimeException $e) {
            return redirect()->route('self-paced.learn.exam.confirm', $course)
                ->with('error', $e->getMessage());
        } catch (\Throwable $e) {
            Log::error('Exam take error', ['exception' => $e, 'user' => auth()->id()]);
            return redirect()->route('self-paced.learn.overview', $course)
                ->with('error', 'Something went wrong. Please try again or contact support.');
        }
    }

    /**
     * Save a single answer (AJAX POST — idempotent).
     * Requirement 8.6, Property 9
     */
    public function saveAnswer(Request $request, Course $course, ExamAttempt $attempt)
    {
        try {
            $enrollment = $this->getActiveEnrollment($course);
            abort_if($attempt->user_id !== auth()->id(), 403, 'You do not have access to this exam.');
            abort_unless($attempt->enrollment_id === $enrollment->id, 403, 'You do not have access to this exam.');

            $request->validate([
                'question_id'     => 'required|integer',
                'selected_option' => ['required', 'string', 'regex:/^[A-Da-d](,[A-Da-d])*$/'],
            ]);

            $attempt = $this->examService->saveAnswer(
                $attempt,
                (int) $request->input('question_id'),
                $request->input('selected_option')
            );

            return response()->json([
                'success'           => true,
                'remaining_seconds' => $attempt->getRemainingSeconds(),
                'answered_count'    => count($attempt->answers ?? []),
            ]);
        } catch (\RuntimeException $e) {
            return response()->json(['error' => $e->getMessage()], 422);
        } catch (\Throwable $e) {
            Log::error('Exam answer save error', ['exception' => $e, 'user' => auth()->id()]);
            return response()->json(['error' => 'An error occurred. Please refresh and try again.'], 500);
        }
    }

    /**
     * Submit the exam attempt (manual or auto on timer expiry).
     * Requirement 8.5, 8.9
     */
    public function submit(Request $request, Course $course, ExamAttempt $attempt)
    {
        try {
            $enrollment = $this->getActiveEnrollment($course);
            abort_if($attempt->user_id !== auth()->id(), 403, 'You do not have access to this exam.');
            abort_unless($attempt->enrollment_id === $enrollment->id, 403, 'You do not have access to this exam.');

            $submissionType = $attempt->isExpired() ? 'timed_out' : 'submitted';
            $result = $this->examService->submitAttempt($attempt, $submissionType);

            if ($request->ajax()) {
                return response()->json([
                    'success'      => true,
                    'redirect_url' => route('self-paced.learn.results', [$course, $result]),
                ]);
            }

            return redirect()->route('self-paced.learn.results', [$course, $result]);
        } catch (\RuntimeException $e) {
            if ($request->ajax()) {
                return response()->json(['error' => $e->getMessage()], 422);
            }
            return redirect()->route('self-paced.learn.exam.confirm', $course)
                ->with('error', $e->getMessage());
        } catch (\Throwable $e) {
            Log::error('Exam submit error', ['exception' => $e, 'user' => auth()->id()]);
            if ($request->ajax()) {
                return response()->json(['error' => 'An error occurred. Please refresh and try again.'], 500);
            }
            return redirect()->route('self-paced.learn.overview', $course)
                ->with('error', 'Something went wrong. Please try again or contact support.');
        }
    }

    /**
     * Navigate to a specific question by index (AJAX GET).
     * Requirement 8.3
     */
    public function question(Course $course, ExamAttempt $attempt, int $index)
    {
        try {
            $enrollment = $this->getActiveEnrollment($course);
            abort_if($attempt->user_id !== auth()->id(), 403, 'You do not have access to this exam.');
            abort_unless($attempt->enrollment_id === $enrollment->id, 403, 'You do not have access to this exam.');

            $questionIds = $attempt->question_ids ?? [];
            $questionId  = $questionIds[$index] ?? null;

            if (!$questionId) {
                return response()->json(['error' => 'Question not found.'], 404);
            }

            $question         = ExamQuestion::findOrFail($questionId);
            $savedAnswer      = $attempt->getAnswerFor((int) $questionId);
            $remainingSeconds = $attempt->getRemainingSeconds();

            return response()->json([
                'success'             => true,
                'index'               => $index,
                'total'               => count($questionIds),
                'question_id'         => $question->id,
                'question_text'       => $question->question_text,
                'question_text_html'  => $question->question_text_html,
                'option_a'            => $question->option_a,
                'option_b'            => $question->option_b,
                'option_c'            => $question->option_c,
                'option_d'            => $question->option_d,
                'allow_multiple'      => (bool) $question->allow_multiple_answers,
                'saved_answer'        => $savedAnswer,
                'remaining_seconds'   => $remainingSeconds,
                'question_media_type' => $question->question_media_type,
                'question_media_url'  => $question->question_media_path
                    ? \Illuminate\Support\Facades\Storage::url($question->question_media_path)
                    : null,
                'question_media_name' => $question->question_media_name,
                'upload_required'     => (bool) $question->upload_required,
                'upload_label'        => $question->upload_label,
            ]);
        } catch (\Throwable $e) {
            Log::error('Exam question fetch error', ['exception' => $e, 'user' => auth()->id()]);
            return response()->json(['error' => 'An error occurred. Please refresh and try again.'], 500);
        }
    }

    // =========================================================================
    // HELPERS
    // =========================================================================

    protected function getActiveEnrollment(Course $course): Enrollment
    {
        $enrollment = Enrollment::where('user_id', Auth::id())
            ->where('course_id', $course->id)
            ->whereIn('status', ['active', 'completed'])
            ->first();

        if (!$enrollment) {
            abort(403, 'You are not enrolled in this course or your enrollment is not active.');
        }

        return $enrollment;
    }
}
