<?php

namespace App\Http\Controllers\Student;

use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Inertia\Response;

class ExamController extends Controller
{
    public function index(Request $request): Response
    {
        $schoolId = $this->currentSchoolId($request);
        $userId = $request->user()?->id;
        $studentId = $userId && $schoolId
            ? DB::table('students')->where('school_id', $schoolId)->where('user_id', $userId)->value('id')
            : null;

        $classroomIds = $studentId
            ? DB::table('class_students')
                ->where('school_id', $schoolId)
                ->where('student_id', $studentId)
                ->where('status', 'active')
                ->pluck('classroom_id')
            : collect();

        $exams = ($schoolId && $classroomIds->isNotEmpty())
            ? DB::table('exams')
                ->leftJoin('classrooms', 'classrooms.id', '=', 'exams.classroom_id')
                ->leftJoin('subjects', 'subjects.id', '=', 'exams.subject_id')
                ->leftJoin('exam_sessions', function ($join) use ($studentId): void {
                    $join->on('exam_sessions.exam_id', '=', 'exams.id')
                         ->where('exam_sessions.student_id', '=', $studentId);
                })
                ->whereIn('exams.classroom_id', $classroomIds)
                ->where('exams.school_id', $schoolId)
                ->where('exams.status', 'published')
                ->select([
                    'exams.id',
                    'exams.title',
                    'exams.type',
                    'exams.starts_at',
                    'exams.ends_at',
                    'exams.duration_minutes',
                    'exams.max_score',
                    'classrooms.name as classroom_name',
                    'subjects.name as subject_name',
                    'exam_sessions.id as session_id',
                    'exam_sessions.status as session_status',
                    'exam_sessions.score as session_score',
                    'exam_sessions.submitted_at',
                ])
                ->orderByDesc('exams.starts_at')
                ->limit(30)
                ->get()
                ->map(fn ($exam): array => [
                    'id' => (int) $exam->id,
                    'title' => $exam->title,
                    'type' => $exam->type,
                    'startsAt' => $exam->starts_at ? $this->jalaliDate($exam->starts_at, true) : '—',
                    'endsAt' => $exam->ends_at ? $this->jalaliDate($exam->ends_at, true) : '—',
                    'durationMinutes' => $exam->duration_minutes,
                    'maxScore' => (float) $exam->max_score,
                    'classroom' => $exam->classroom_name ?: '—',
                    'subject' => $exam->subject_name ?: '—',
                    'sessionId' => $exam->session_id ? (int) $exam->session_id : null,
                    'sessionStatus' => $exam->session_status,
                    'sessionScore' => $exam->session_score !== null ? (float) $exam->session_score : null,
                    'submittedAt' => $exam->submitted_at ? $this->jalaliDate($exam->submitted_at, true) : null,
                    'isAvailable' => $this->isExamAvailable($exam),
                ])
                ->values()
            : collect()->values();

        return Inertia::render('Student/Exams', [
            'exams' => $exams,
        ]);
    }

    public function show(Request $request, int $id): Response|RedirectResponse
    {
        $schoolId = $this->currentSchoolId($request);
        $userId = $request->user()?->id;
        $studentId = $userId && $schoolId
            ? DB::table('students')->where('school_id', $schoolId)->where('user_id', $userId)->value('id')
            : null;

        abort_unless($studentId, 403);

        $exam = DB::table('exams')
            ->where('school_id', $schoolId)
            ->where('id', $id)
            ->where('status', 'published')
            ->first();

        abort_unless($exam, 404);

        $inClass = DB::table('class_students')
            ->where('school_id', $schoolId)
            ->where('student_id', $studentId)
            ->where('classroom_id', $exam->classroom_id)
            ->where('status', 'active')
            ->exists();

        abort_unless($inClass, 403, 'شما در این کلاس نیستید.');

        if (! $this->isExamAvailable($exam)) {
            return redirect()->route('student.exams')->withErrors(['exam' => 'این امتحان در حال حاضر در دسترس نیست.']);
        }

        $session = DB::table('exam_sessions')
            ->where('exam_id', $id)
            ->where('student_id', $studentId)
            ->first();

        if ($session && $session->status !== 'started') {
            return redirect()->route('student.exams')->withErrors(['exam' => 'قبلاً در این امتحان شرکت کرده‌اید.']);
        }

        if (! $session) {
            $sessionId = DB::table('exam_sessions')->insertGetId([
                'school_id' => $schoolId,
                'exam_id' => $id,
                'student_id' => $studentId,
                'started_at' => now(),
                'status' => 'started',
                'ip_address' => $request->ip(),
                'user_agent' => $request->userAgent(),
                'created_at' => now(),
                'updated_at' => now(),
            ]);
            $session = DB::table('exam_sessions')->find($sessionId);
        }

        $questions = DB::table('exam_questions')
            ->where('exam_id', $id)
            ->where('school_id', $schoolId)
            ->orderBy('sort_order')
            ->get(['id', 'question_type', 'body', 'score', 'sort_order'])
            ->map(function ($q) use ($session): array {
                $options = [];
                if ($q->question_type === 'test') {
                    $options = DB::table('exam_options')
                        ->where('question_id', $q->id)
                        ->orderBy('sort_order')
                        ->get(['id', 'body'])
                        ->map(fn ($o): array => ['id' => (int) $o->id, 'body' => $o->body])
                        ->values()
                        ->all();
                }

                $savedAnswer = DB::table('exam_answers')
                    ->where('exam_session_id', $session->id)
                    ->where('question_id', $q->id)
                    ->first(['option_id', 'answer_text']);

                return [
                    'id' => (int) $q->id,
                    'type' => $q->question_type,
                    'body' => $q->body,
                    'score' => (float) $q->score,
                    'options' => $options,
                    'savedOptionId' => $savedAnswer?->option_id ? (int) $savedAnswer->option_id : null,
                    'savedText' => $savedAnswer?->answer_text,
                ];
            })
            ->values();

        $elapsedSeconds = $session->started_at ? now()->diffInSeconds($session->started_at) : 0;
        $remainingSeconds = $exam->duration_minutes
            ? max(0, ($exam->duration_minutes * 60) - $elapsedSeconds)
            : null;

        return Inertia::render('Exams/TakeExam', [
            'exam' => [
                'id' => (int) $exam->id,
                'title' => $exam->title,
                'maxScore' => (float) $exam->max_score,
                'durationMinutes' => $exam->duration_minutes,
            ],
            'sessionId' => (int) $session->id,
            'questions' => $questions,
            'remainingSeconds' => $remainingSeconds,
        ]);
    }

