<?php

namespace App\Http\Controllers\Teacher;

use App\Http\Controllers\Concerns\RestrictsTeacherLessons;
use App\Http\Controllers\Controller;
use App\Models\Answer;
use App\Models\Exam;
use App\Models\ExamSession;
use App\Models\Grade;
use App\Models\Student;
use App\Support\AnswerEvaluator;
use App\Services\GradingService;
use Carbon\Carbon;
use Illuminate\Http\Request;

class ReportController extends Controller
{
    use RestrictsTeacherLessons;

    public function index(Request $request)
    {
        $query = $this->teacherExams()->with('lesson', 'classroom')->withCount('grades');

        if ($request->filled('lesson')) {
            $query->whereHas('lesson', function($q) use ($request) {
                $q->where('title', $request->lesson);
            });
        }
        
        if ($request->filled('classroom')) {
            $query->whereHas('classroom', function($q) use ($request) {
                $q->where('title', $request->classroom);
            });
        }
        
        if ($request->filled('status')) {
            $now = Carbon::now();
            if ($request->status === 'berlangsung') {
                $query->whereHas('sessions', function($q) use ($now) {
                    $q->where('start_time', '<=', $now)
                      ->where('end_time', '>=', $now);
                });
            } elseif ($request->status === 'selesai') {
                $query->where(function($q) use ($now) {
                    $q->doesntHave('sessions')
                      ->orWhereHas('sessions', function($sq) use ($now) {
                          $sq->where('start_time', '>', $now)
                            ->orWhere('end_time', '<', $now);
                      });
                });
            }
        }

        $exams = $query->paginate(15)->through(function ($exam) {
            $session = ExamSession::where('exam_id', $exam->id)->first();
            $status = 'selesai';

            if ($session && Carbon::now()->between($session->start_time, $session->end_time)) {
                $status = 'berlangsung';
            }

            $exam->status = $status;
            $exam->session = $session;

            return $exam;
        })->withQueryString();

        $allTeacherExams = $this->teacherExams()->with('lesson', 'classroom')->get();
        $uniqueLessons = $allTeacherExams->pluck('lesson.title')->filter()->unique()->values();
        $uniqueClassrooms = $allTeacherExams->pluck('classroom.title')->filter()->unique()->values();

        return inertia('Admin/Reports/Index', [
            'exams' => $exams,
            'uniqueLessons' => $uniqueLessons,
            'uniqueClassrooms' => $uniqueClassrooms,
            'filters' => $request->only(['lesson', 'classroom', 'status']),
            'grades' => [],
        ]);
    }

    public function show($id)
    {
        $exam = $this->teacherExams()->with('lesson', 'classroom')->findOrFail($id);
        $examSession = ExamSession::where('exam_id', $exam->id)->first();

        // For each student, pick the grade matching the session where they have answers
        $allGradesRaw = Grade::where('exam_id', $exam->id)->get();

        $studentSessions = Answer::where('exam_id', $exam->id)
            ->selectRaw('student_id, exam_session_id')
            ->groupBy('student_id', 'exam_session_id')
            ->pluck('exam_session_id', 'student_id');

        $relevantGradeIds = $allGradesRaw->filter(function ($grade) use ($studentSessions) {
            $answerSession = $studentSessions[$grade->student_id] ?? null;
            return $answerSession !== null && $grade->exam_session_id == $answerSession;
        })->pluck('id');

        if ($relevantGradeIds->isEmpty()) {
            $relevantGradeIds = $allGradesRaw->pluck('id');
        }

        $query = Grade::with('student', 'exam.classroom', 'exam.lesson', 'exam_session')
            ->whereIn('id', $relevantGradeIds);

        $allGrades = (clone $query)->get(['grade']);
        $totalCount = $allGrades->count();
        $avgGrade = $totalCount > 0 ? rtrim(rtrim(sprintf('%.1f', $allGrades->avg('grade')), '0'), '.') : '-';
        $highestGrade = $totalCount > 0 ? rtrim(rtrim(sprintf('%.1f', $allGrades->max('grade')), '0'), '.') : '-';
        $lowestGrade = $totalCount > 0 ? rtrim(rtrim(sprintf('%.1f', $allGrades->min('grade')), '0'), '.') : '-';

        $grades = $query->paginate(15)->withQueryString();

        $exam->status = $examSession && Carbon::now()->between($examSession->start_time, $examSession->end_time)
            ? 'berlangsung'
            : 'selesai';

        return inertia('Admin/Reports/Show', [
            'exam' => $exam,
            'grades' => $grades,
            'stats' => [
                'total' => $totalCount,
                'avg' => $avgGrade,
                'highest' => $highestGrade,
                'lowest' => $lowestGrade,
            ],
            'pendingPerStudent' => $this->getPendingPerStudent($exam->id, $grades->items()),
        ]);
    }

