<?php

namespace App\Services;

use App\Models\Mark;
use App\Models\Exam;
use App\Models\Student;
use App\Models\Stream;
use Illuminate\Support\Collection;

class GradingService
{
    public function saveMarks(array $marksData, int $examId, int $subjectId, int $enteredBy): int
    {
        $saved = 0;
        foreach ($marksData as $studentId => $score) {
            if ($score === '' || $score === null) continue;

            $score = (float) $score;
            $percentage = $score; // assuming out_of=100 by default
            $gradeData = Mark::computeGrade($percentage);

            Mark::updateOrCreate(
                ['student_id' => $studentId, 'exam_id' => $examId, 'subject_id' => $subjectId],
                array_merge($gradeData, ['score' => $score, 'entered_by' => $enteredBy])
            );
            $saved++;
        }
        return $saved;
    }

    public function getStreamResults(int $streamId, int $examId): Collection
    {
        return Mark::with(['student.user', 'subject'])
            ->whereHas('student', fn($q) => $q->where('stream_id', $streamId))
            ->where('exam_id', $examId)
            ->get()
            ->groupBy('student_id')
            ->map(function ($marks, $studentId) {
                $student = $marks->first()->student;
                $totalPoints = $marks->sum('points');
                $subjectCount = $marks->count();
                $meanGrade = $subjectCount > 0 ? $totalPoints / $subjectCount : 0;

                return [
                    'student'       => $student,
                    'marks'         => $marks->keyBy('subject_id'),
                    'total_points'  => $totalPoints,
                    'mean_grade'    => $this->pointsToGrade($meanGrade),
                    'subject_count' => $subjectCount,
                ];
            })
            ->sortByDesc('total_points')
            ->values()
            ->map(function ($item, $index) {
                $item['position'] = $index + 1;
                return $item;
            });
    }

    public function pointsToGrade(float $points): string
    {
        return match(true) {
            $points >= 11.5 => 'A',
            $points >= 10.5 => 'A-',
            $points >= 9.5  => 'B+',
            $points >= 8.5  => 'B',
            $points >= 7.5  => 'B-',
            $points >= 6.5  => 'C+',
            $points >= 5.5  => 'C',
            $points >= 4.5  => 'C-',
            $points >= 3.5  => 'D+',
            $points >= 2.5  => 'D',
            $points >= 1.5  => 'D-',
            default         => 'E',
        };
    }
}
