<?php

namespace App\Services\Parents;

use App\Models\EmergencyContact;
use App\Models\Student;
use App\Models\StudentAllergy;
use App\Models\StudentMedicalCondition;
use App\Models\User;
use App\Services\SchoolIdService;
use Illuminate\Support\Facades\DB;

class ParentRegistrationService
{
    public function __construct(
        private ParentConfigService $configService,
        private SchoolIdService $schoolIdService
    ) {
    }

    public function overview(int $parentId): array
    {
        $context = $this->configService->context();
        $parent = User::query()->find($parentId);

        $kids = Student::query()->where('parent_id', $parentId)->get();
        $kidIds = $kids->pluck('id')->all();

        $allergies = StudentAllergy::query()
            ->whereIn('student_id', $kidIds)
            ->get()
            ->groupBy('student_id');

        $conditions = StudentMedicalCondition::query()
            ->whereIn('student_id', $kidIds)
            ->get()
            ->groupBy('student_id');

        $kids = $kids->map(function ($kid) use ($allergies, $conditions) {
            $kid->allergies = ($allergies[$kid->id] ?? collect())->pluck('allergy')->all();
            $kid->medical_conditions = ($conditions[$kid->id] ?? collect())->pluck('condition_name')->all();
            return $kid->toArray();
        })->all();

        $emergencies = EmergencyContact::query()->where('parent_id', $parentId)->get()->toArray();

        return [
            'parent' => $parent ? $parent->toArray() : null,
            'existingKids' => $kids,
            'emergencies' => $emergencies,
            'maxChilds' => $context['max_kids'],
            'maxEmergency' => $context['max_emergency'],
            'lastDayOfRegistration' => $context['enrollment_deadline'],
            'registrationAgeDeadline' => $context['date_age_reference'],
        ];
    }

    public function register(int $parentId, array $students, array $emergencyContacts): array
    {
        $context = $this->configService->context();
        $schoolYear = $context['school_year'];
        $semester = $context['semester'];
        $ageReference = $context['date_age_reference'] ?: now()->toDateString();

        $existingKidsCount = Student::query()->where('parent_id', $parentId)->count();
        $existingECCount = EmergencyContact::query()->where('parent_id', $parentId)->count();

        if ($existingKidsCount + count($students) > $context['max_kids']) {
            throw new \RuntimeException('Student limit exceeded.');
        }

        if ($existingECCount + count($emergencyContacts) > $context['max_emergency']) {
            throw new \RuntimeException('Emergency contact limit exceeded.');
        }

        $createdStudentIds = [];
        $skippedStudents = [];

        DB::transaction(function () use (
            $parentId,
            $students,
            $emergencyContacts,
            $schoolYear,
            $semester,
            $ageReference,
            &$createdStudentIds,
            &$skippedStudents
        ) {
            foreach ($students as $student) {
                // Duplicate check is scoped to THIS parent: one family's
                // legitimately registered child must not block another family
                // from registering a child with the same name and DOB.
                $exists = Student::query()
                    ->where('parent_id', $parentId)
                    ->where('school_year', $schoolYear)
                    ->where('dob', $student['dob'])
                    ->whereRaw('LOWER(TRIM(firstname)) = ?', [strtolower(trim((string) $student['firstname']))])
                    ->whereRaw('LOWER(TRIM(lastname)) = ?', [strtolower(trim((string) $student['lastname']))])
                    ->first();

                if ($exists) {
                    $skippedStudents[] = [
                        'firstname' => $student['firstname'],
                        'lastname' => $student['lastname'],
                        'dob' => $student['dob'],
                        'reason' => 'already_registered',
                    ];
                    continue;
                }

                $row = Student::query()->create([
                    'firstname' => $student['firstname'],
                    'lastname' => $student['lastname'],
                    'dob' => $student['dob'],
                    'age' => $this->calculateAge($student['dob'], $ageReference),
                    'gender' => $student['gender'],
                    'registration_grade' => $student['registration_grade'] ?? null,
                    'photo_consent' => !empty($student['photo_consent']) ? 1 : 0,
                    'parent_id' => $parentId,
                    'year_of_registration' => (string) date('Y'),
                    'school_year' => $schoolYear,
                    'semester' => $semester,
                    'is_new' => isset($student['is_new']) ? (int) (bool) $student['is_new'] : null,
                    'registration_date' => now(),
                    'tuition_paid' => 0,
                    'school_id' => $this->schoolIdService->generateStudentSchoolId(),
                ]);

                $createdStudentIds[] = (int) $row->id;

                foreach (($student['medical_conditions'] ?? []) as $condition) {
                    $condition = trim((string) $condition);
                    if ($condition === '') {
                        continue;
                    }
                    StudentMedicalCondition::query()->create([
                        'student_id' => $row->id,
                        'condition_name' => $condition,
                    ]);
                }

                foreach (($student['allergies'] ?? []) as $allergy) {
                    $allergy = trim((string) $allergy);
                    if ($allergy === '') {
                        continue;
                    }
                    StudentAllergy::query()->create([
                        'student_id' => $row->id,
                        'allergy' => $allergy,
                    ]);
                }
            }

            foreach ($emergencyContacts as $contact) {
                EmergencyContact::query()->create([
                    'parent_id' => $parentId,
                    'emergency_contact_name' => $contact['name'],
                    'cellphone' => $contact['cellphone'],
                    'email' => $contact['email'] ?? null,
                    'relation' => $contact['relation'] ?? null,
                    'semester' => $semester,
                    'school_year' => $schoolYear,
                ]);
            }
        });

        return [
            'created_student_ids' => $createdStudentIds,
            'skipped' => $skippedStudents,
        ];
    }

