<?php

namespace App\Services\Parents;

use App\Models\AttendanceData;
use App\Models\AttendanceRecord;
use App\Models\EarlyDismissalSignature;
use App\Models\ParentAttendanceReport;
use App\Models\Student;
use App\Models\ClassSection;
use App\Services\SemesterRangeService;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;

class ParentAttendanceReportService
{
    public function __construct(
        private ParentConfigService $configService,
        private ParentAttendanceReportCalendarService $calendarService,
        private SemesterRangeService $semesterRangeService
    ) {
    }

    public function formData(int $parentId): array
    {
        $context = $this->configService->context();
        $students = Student::query()
            ->where('parent_id', $parentId)
            ->orderBy('firstname')
            ->orderBy('lastname')
            ->get()
            ->toArray();

        [$sundays, $defaultDate] = $this->calendarService->computeSundays();

        $today = now()->toDateString();
        $schoolYear = (string) ($context['school_year'] ?? '');
        $previewRows = DB::table('parent_attendance_reports as par')
            ->select('par.*', 's.firstname', 's.lastname')
            ->leftJoin('students as s', 's.id', '=', 'par.student_id')
            ->where('par.parent_id', $parentId)
            ->where('par.school_year', $schoolYear)
            ->where('par.report_date', '>=', $today)
            ->orderBy('par.report_date')
            ->orderBy('s.firstname')
            ->orderBy('s.lastname')
            ->get()
            ->map(fn ($row) => (array) $row)
            ->all();

        $cutoffThreshold = $this->calendarService->normalizeCutoffTime(
            (string) ($context['parent_report_cutoff'] ?? ''),
            '09:00'
        );

        return [
            'students' => $students,
            'today' => $today,
            'sundays' => $sundays,
            'defaultDate' => $defaultDate,
            'myReports' => $previewRows,
            'cutoffThreshold' => $cutoffThreshold,
        ];
    }

