<?php

namespace App\Http\Controllers\Admin;

use Carbon\Carbon;
use App\Models\Exam;
use App\Models\Grade;
use App\Models\Student;
use App\Models\Answer;
use App\Models\ExamSession;
use Illuminate\Http\Request;
use App\Exports\GradesExport;
use App\Support\AnswerEvaluator;
use App\Services\GradingService;
use App\Http\Controllers\Controller;
use Maatwebsite\Excel\Facades\Excel;

class ReportController extends Controller
{    
    /**
     * index
     *
     * @return void
     */
    public function index(Request $request)
    {
        $query = Exam::with('lesson', 'classroom', 'sessions')->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 = $exam->sessions->first();
            $status = 'selesai';
            if ($session) {
                $now = Carbon::now();
                if ($now->between($session->start_time, $session->end_time)) {
                    $status = 'berlangsung';
                }
            }
            $exam->status = $status;
            $exam->session = $session;
            return $exam;
        })->withQueryString();

        $uniqueLessons = \App\Models\Lesson::pluck('title')->unique()->values();
        $uniqueClassrooms = \App\Models\Classroom::pluck('title')->unique()->values();

        return inertia('Admin/Reports/Index', [
            'exams'  => $exams,
            'uniqueLessons' => $uniqueLessons,
            'uniqueClassrooms' => $uniqueClassrooms,
            'filters' => $request->only(['lesson', 'classroom', 'status']),
            'grades' => [],
        ]);
    }
    
    /**
     * filter
     *
     * @param  mixed $request
     * @return void
     */
    public function filter(Request $request)
    {
        $request->validate([
            'exam_id' => 'required',
        ]);

        // Get all exams with lesson, classroom, and count grades
        $exams = Exam::with('lesson', 'classroom', 'sessions')
            ->withCount('grades')
            ->get()
            ->map(function ($exam) {
                $session = $exam->sessions->first();
                $status = 'selesai';
                if ($session) {
                    $now = Carbon::now();
                    if ($now->between($session->start_time, $session->end_time)) {
                        $status = 'berlangsung';
                    }
                }
                $exam->status = $status;
                $exam->session = $session;
                return $exam;
            });

        // Get exam
        $exam = Exam::with('lesson', 'classroom')
                ->where('id', $request->exam_id)
                ->first();

        if ($exam) {
            // Get exam session
            $exam_session = ExamSession::where('exam_id', $exam->id)->first();

            // Get grades / nilai
            $grades = Grade::with('student', 'exam.classroom', 'exam.lesson', 'exam_session')
                    ->where('exam_id', $exam->id)
                    ->where('exam_session_id', $exam_session->id)        
                    ->get();
        } else {
            $grades = [];
        }        
        
        return inertia('Admin/Reports/Index', [
            'exams'  => $exams,
            'grades' => $grades,
        ]);
        
    }

    /**
     * show
     *
     * @param  mixed $id
     * @return void
     */
    public function show($id)
    {
        // Get exam
        $exam = Exam::with('lesson', 'classroom')
                ->where('id', $id)
                ->firstOrFail();

        // Get exam session (for status display only)
        $exam_session = 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();

        // Get the session_id where each student actually has answers
        $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) {
            // Pick the grade whose session matches where the student has answers
            $answerSession = $studentSessions[$grade->student_id] ?? null;
            return $answerSession !== null && $grade->exam_session_id == $answerSession;
        })->pluck('id');

        // Fallback: if no answers found, show all grades (shouldn't happen normally)
        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();

        $status = 'selesai';
        if ($exam_session) {
            $now = Carbon::now();
            if ($now->between($exam_session->start_time, $exam_session->end_time)) {
                $status = 'berlangsung';
            }
        }
        $exam->status = $status;
        
        return inertia('Admin/Reports/Show', [
            'exam'  => $exam,
            'grades' => $grades,
            'stats' => [
                'total' => $totalCount,
                'avg' => $avgGrade,
                'highest' => $highestGrade,
                'lowest' => $lowestGrade,
            ],
            'pendingPerStudent' => $this->getPendingPerStudent($id, $grades->items()),
        ]);
    }

    /**
     * analyze
     *
     * @param  mixed $id
     * @param  mixed $student_id
     * @return void
     */
    public function analyze($id, $student_id)
    {
        $exam = Exam::with('lesson', 'classroom')->findOrFail($id);
        $student = Student::findOrFail($student_id);

        // Determine the student's exam_session_id from their answers
        $sessionId = Answer::where('exam_id', $id)
            ->where('student_id', $student_id)
            ->value('exam_session_id');
        
        // get student answers for this exam + session
        $answers = GradingService::syncAutomaticAnswers($id, $student_id, $sessionId);
        GradingService::refreshGradeSummary($exam, $student_id, $sessionId, $answers);

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

        // get question weights
        $questionWeights = $exam->getWeights();

        // count pending grading (isian/uraian that haven't been manually graded)
        $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' => $questionWeights,
            'pendingGrading' => $pendingGrading,
            'grade' => $grade,
        ]);
    }

    /**
     * gradeAnswer - Manual grading for isian/uraian
     *
     * @param  Request $request
     * @param  mixed $id  exam id
     * @return \Illuminate\Http\RedirectResponse
     */
    public function gradeAnswer(Request $request, $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();

        // Determine is_correct based on manual_score (>= 50 = Y)
        $isCorrect = $request->manual_score >= 50 ? 'Y' : 'N';

        $answer->update([
            'manual_score' => $request->manual_score,
            'is_graded' => 'Y',
            'is_correct' => $isCorrect,
        ]);

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

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

    /**
     * recalculateGrade - Recalculate weighted grade after manual grading
     *
     * @param  mixed $id  exam id
     * @param  mixed $student_id
     * @return \Illuminate\Http\RedirectResponse
     */
    public function recalculateGrade($id, $student_id)
    {
        $exam = Exam::findOrFail($id);
        
        // get all answers for this student
        $answers = GradingService::syncAutomaticAnswers($id, $student_id, null, false);

        $summary = GradingService::calculateGradeSummary($exam, $answers);
        GradingService::refreshGradeSummary($exam, $student_id, null, $answers);

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

    /**
     * export
     *
     * @param  mixed $request
     * @return void
     */
    public function export(Request $request)
    {
        // Get exam
        $exam = Exam::with('lesson', 'classroom')
                ->where('id', $request->exam_id)
                ->firstOrFail();

        // Get exam session
        $exam_session = ExamSession::where('exam_id', $exam->id)->first();

        // Get grades / nilai
        if ($exam_session) {
            $grades = Grade::with('student', 'exam.classroom', 'exam.lesson', 'exam_session')
                    ->where('exam_id', $exam->id)
                    ->where('exam_session_id', $exam_session->id)        
                    ->get();
        } else {
            $grades = Grade::with('student', 'exam.classroom', 'exam.lesson', 'exam_session')
                    ->where('exam_id', $exam->id)
                    ->get();
        }

        $filename = 'Laporan ' . $exam->title . ' - ' . ($exam->lesson->title ?? 'Unknown') . ' - ' . Carbon::now()->format('Y-m-d H-i') . '.xlsx';

        return Excel::download(new GradesExport($grades, $exam), $filename);
    }

    /**
     * Get count of pending grading per student
     *
     * @param  int $examId
     * @param  mixed $grades
     * @return array
     */
    private function getPendingPerStudent($examId, $grades)
    {
        $pendingMap = [];

        if (!is_array($grades) && !($grades instanceof \Illuminate\Support\Collection)) {
            return $pendingMap;
        }

        $studentIds = [];
        foreach ($grades as $grade) {
            $studentIds[] = $grade->student_id;
            $pendingMap[$grade->student_id] = 0;
        }

        if (empty($studentIds)) {
            return $pendingMap;
        }

        $pendingAnswers = Answer::with('question')
            ->where('exam_id', $examId)
            ->whereIn('student_id', $studentIds)
            ->where('is_graded', 'N')
            ->get();

        foreach ($pendingAnswers as $answer) {
            if (in_array($answer->question->type ?? '', ['isian', 'uraian'])) {
                $pendingMap[$answer->student_id]++;
            }
        }

        return $pendingMap;
    }

}
