<?php

namespace App\Services\Scores;

use App\Models\GradingLock;
use App\Models\MissingScoreOverride;
use App\Models\Participation;
use App\Models\Student;
use App\Models\StudentClass;

class ParticipationScoreService
{
    public function __construct(private ScoreTermService $term)
    {
    }

    public function list(int $classSectionId, ?string $semester, ?string $schoolYear): array
    {
        $semester = $this->term->semesterLabel($semester);
        $schoolYear = $this->term->schoolYear($schoolYear);

        $studentIds = StudentClass::query()
            ->where('class_section_id', $classSectionId)
            ->where('school_year', $schoolYear)
            ->pluck('student_id')
            ->map(fn ($v) => (int) $v)
            ->all();

        $students = Student::query()
            ->whereIn('id', $studentIds)
            ->where('is_active', 1)
            ->orderBy('lastname')
            ->orderBy('firstname')
            ->get()
            ->map(fn ($row) => [
                'student_id' => (int) $row->id,
                'school_id' => $row->school_id,
                'firstname' => (string) $row->firstname,
                'lastname' => (string) $row->lastname,
                'scores' => [],
            ])
            ->all();

        $scoresRows = Participation::query()
            ->select('student_id', 'score')
            ->where('class_section_id', $classSectionId)
            ->where('semester', $semester)
            ->where('school_year', $schoolYear)
            ->get();

        $scoreMap = [];
        foreach ($scoresRows as $row) {
            $score = $row->score;
            $scoreMap[(int) $row->student_id] = is_numeric($score) ? (float) $score : $score;
        }

        foreach ($students as &$student) {
            $score = $scoreMap[$student['student_id']] ?? '';
            $student['scores'] = [
                'score' => $score,
            ];
        }
        unset($student);

        return [
            'students' => $students,
            'semester' => $semester,
            'schoolYear' => $schoolYear,
            'scoresLocked' => GradingLock::isLocked($classSectionId, $semester, $schoolYear),
            'missingOkMap' => MissingScoreOverride::getOverridesMap($classSectionId, $semester, $schoolYear, 'participation'),
        ];
    }

    public function update(int $classSectionId, string $semester, string $schoolYear, array $scores, array $missingOk, int $updatedBy): int
    {
        if (GradingLock::isLocked($classSectionId, $semester, $schoolYear)) {
            throw new \RuntimeException('Scores are locked for this class.');
        }

        $studentIds = array_keys($scores);
        $checkedItems = [];
        foreach ($missingOk as $studentId => $flags) {
            $checkedItems[] = [
                'student_id' => (int) $studentId,
                'item_index' => null,
            ];
        }

        MissingScoreOverride::replaceOverrides(
            $classSectionId,
            $semester,
            $schoolYear,
            'participation',
            $studentIds,
            null,
            $checkedItems,
            $updatedBy,
            true
        );

        $count = 0;
        foreach ($scores as $studentId => $data) {
            if (!is_numeric($studentId)) {
                continue;
            }
            if (!is_array($data)) {
                $data = ['score' => $data];
            }

            $student = Student::query()->find((int) $studentId);
            if (!$student) {
                continue;
            }

            $rawScore = $data['score'] ?? null;
            $isBlank = $rawScore === null || (is_string($rawScore) && trim($rawScore) === '');
            $normalizedScore = (!$isBlank && is_numeric($rawScore)) ? (float) $rawScore : null;

            $existing = Participation::query()
                ->where('student_id', $studentId)
                ->where('class_section_id', $classSectionId)
                ->where('semester', $semester)
                ->where('school_year', $schoolYear)
                ->first();

            $payload = [
                'student_id' => (int) $studentId,
                'school_id' => $student->school_id,
                'class_section_id' => $classSectionId,
                'updated_by' => $updatedBy,
                'score' => $normalizedScore,
                'semester' => $semester,
                'school_year' => $schoolYear,
                'updated_at' => now(),
            ];

            if ($existing) {
                $existing->update($payload);
            } else {
                $payload['created_at'] = now();
                Participation::query()->create($payload);
            }
            $count++;
        }

        return $count;
    }
}