    public function submit(int $parentId, array $payload): array
    {
        $context = $this->configService->context();
        $schoolYear = (string) ($context['school_year'] ?? '');
        $semester = (string) ($context['semester'] ?? '');

        $studentIds = array_values(array_filter(array_map('intval', (array) ($payload['student_ids'] ?? []))));
        if (empty($studentIds)) {
            throw new \RuntimeException('At least select one student.');
        }

        $datesInput = $payload['dates'] ?? ($payload['date'] ?? null);
        $rawDates = [];
        if (is_array($datesInput)) {
            $rawDates = $datesInput;
        } elseif ($datesInput !== null) {
            $rawDates = [$datesInput];
        }
        $rawDates = array_values(array_unique(array_filter(array_map(static function ($val) {
            return substr((string) $val, 0, 10);
        }, $rawDates))));

        if (empty($rawDates)) {
            throw new \RuntimeException('Please select at least one Sunday date.');
        }

        $type = (string) ($payload['type'] ?? '');
        if (!in_array($type, ['absent', 'late', 'early_dismissal'], true)) {
            throw new \RuntimeException('Invalid report type.');
        }

        $arrivalTime = $payload['arrival_time'] ?? null;
        $dismissTime = $payload['dismiss_time'] ?? null;
        $reason = isset($payload['reason']) ? trim((string) $payload['reason']) : null;

        $todayCheck = new \DateTime('today');
        $cap = $this->calendarService->firstSundayOfJune($schoolYear);
        $validDates = [];

        foreach ($rawDates as $entry) {
            $dt = \DateTime::createFromFormat('Y-m-d', $entry);
            if (!$dt) {
                throw new \RuntimeException('Invalid date selected: ' . $entry);
            }
            if ((int) $dt->format('w') !== 0) {
                throw new \RuntimeException('Please select Sunday dates only.');
            }
            if ($dt < $todayCheck) {
                throw new \RuntimeException('Past dates are not allowed. Please select today or a future Sunday.');
            }
            if ($dt > $cap) {
                throw new \RuntimeException('The last available date is the first Sunday of June.');
            }
            $validDates[$entry] = $dt;
        }

        if ($type === 'late' && (!is_string($arrivalTime) || $arrivalTime === '')) {
            throw new \RuntimeException('Please provide an expected arrival time for late reporting.');
        }
        if ($type === 'early_dismissal' && (!is_string($dismissTime) || $dismissTime === '')) {
            throw new \RuntimeException('Please provide a dismissal time for early dismissal.');
        }
        if ($type !== 'early_dismissal') {
            if ($reason === null || $reason === '') {
                throw new \RuntimeException('Please provide a reason for absence or late arrival.');
            }
        }

        $inserted = 0;
        $blocked = [];
        $successDetails = [];

        foreach ($studentIds as $sid) {
            if ($sid <= 0) {
                continue;
            }
            $sectionRow = DB::table('student_class')
                ->select('class_section_id')
                ->where('student_id', $sid)
                ->where('school_year', $schoolYear)
                ->orderByDesc('updated_at')
                ->first();
            $classSectionId = $sectionRow->class_section_id ?? null;
            $student = Student::query()->select('firstname', 'lastname')->find($sid);
            $studentName = $student ? trim($student->firstname . ' ' . $student->lastname) : ('Student #' . $sid);
            $classLabel = $this->resolveClassSectionLabel($classSectionId);

            foreach ($validDates as $reportDate => $_dt) {
                $semesterForDate = $this->semesterRangeService->getSemesterForDate($reportDate) ?: $semester;
                $saved = false;

                $qb = ParentAttendanceReport::query()
                    ->where('student_id', $sid)
                    ->where('report_date', $reportDate);

                if ($type === 'early_dismissal') {
                    $existingAL = (clone $qb)
                        ->whereIn('type', ['absent', 'late'])
                        ->first();
                    if ($existingAL) {
                        $blocked[] = $studentName . ' (' . $reportDate . ')';
                    } else {
                        $existingED = (clone $qb)->where('type', 'early_dismissal')->first();
                        if ($existingED) {
                            $existingED->update([
                                'dismiss_time' => $dismissTime ?: $existingED->dismiss_time,
                                'status' => 'new',
                            ]);
                            $saved = true;
                            $inserted++;
                        } else {
                            ParentAttendanceReport::query()->create([
                                'parent_id' => $parentId,
                                'student_id' => $sid,
                                'class_section_id' => $classSectionId,
                                'report_date' => $reportDate,
                                'type' => 'early_dismissal',
                                'dismiss_time' => $dismissTime ?: null,
                                'reason' => $reason ?: null,
                                'semester' => $semesterForDate,
                                'school_year' => $schoolYear,
                                'status' => 'new',
                            ]);
                            $saved = true;
                            $inserted++;
                        }
                    }
                } else {
                    $existingAny = (clone $qb)
                        ->whereIn('type', ['absent', 'late', 'early_dismissal'])
                        ->first();
                    if ($existingAny) {
                        $blocked[] = $studentName . ' (' . $reportDate . ')';
                    } else {
                        ParentAttendanceReport::query()->create([
                            'parent_id' => $parentId,
                            'student_id' => $sid,
                            'class_section_id' => $classSectionId,
                            'report_date' => $reportDate,
                            'type' => $type,
                            'arrival_time' => ($type === 'late') ? ($arrivalTime ?: null) : null,
                            'reason' => $reason ?: null,
                            'semester' => $semesterForDate,
                            'school_year' => $schoolYear,
                            'status' => 'new',
                        ]);
                        $saved = true;
                        $inserted++;
                    }
                }

                if ($saved && in_array($type, ['absent', 'late'], true)) {
                    $this->reflectToAttendanceData(
                        studentId: $sid,
                        reportDate: $reportDate,
                        type: $type,
                        semester: $semesterForDate,
                        schoolYear: $schoolYear,
                        classSectionId: $classSectionId,
                        reason: $reason,
                        arrivalTime: $arrivalTime
                    );
                }

                if ($saved) {
                    $successDetails[] = [
                        'student_id' => $sid,
                        'name' => $studentName,
                        'class_label' => $classLabel,
                        'type' => $type,
                        'arrival_time' => $arrivalTime,
                        'dismiss_time' => $dismissTime,
                        'date' => $reportDate,
                    ];
                }
            }
        }

        if ($inserted <= 0) {
            $err = !empty($blocked)
                ? ('Already submitted and cannot be changed for: ' . implode(', ', array_slice($blocked, 0, 5)) . (count($blocked) > 5 ? '…' : ''))
                : 'Could not save your report. Please try again.';
            throw new \RuntimeException($err);
        }

        return [
            'inserted' => $inserted,
            'blocked' => $blocked,
            'students' => $successDetails,
            'dates' => array_keys($validDates),
        ];
    }