    public function analyze($id, $studentId)
    {
        $exam = $this->teacherExams()->with('lesson', 'classroom')->findOrFail($id);
        $student = Student::findOrFail($studentId);

        // Determine the student's exam_session_id from their answers
        $sessionId = Answer::where('exam_id', $id)
            ->where('student_id', $studentId)
            ->value('exam_session_id');

        $answers = GradingService::syncAutomaticAnswers($id, $studentId, $sessionId);
        GradingService::refreshGradeSummary($exam, $studentId, $sessionId, $answers);

        // get grade for this student's session
        $gradeQuery = Grade::where('exam_id', $id)
            ->where('student_id', $studentId);
        if ($sessionId !== null) {
            $gradeQuery->where('exam_session_id', $sessionId);
        }
        $grade = $gradeQuery->first();

        $pendingGrading = $answers->filter(function ($answer) {
            return in_array($answer->question->type ?? '', ['isian', 'uraian'])
                && $answer->is_graded !== 'Y';
        })->count();

        return inertia('Admin/Reports/Analyze', [
            'exam' => $exam,
            'student' => $student,
            'answers' => $answers,
            'questionWeights' => $exam->getWeights(),
            'pendingGrading' => $pendingGrading,
            'grade' => $grade,
        ]);
    }

    public function gradeAnswer(Request $request, $id)
    {
        $this->teacherExams()->findOrFail($id);

        $request->validate([
            'answer_id' => 'required|integer',
            'manual_score' => 'required|numeric|min:0|max:100',
        ]);

        $answer = Answer::where('id', $request->answer_id)
            ->where('exam_id', $id)
            ->firstOrFail();

        $answer->update([
            'manual_score' => $request->manual_score,
            'is_graded' => 'Y',
            'is_correct' => $request->manual_score >= 50 ? 'Y' : 'N',
        ]);

        // Auto-recalculate grade using the answer's session context
        $exam = Exam::findOrFail($id);
        GradingService::refreshGradeSummary($exam, $answer->student_id, $answer->exam_session_id);

        return back()->with('success', 'Skor berhasil disimpan.');
    }

    public function recalculateGrade($id, $studentId)
    {
        $exam = $this->teacherExams()->findOrFail($id);

        $answers = GradingService::syncAutomaticAnswers($id, $studentId, null, false);
        $summary = GradingService::calculateGradeSummary($exam, $answers);
        GradingService::refreshGradeSummary($exam, $studentId, null, $answers);

        return back()->with('success', 'Nilai berhasil dihitung ulang: ' . $summary['grade']);
    }

    private function getPendingPerStudent($examId, $grades)
    {
        $pendingMap = [];

        foreach ($grades as $grade) {
            $pendingMap[$grade->student_id] = Answer::with('question')
                ->where('exam_id', $examId)
                ->where('student_id', $grade->student_id)
                ->where('is_graded', 'N')
                ->get()
                ->filter(fn ($answer) => in_array($answer->question->type ?? '', ['isian', 'uraian']))
                ->count();
        }

        return $pendingMap;
    }

}