    public function saveAnswer(Request $request, int $id): \Illuminate\Http\JsonResponse
    {
        $schoolId = $this->currentSchoolId($request);
        $userId = $request->user()?->id;
        $studentId = $userId && $schoolId
            ? DB::table('students')->where('school_id', $schoolId)->where('user_id', $userId)->value('id')
            : null;

        abort_unless($studentId, 403);

        $data = $request->validate([
            'session_id' => 'required|integer',
            'question_id' => 'required|integer',
            'option_id' => 'nullable|integer',
            'answer_text' => 'nullable|string|max:5000',
        ]);

        $session = DB::table('exam_sessions')
            ->where('id', $data['session_id'])
            ->where('exam_id', $id)
            ->where('student_id', $studentId)
            ->where('status', 'started')
            ->first();

        abort_unless($session, 404);

        DB::table('exam_answers')->updateOrInsert(
            ['exam_session_id' => $session->id, 'question_id' => $data['question_id']],
            [
                'school_id' => $schoolId,
                'option_id' => $data['option_id'] ?? null,
                'answer_text' => $data['answer_text'] ?? null,
                'created_at' => now(),
                'updated_at' => now(),
            ]
        );

        return response()->json(['ok' => true]);
    }

    public function submit(Request $request, int $id): RedirectResponse
    {
        $schoolId = $this->currentSchoolId($request);
        $userId = $request->user()?->id;
        $studentId = $userId && $schoolId
            ? DB::table('students')->where('school_id', $schoolId)->where('user_id', $userId)->value('id')
            : null;

        abort_unless($studentId, 403);

        $data = $request->validate(['session_id' => 'required|integer']);

        $session = DB::table('exam_sessions')
            ->where('id', $data['session_id'])
            ->where('exam_id', $id)
            ->where('student_id', $studentId)
            ->where('status', 'started')
            ->first();

        abort_unless($session, 404);

        $mcqScore = $this->autoGradeMcq((int) $session->id, (int) $schoolId, $id);

        DB::table('exam_sessions')
            ->where('id', $session->id)
            ->update([
                'status' => 'submitted',
                'submitted_at' => now(),
                'score' => $mcqScore,
                'updated_at' => now(),
            ]);

        return redirect()->route('student.exams')->with('success', 'امتحان با موفقیت ارسال شد.');
    }

    private function autoGradeMcq(int $sessionId, int $schoolId, int $examId): float
    {
        $questions = DB::table('exam_questions')
            ->where('exam_id', $examId)
            ->where('question_type', 'test')
            ->get(['id', 'score']);

        $total = 0.0;
        foreach ($questions as $q) {
            $answer = DB::table('exam_answers')
                ->where('exam_session_id', $sessionId)
                ->where('question_id', $q->id)
                ->first(['option_id']);

            if ($answer?->option_id) {
                $isCorrect = DB::table('exam_options')
                    ->where('id', $answer->option_id)
                    ->where('is_correct', true)
                    ->exists();

                if ($isCorrect) {
                    $total += (float) $q->score;

                    DB::table('exam_answers')
                        ->where('exam_session_id', $sessionId)
                        ->where('question_id', $q->id)
                        ->update(['score' => $q->score]);
                }
            }
        }

        return round($total, 2);
    }

    private function isExamAvailable(object $exam): bool
    {
        $now = now();
        if ($exam->starts_at && $now->lt($exam->starts_at)) {
            return false;
        }
        if ($exam->ends_at && $now->gt($exam->ends_at)) {
            return false;
        }

        return true;
    }
}