    public function listReports(string $start, ?string $end, ?string $schoolYear, ?string $semester, int $parentId): array
    {
        return ParentAttendanceReport::listForDateRange($start, $end, $schoolYear, $semester, $parentId);
    }

    public function checkExisting(int $parentId, array $payload): array
    {
        $datesPost = $payload['dates'] ?? null;
        $dateSingle = $payload['date'] ?? null;
        $dateValues = [];
        if (is_array($datesPost)) {
            foreach ($datesPost as $d) {
                $dateValues[] = substr((string) $d, 0, 10);
            }
        } elseif ($dateSingle !== null) {
            $dateValues[] = substr((string) $dateSingle, 0, 10);
        }
        $dateValues = array_values(array_unique(array_filter($dateValues, static function ($d) {
            return preg_match('/^\\d{4}-\\d{2}-\\d{2}$/', $d);
        })));

        $type = (string) ($payload['type'] ?? '');
        if (empty($dateValues) || !in_array($type, ['absent', 'late', 'early_dismissal'], true)) {
            throw new \RuntimeException('Invalid date or type.');
        }

        $studentIds = array_values(array_unique(array_map('intval', (array) ($payload['student_ids'] ?? []))));
        $studentIds = array_filter($studentIds, static fn ($v) => $v > 0);
        if (empty($studentIds)) {
            return [];
        }

        $uniqueIds = array_values(array_unique($studentIds));
        $ownedCount = Student::query()
            ->where('parent_id', $parentId)
            ->whereIn('id', $uniqueIds)
            ->count();
        if ($ownedCount !== count($uniqueIds)) {
            throw new \RuntimeException('Invalid student selection.');
        }

        $rows = DB::table('parent_attendance_reports as par')
            ->select('par.student_id', 'par.type', 'par.report_date', 's.firstname', 's.lastname')
            ->leftJoin('students as s', 's.id', '=', 'par.student_id')
            ->whereIn('par.report_date', $dateValues)
            ->whereIn('par.student_id', $studentIds)
            ->get()
            ->map(fn ($row) => (array) $row)
            ->all();

        $map = [];
        foreach ($rows as $row) {
            $sid = (int) ($row['student_id'] ?? 0);
            if ($sid <= 0) {
                continue;
            }
            if (!isset($map[$sid])) {
                $map[$sid] = [
                    'student_id' => $sid,
                    'firstname' => (string) ($row['firstname'] ?? ''),
                    'lastname' => (string) ($row['lastname'] ?? ''),
                    'dates' => [],
                ];
            }
            $dVal = substr((string) ($row['report_date'] ?? ''), 0, 10);
            if ($dVal === '') {
                continue;
            }
            $map[$sid]['dates'][$dVal] = $map[$sid]['dates'][$dVal] ?? [];
            $t = (string) ($row['type'] ?? '');
            if ($t !== '' && !in_array($t, $map[$sid]['dates'][$dVal], true)) {
                $map[$sid]['dates'][$dVal][] = $t;
            }
        }

        return array_values($map);
    }

