<?php

namespace App\Services\Assignment;

use App\Models\StudentClass;

class AssignmentService
{
    public function __construct(
        protected StudentClass $studentClassModel,
        protected AssignmentContextService $contextService,
        protected AssignmentDataLoaderService $dataLoader,
        protected AssignmentSectionService $sectionService,
        protected AssignmentMetaService $metaService
    ) {}

    public function getCurrentSemester(): string
    {
        return $this->contextService->getCurrentSemester();
    }

    public function getCurrentSchoolYear(): string
    {
        return $this->contextService->getCurrentSchoolYear();
    }

    public function getAssignmentsOverview(?string $schoolYear = null, ?string $semester = null): array
    {
        $currentSemester = $this->getCurrentSemester();
        $currentSchoolYear = $this->getCurrentSchoolYear();

        $selectedSemester = (string) ($semester ?? $currentSemester);
        $selectedYear = (string) ($schoolYear ?? $currentSchoolYear);

        $teacherClasses = $this->dataLoader->loadTeacherClasses($selectedYear);
        $studentClasses = $this->dataLoader->loadStudentClasses($selectedYear);

        $teacherBySection = $teacherClasses->groupBy('class_section_id');
        $studentBySection = $studentClasses->groupBy('class_section_id');

        $allSectionIds = $teacherBySection->keys()
            ->merge($studentBySection->keys())
            ->unique()
            ->filter()
            ->values();

        $sectionNames = $this->sectionService->getSectionNamesMap($allSectionIds->all());

        $classSections = $allSectionIds->map(function ($sectionId) use (
            $teacherBySection,
            $studentBySection,
            $sectionNames,
            $currentSemester,
            $currentSchoolYear
        ) {
            $teacherRows = $teacherBySection->get($sectionId, collect());
            $studentRows = $studentBySection->get($sectionId, collect());

            if ($teacherRows->isEmpty() && $studentRows->isEmpty()) {
                return null;
            }

            $mainTeachers = $teacherRows
                ->where('position', 'main')
                ->pluck('teacher_full_name')
                ->filter()
                ->unique()
                ->values();

            $teacherAssistants = $teacherRows
                ->where('position', 'ta')
                ->pluck('teacher_full_name')
                ->filter()
                ->unique()
                ->values();

            $semesterMeta = $this->metaService->firstNonEmpty([
                $teacherRows->pluck('semester')->first(fn ($v) => filled($v)),
                $studentRows->pluck('semester')->first(fn ($v) => filled($v)),
                $currentSemester,
            ]);

            $schoolYearMeta = $this->metaService->firstNonEmpty([
                $teacherRows->pluck('school_year')->first(fn ($v) => filled($v)),
                $studentRows->pluck('school_year')->first(fn ($v) => filled($v)),
                $currentSchoolYear,
            ]);

            $descriptionMeta = $this->metaService->firstNonEmpty([
                $teacherRows->pluck('description')->first(fn ($v) => filled($v)),
                $studentRows->pluck('description')->first(fn ($v) => filled($v)),
                '',
            ]);

            $students = $studentRows
                ->filter(fn ($row) => !empty($row->student))
                ->map(function ($row) {
                    $student = $row->student;

                    return [
                        'id' => (int) $student->id,
                        'firstname' => (string) ($student->firstname ?? ''),
                        'lastname' => (string) ($student->lastname ?? ''),
                        'age' => $student->age,
                        'gender' => (string) ($student->gender ?? ''),
                        'registration_grade' => (string) ($student->registration_grade ?? ''),
                        'photo_consent' => (bool) ($student->photo_consent ?? false),
                        'tuition_paid' => (bool) ($student->tuition_paid ?? false),
                        'school_id' => (string) ($student->school_id ?? ''),
                    ];
                })
                ->values();

            return [
                'class_section_id' => (int) $sectionId,
                'class_section_name' => (string) ($sectionNames[$sectionId] ?? ''),
                'main_teachers' => $mainTeachers->all(),
                'teacher_assistants' => $teacherAssistants->all(),
                'students' => $students->all(),
                'semester' => (string) $semesterMeta,
                'school_year' => (string) $schoolYearMeta,
                'description' => (string) $descriptionMeta,
            ];
        })
        ->filter()
        ->sortBy('class_section_name', SORT_NATURAL | SORT_FLAG_CASE)
        ->values()
        ->all();

        return [
            'classSections' => $classSections,
            'schoolYears' => $this->metaService->getSchoolYears($currentSchoolYear),
            'schoolYear' => $selectedYear,
            'selectedYear' => $selectedYear,
            'selectedSemester' => $selectedSemester,
            'semester' => $currentSemester,
            'current_school_year' => $currentSchoolYear,
        ];
    }