    public function updateStudent(int $parentId, int $studentId, array $payload): void
    {
        $student = Student::query()
            ->where('id', $studentId)
            ->where('parent_id', $parentId)
            ->firstOrFail();

        $ageReference = $this->configService->context()['date_age_reference'] ?: now()->toDateString();

        $student->update([
            'firstname' => $payload['firstname'],
            'lastname' => $payload['lastname'],
            'dob' => $payload['dob'],
            'age' => $this->calculateAge($payload['dob'], $ageReference),
            'gender' => $payload['gender'],
            'registration_grade' => $payload['registration_grade'] ?? null,
            'photo_consent' => !empty($payload['photo_consent']) ? 1 : 0,
        ]);

        StudentMedicalCondition::query()->where('student_id', $studentId)->delete();
        foreach (($payload['medical_conditions'] ?? []) as $condition) {
            $condition = trim((string) $condition);
            if ($condition === '') {
                continue;
            }
            StudentMedicalCondition::query()->create([
                'student_id' => $studentId,
                'condition_name' => $condition,
            ]);
        }

        StudentAllergy::query()->where('student_id', $studentId)->delete();
        foreach (($payload['allergies'] ?? []) as $allergy) {
            $allergy = trim((string) $allergy);
            if ($allergy === '') {
                continue;
            }
            StudentAllergy::query()->create([
                'student_id' => $studentId,
                'allergy' => $allergy,
            ]);
        }
    }

    public function deleteStudent(int $parentId, int $studentId): void
    {
        $student = Student::query()
            ->where('id', $studentId)
            ->where('parent_id', $parentId)
            ->firstOrFail();

        $student->delete();

        $remaining = Student::query()->where('parent_id', $parentId)->count();
        if ($remaining === 0) {
            EmergencyContact::query()->where('parent_id', $parentId)->delete();
        }
    }

    private function calculateAge(string $dob, string $referenceDate): int
    {
        try {
            $dobObj = new \DateTimeImmutable($dob);
            $refObj = new \DateTimeImmutable($referenceDate);
            return (int) $dobObj->diff($refObj)->y;
        } catch (\Throwable $e) {
            return 0;
        }
    }
}