    public function updateReport(int $parentId, int $reportId, array $payload): void
    {
        $row = ParentAttendanceReport::query()->find($reportId);
        if (!$row || (int) $row->parent_id !== $parentId) {
            throw new \RuntimeException('Report not found.');
        }

        if ((string) ($row->status ?? '') !== 'new') {
            throw new \RuntimeException('This report can no longer be edited.');
        }

        $tzName = (string) (config('School')->attendance['timezone'] ?? 'UTC');
        $tz = new \DateTimeZone($tzName ?: 'UTC');
        $cutoff = new \DateTime($row->report_date . ' 09:00:00', $tz);
        $now = new \DateTime('now', $tz);
        if ($now >= $cutoff) {
            throw new \RuntimeException('Editing window closed at 9:00 AM on the report date.');
        }

        $type = (string) $row->type;
        $reason = trim((string) ($payload['reason'] ?? ''));
        $arrival = (string) ($payload['arrival_time'] ?? '');
        $dismiss = (string) ($payload['dismiss_time'] ?? '');

        $update = [
            'reason' => $reason !== '' ? $reason : null,
        ];

        if ($type === 'late' && $arrival !== '') {
            if (!preg_match('/^\\d{2}:\\d{2}(:\\d{2})?$/', $arrival)) {
                throw new \RuntimeException('Invalid arrival time format.');
            }
            $update['arrival_time'] = $arrival;
        }
        if ($type === 'early_dismissal' && $dismiss !== '') {
            if (!preg_match('/^\\d{2}:\\d{2}(:\\d{2})?$/', $dismiss)) {
                throw new \RuntimeException('Invalid dismissal time format.');
            }
            $update['dismiss_time'] = $dismiss;
        }

        if (empty($update)) {
            throw new \RuntimeException('Nothing to update.');
        }

        $row->update($update);
    }

    /**
     * Staff index: early dismissal rows grouped by date (+ signature metadata per date).
     *
     * Parity with legacy {@see \App\Controllers\View\ParentAttendanceReportController::earlyDismissals}.
     *
     * @return array{groups: array<string, array<int, array<string, mixed>>>, school_year: string, semester: string, signature_by_date: array<string, array<string, mixed>>}
     */
    public function staffEarlyDismissalsIndex(?string $schoolYearParam, ?string $semesterParam): array
    {
        $context = $this->configService->context();
        $schoolYear = filled($schoolYearParam) ? trim((string) $schoolYearParam) : (string) ($context['school_year'] ?? '');
        $semester = filled($semesterParam) ? trim((string) $semesterParam) : '';

        $b = DB::table('parent_attendance_reports as par')
            ->select('par.*', 's.firstname', 's.lastname', 'cs.class_section_name')
            ->leftJoin('students as s', 's.id', '=', 'par.student_id')
            ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'par.class_section_id')
            ->where('par.type', '=', 'early_dismissal');

        if ($schoolYear !== '') {
            $b->where('par.school_year', $schoolYear);
        }
        if ($semester !== '') {
            $b->where('par.semester', $semester);
        }

        $rows = $b->orderByDesc('par.report_date')
            ->orderBy('par.dismiss_time')
            ->get()
            ->map(fn ($r) => (array) $r)
            ->all();

        $groups = [];
        foreach ($rows as $r) {
            $d = substr((string) ($r['report_date'] ?? ''), 0, 10);
            if ($d === '') {
                $d = 'Unknown';
            }
            $groups[$d][] = $r;
        }
        uksort($groups, static function ($a, $b) {
            if ($a === 'Unknown' && $b === 'Unknown') {
                return 0;
            }
            if ($a === 'Unknown') {
                return 1;
            }
            if ($b === 'Unknown') {
                return -1;
            }

            return strcmp((string) $b, (string) $a);
        });