    public function storeAssignment(array $data, int|string|null $updatedBy = null): StudentClass
    {
        return $this->studentClassModel->newQuery()->updateOrCreate(
            [
                'student_id' => $data['student_id'],
                'class_section_id' => $data['class_section_id'],
                'semester' => $data['semester'],
                'school_year' => $data['school_year'],
            ],
            [
                'description' => $data['description'] ?? null,
                'updated_by' => $updatedBy,
            ]
        );
    }

    public function getClassAssignmentData(): array
    {
        $currentSemester = $this->getCurrentSemester();
        $currentSchoolYear = $this->getCurrentSchoolYear();

        $teacherClasses = $this->dataLoader->loadTeacherClasses();
        $studentClasses = $this->dataLoader->loadStudentClasses();

        $teacherBySection = $teacherClasses->groupBy('class_section_id');
        $studentBySection = $studentClasses->groupBy('class_section_id');

        $allSectionIds = $teacherBySection->keys()
            ->merge($studentBySection->keys())
            ->unique()
            ->filter()
            ->values();

        $sectionNames = $this->sectionService->getSectionNamesMap($allSectionIds->all());

        $classSections = $allSectionIds->map(function ($sectionId) use (
            $teacherBySection,
            $studentBySection,
            $sectionNames,
            $currentSemester,
            $currentSchoolYear
        ) {
            $teacherRows = $teacherBySection->get($sectionId, collect());
            $studentRows = $studentBySection->get($sectionId, collect());

            if ($teacherRows->isEmpty() && $studentRows->isEmpty()) {
                return null;
            }

            $mainTeachers = $teacherRows
                ->where('position', 'main')
                ->pluck('teacher_full_name')
                ->filter()
                ->unique()
                ->values();

            $teacherAssistants = $teacherRows
                ->where('position', 'ta')
                ->pluck('teacher_full_name')
                ->filter()
                ->unique()
                ->values();

            $semesterMeta = $this->metaService->firstNonEmpty([
                $teacherRows->pluck('semester')->first(fn ($v) => filled($v)),
                $studentRows->pluck('semester')->first(fn ($v) => filled($v)),
                $currentSemester,
            ]);

            $schoolYearMeta = $this->metaService->firstNonEmpty([
                $teacherRows->pluck('school_year')->first(fn ($v) => filled($v)),
                $studentRows->pluck('school_year')->first(fn ($v) => filled($v)),
                $currentSchoolYear,
            ]);

            $descriptionMeta = $this->metaService->firstNonEmpty([
                $teacherRows->pluck('description')->first(fn ($v) => filled($v)),
                $studentRows->pluck('description')->first(fn ($v) => filled($v)),
                '',
            ]);

            $students = $studentRows
                ->filter(fn ($row) => !empty($row->student))
                ->map(function ($row) {
                    $student = $row->student;

                    return [
                        'id' => (int) $student->id,
                        'firstname' => (string) ($student->firstname ?? ''),
                        'lastname' => (string) ($student->lastname ?? ''),
                        'age' => $student->age,
                        'gender' => (string) ($student->gender ?? ''),
                        'registration_grade' => (string) ($student->registration_grade ?? ''),
                        'photo_consent' => (bool) ($student->photo_consent ?? false),
                        'tuition_paid' => (bool) ($student->tuition_paid ?? false),
                        'school_id' => (string) ($student->school_id ?? ''),
                    ];
                })
                ->values();

            return [
                'class_section_id' => (int) $sectionId,
                'class_section_name' => (string) ($sectionNames[$sectionId] ?? ''),
                'main_teachers' => $mainTeachers->all(),
                'teacher_assistants' => $teacherAssistants->all(),
                'students' => $students->all(),
                'semester' => (string) $semesterMeta,
                'school_year' => (string) $schoolYearMeta,
                'description' => (string) $descriptionMeta,
            ];
        })
        ->filter()
        ->sortBy('class_section_name', SORT_NATURAL | SORT_FLAG_CASE)
        ->values()
        ->all();

        return [
            'classSections' => $classSections,
            'semester' => $currentSemester,
            'school_year' => $currentSchoolYear,
        ];
    }
}