        $signatureByDate = [];
        $dates = array_values(array_filter(array_keys($groups), static function ($d) {
            return preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) $d) === 1;
        }));
        if ($dates !== []) {
            $sigQ = EarlyDismissalSignature::query()->whereIn('report_date', $dates);
            if ($schoolYear !== '') {
                $sigQ->where('school_year', $schoolYear);
            }
            if ($semester !== '') {
                $sigQ->where('semester', $semester);
            }
            foreach ($sigQ->orderBy('report_date')->get() as $sig) {
                $d = $sig->report_date instanceof \DateTimeInterface
                    ? $sig->report_date->format('Y-m-d')
                    : substr((string) $sig->report_date, 0, 10);
                if ($d !== '') {
                    $signatureByDate[$d] = $sig->toArray();
                }
            }
        }

        return [
            'groups' => $groups,
            'school_year' => $schoolYear,
            'semester' => $semester,
            'signature_by_date' => $signatureByDate,
        ];
    }

    /**
     * Parity with legacy {@see \App\Controllers\View\ParentAttendanceReportController::addEarlyDismissalForm}.
     *
     * @return array{students: array<int, array<string, mixed>>, default_date: string, school_year: string, semester: string}
     */
    public function staffAddEarlyDismissalFormData(): array
    {
        $context = $this->configService->context();
        $schoolYear = (string) ($context['school_year'] ?? '');
        $semester = (string) ($context['semester'] ?? '');

        try {
            $students = DB::table('students as s')
                ->select('s.id', 's.firstname', 's.lastname', 's.parent_id', 'cs.class_section_name', 'sc.class_section_id')
                ->leftJoin('student_class as sc', function ($join) use ($schoolYear) {
                    $join->on('sc.student_id', '=', 's.id')
                        ->where('sc.school_year', '=', $schoolYear);
                })
                ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'sc.class_section_id')
                ->orderBy('s.lastname')
                ->orderBy('s.firstname')
                ->get()
                ->map(fn ($r) => (array) $r)
                ->all();
        } catch (\Throwable) {
            $students = [];
        }

        [, $defaultDate] = $this->calendarService->computeSundays(0, 26);

        return [
            'students' => $students,
            'default_date' => $defaultDate,
            'school_year' => $schoolYear,
            'semester' => $semester,
        ];
    }

    /**
     * Parity with legacy {@see \App\Controllers\View\ParentAttendanceReportController::saveEarlyDismissal}.
     */
    public function saveStaffEarlyDismissal(int $studentId, string $reportDate, string $dismissTime, string $reason): void
    {
        $context = $this->configService->context();
        $schoolYear = (string) ($context['school_year'] ?? '');
        $semester = (string) ($context['semester'] ?? '');

        $dt = \DateTime::createFromFormat('Y-m-d', $reportDate);
        if (! $dt || (int) $dt->format('w') !== 0) {
            throw new \RuntimeException('Please select a Sunday date.');
        }

        $stu = Student::query()->select('id', 'parent_id', 'firstname', 'lastname')->find($studentId);
        if (! $stu || empty($stu->parent_id)) {
            throw new \RuntimeException('Selected student not found or has no primary parent assigned.');
        }
        $parentId = (int) $stu->parent_id;

        $sectionRow = DB::table('student_class')
            ->select('class_section_id')
            ->where('student_id', $studentId)
            ->where('school_year', $schoolYear)
            ->orderByDesc('updated_at')
            ->first();

        $classSectionId = $sectionRow ? (int) $sectionRow->class_section_id : null;

        $qb = ParentAttendanceReport::query()
            ->where('student_id', $studentId)
            ->whereDate('report_date', $reportDate)
            ->where('school_year', $schoolYear);

        $existingAl = (clone $qb)->where(function ($q) {
            $q->where('type', 'absent')->orWhere('type', 'late');
        })->first();

        if ($existingAl) {
            throw new \RuntimeException('Absent/Late already submitted for this student on the selected date.');
        }

        $existingEd = (clone $qb)->where('type', 'early_dismissal')->first();

        if ($existingEd) {
            $existingEd->update([
                'dismiss_time' => $dismissTime !== '' ? $dismissTime : $existingEd->dismiss_time,
                'reason' => $reason !== '' ? $reason : $existingEd->reason,
                'status' => 'new',
            ]);

            return;
        }

        ParentAttendanceReport::query()->create([
            'parent_id' => $parentId,
            'student_id' => $studentId,
            'class_section_id' => $classSectionId,
            'report_date' => $reportDate,
            'type' => 'early_dismissal',
            'dismiss_time' => $dismissTime,
            'reason' => $reason !== '' ? $reason : null,
            'semester' => $semester,
            'school_year' => $schoolYear,
            'status' => 'new',
        ]);
    }

    /**
     * Parity with legacy {@see \App\Controllers\View\ParentAttendanceReportController::uploadEarlyDismissalSignature}.
     * Files live under {@see storage_path('uploads/early_dismissal_signatures')} (same as {@see \App\Http\Controllers\Api\Reports\FilesController::earlyDismissalSignature}).
     */
    public function storeEarlyDismissalSignature(
        UploadedFile $file,
        string $reportDate,
        ?string $schoolYearPost,
        ?string $semesterPost,
        int $uploadedByUserId,
    ): void {
        $dt = \DateTime::createFromFormat('Y-m-d', $reportDate);
        if (! $dt || (int) $dt->format('w') !== 0) {
            throw new \RuntimeException('Please select a Sunday date.');
        }

        $context = $this->configService->context();
        $schoolYear = $schoolYearPost !== null && $schoolYearPost !== ''
            ? (string) $schoolYearPost
            : (string) ($context['school_year'] ?? '');
        $semesterRaw = (string) ($semesterPost ?? '');
        $hasSemesterFilter = $semesterRaw !== '';
        $semester = $hasSemesterFilter ? $semesterRaw : null;

        $existsQ = ParentAttendanceReport::query()
            ->where('type', 'early_dismissal')
            ->whereDate('report_date', $reportDate);
        if ($schoolYear !== '') {
            $existsQ->where('school_year', $schoolYear);
        }
        if ($hasSemesterFilter) {
            $existsQ->where('semester', $semester);
        }
        if (! $existsQ->exists()) {
            throw new \RuntimeException('No early dismissal records found for that date.');
        }

        $targetDir = storage_path('uploads/early_dismissal_signatures');
        if (! is_dir($targetDir) && ! @mkdir($targetDir, 0755, true) && ! is_dir($targetDir)) {
            throw new \RuntimeException('Upload directory is not available.');
        }

        $originalName = $file->getClientOriginalName();
        $mimeType = $file->getClientMimeType();
        $fileSize = (int) $file->getSize();
        $filename = $file->hashName();
        $file->move($targetDir, $filename);

        $payload = [
            'report_date' => $reportDate,
            'school_year' => $schoolYear !== '' ? $schoolYear : null,
            'semester' => $semester,
            'filename' => $filename,
            'original_name' => $originalName,
            'mime_type' => $mimeType,
            'file_size' => $fileSize,
            'uploaded_by' => $uploadedByUserId,
        ];

        $existingQ = EarlyDismissalSignature::query()->whereDate('report_date', $reportDate);
        if ($schoolYear !== '') {
            $existingQ->where('school_year', $schoolYear);
        }
        if ($hasSemesterFilter) {
            $existingQ->where('semester', $semester);
        }
        $existing = $existingQ->first();

        if ($existing) {
            $oldFile = (string) ($existing->filename ?? '');
            $existing->update($payload);
            if ($oldFile !== '' && $oldFile !== $filename) {
                @unlink($targetDir . DIRECTORY_SEPARATOR . $oldFile);
            }
        } else {
            EarlyDismissalSignature::query()->create($payload);
        }
    }

    private function resolveClassSectionLabel(?int $classSectionId): string
    {
        $cid = (int) ($classSectionId ?? 0);
        if ($cid <= 0) {
            return 'Not Assigned';
        }

        $name = ClassSection::query()
            ->where('class_section_id', $cid)
            ->value('class_section_name');

        return $name ?: 'Not Assigned';
    }

    private function reflectToAttendanceData(
        int $studentId,
        string $reportDate,
        string $type,
        string $semester,
        string $schoolYear,
        ?int $classSectionId,
        ?string $reason = null,
        ?string $arrivalTime = null
    ): void {
        $status = ($type === 'late') ? 'late' : (($type === 'absent') ? 'absent' : null);
        if ($status === null) {
            return;
        }

        if (!$classSectionId) {
            $row = DB::table('student_class')
                ->select('class_section_id')
                ->where('student_id', $studentId)
                ->where('school_year', $schoolYear)
                ->orderByDesc('updated_at')
                ->first();
            $classSectionId = (int) ($row->class_section_id ?? 0);
        }
        if ($classSectionId <= 0) {
            return;
        }

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

        $reasonParts = ['Parent-reported'];
        if ($type === 'late' && $arrivalTime) {
            $reasonParts[] = 'ETA ' . substr($arrivalTime, 0, 5);
        }
        if (!empty($reason)) {
            $reasonParts[] = trim($reason);
        }
        $reasonText = implode(' — ', $reasonParts);

        if (!$existing) {
            $classId = ClassSection::query()
                ->where('class_section_id', $classSectionId)
                ->value('class_id');
            $schoolId = Student::query()->whereKey($studentId)->value('school_id');
            if (!$classId || !$schoolId) {
                return;
            }
            AttendanceData::query()->create([
                'class_id' => $classId,
                'class_section_id' => $classSectionId,
                'student_id' => $studentId,
                'school_id' => $schoolId,
                'date' => $reportDate,
                'status' => $status,
                'reason' => $reasonText,
                'semester' => $semester,
                'school_year' => $schoolYear,
            ]);
            $this->bumpAttendanceRecord($studentId, $classSectionId, $schoolId, $status, $semester, $schoolYear);
            return;
        }

        $existingStatus = strtolower((string) ($existing->status ?? ''));
        if ($existingStatus === 'present' || $existingStatus === '') {
            $existing->update([
                'status' => $status,
                'reason' => $existing->reason ?: $reasonText,
            ]);
        }
    }

    private function bumpAttendanceRecord(
        int $studentId,
        int $classSectionId,
        string $schoolId,
        string $status,
        string $semester,
        string $schoolYear
    ): void {
        $record = AttendanceRecord::query()
            ->where('student_id', $studentId)
            ->where('semester', $semester)
            ->where('school_year', $schoolYear)
            ->first();

        if ($record) {
            $updates = [
                'total_presence' => (int) ($record->total_presence ?? 0),
                'total_absence' => (int) ($record->total_absence ?? 0),
                'total_late' => (int) ($record->total_late ?? 0),
                'total_attendance' => (int) ($record->total_attendance ?? 0) + 1,
            ];
            if ($status === 'present') {
                $updates['total_presence']++;
            } elseif ($status === 'absent') {
                $updates['total_absence']++;
            } elseif ($status === 'late') {
                $updates['total_late']++;
            }
            $record->update($updates);
            return;
        }

        AttendanceRecord::query()->create([
            'class_section_id' => $classSectionId,
            'student_id' => $studentId,
            'school_id' => $schoolId,
            'semester' => $semester,
            'school_year' => $schoolYear,
            'total_presence' => ($status === 'present') ? 1 : 0,
            'total_absence' => ($status === 'absent') ? 1 : 0,
            'total_late' => ($status === 'late') ? 1 : 0,
            'total_attendance' => 1,
        ]);
    }
}
