<?php

namespace App\Services\Parents;

use App\Models\Enrollment;
use App\Models\Refund;
use App\Models\Student;
use App\Models\StudentClass;
use Illuminate\Support\Facades\DB;

class ParentEnrollmentService
{
    public function __construct(private ParentConfigService $configService)
    {
    }

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

        $students = Student::query()
            ->where('parent_id', $parentId)
            ->orderBy('lastname')
            ->orderBy('firstname')
            ->get()
            ->map(function ($student) use ($selectedYear) {
                $classSections = StudentClass::getClassSectionsByStudentId($student->id, $selectedYear, true);
                $student->class_section = !empty($classSections)
                    ? implode(', ', $classSections)
                    : 'Class not Assigned';

                $isArabicClass = !empty($classSections) && array_reduce(
                    $classSections,
                    static fn ($carry, $name) => $carry || (is_string($name) && stripos($name, 'arabic') === 0),
                    false
                );

                $enrollment = Enrollment::query()
                    ->select('enrollment_status', 'admission_status')
                    ->where('student_id', $student->id)
                    ->where('school_year', $selectedYear)
                    ->first();

                $statusMap = [
                    'admission under review' => 'admission under review',
                    'payment pending' => 'payment pending',
                    'enrolled' => 'enrolled',
                    'withdraw under review' => 'withdraw under review',
                    'refund pending' => 'refund pending',
                    'withdrawn' => 'withdrawn',
                    'denied' => 'denied',
                    'waitlist' => 'waitlist',
                ];

                if ($enrollment && isset($enrollment->admission_status)) {
                    $student->admission_status = $enrollment->admission_status;
                    if ($enrollment->admission_status === 'denied') {
                        $student->enrollment_status = 'denied';
                    } else {
                        $student->enrollment_status = $statusMap[$enrollment->enrollment_status] ?? 'not enrolled';
                    }
                } else {
                    $student->admission_status = null;
                    $student->enrollment_status = 'not enrolled';
                }

                if ($student->enrollment_status === 'not enrolled' && $isArabicClass) {
                    $student->enrollment_status = 'enrolled';
                }

                $student->disable_enroll = in_array(
                    $student->enrollment_status,
                    ['admission under review', 'payment pending', 'enrolled', 'withdraw under review', 'denied'],
                    true
                );

                return $student->toArray();
            })
            ->all();

        $schoolYears = DB::table('enrollments')
            ->select('school_year')
            ->distinct()
            ->orderBy('school_year', 'desc')
            ->get()
            ->map(fn ($row) => (array) $row)
            ->all();

        if (empty($schoolYears)) {
            $schoolYears[] = ['school_year' => $selectedYear];
        }

        return [
            'students' => $students,
            'schoolYears' => $schoolYears,
            'selectedYear' => $selectedYear,
            'withdrawalDeadline' => $context['refund_deadline'],
            'lastDayOfRegistration' => $context['enrollment_deadline'],
            'schoolStartDate' => $context['fall_semester_start'],
        ];
    }

    public function updateEnrollment(int $parentId, array $enrollIds, array $withdrawIds): array
    {
        $context = $this->configService->context();
        $schoolYear = $context['school_year'];
        $semester = $context['semester'];

        // Authorize every submitted student id against this parent up-front to
        // prevent IDOR — a parent must not be able to enroll or withdraw
        // another family's students by passing arbitrary ids.
        $requestedIds = array_values(array_unique(array_map(
            'intval',
            array_merge($enrollIds, $withdrawIds)
        )));
        $requestedIds = array_values(array_filter($requestedIds, static fn ($id) => $id > 0));

        $ownedIds = $requestedIds === []
            ? []
            : Student::query()
                ->where('parent_id', $parentId)
                ->whereIn('id', $requestedIds)
                ->pluck('id')
                ->map(fn ($id) => (int) $id)
                ->all();
        $ownedSet = array_flip($ownedIds);

        $enrolled = [];
        $withdrawn = [];

        foreach ($enrollIds as $studentId) {
            $studentId = (int) $studentId;
            if (! isset($ownedSet[$studentId])) {
                continue;
            }

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

            if ($existing) {
                if ((int) $existing->is_withdrawn === 1) {
                    $existing->update([
                        'is_withdrawn' => 0,
                        'withdrawal_date' => null,
                        'enrollment_status' => 'payment pending',
                        'updated_at' => now(),
                    ]);
                }
            } else {
                Enrollment::query()->create([
                    'student_id' => $studentId,
                    'parent_id' => $parentId,
                    'school_year' => $schoolYear,
                    'semester' => $semester,
                    'enrollment_date' => now()->toDateString(),
                    'is_withdrawn' => 0,
                    'enrollment_status' => 'admission under review',
                    'admission_status' => 'pending',
                    'created_at' => now(),
                ]);
            }

            $enrolled[] = $studentId;
        }

        foreach ($withdrawIds as $studentId) {
            $studentId = (int) $studentId;
            if (! isset($ownedSet[$studentId])) {
                continue;
            }

            $enrollment = Enrollment::query()
                ->where('student_id', $studentId)
                ->where('parent_id', $parentId)
                ->where('school_year', $schoolYear)
                ->where('semester', $semester)
                ->where('is_withdrawn', 0)
                ->first();

            if (!$enrollment) {
                continue;
            }

            $enrollment->update([
                'withdrawal_date' => now()->toDateString(),
                'enrollment_status' => 'withdraw under review',
                'updated_at' => now(),
            ]);

            $invoice = DB::table('invoices')
                ->where('parent_id', $parentId)
                ->where('school_year', $schoolYear)
                ->orderByDesc('created_at')
                ->first();

            if ($invoice) {
                $refund = Refund::query()
                    ->where('parent_id', $parentId)
                    ->where('invoice_id', $invoice->id)
                    ->where('school_year', $schoolYear)
                    ->first();

                if ($refund) {
                    $refund->update([
                        'reason' => 'Withdrawal under review for student ID ' . $studentId,
                        'note' => null,
                        'updated_by' => $parentId,
                    ]);
                } else {
                    Refund::query()->create([
                        'parent_id' => $parentId,
                        'invoice_id' => $invoice->id,
                        'requested_at' => now(),
                        'school_year' => $schoolYear,
                        'status' => Refund::STATUS_PENDING,
                        'reason' => 'Withdrawal under review for student ID ' . $studentId,
                        'request' => 'new',
                        'semester' => $semester,
                        'refund_paid_amount' => 0.0,
                    ]);
                }
            }

            $withdrawn[] = $studentId;
        }

        return [
            'enrolled' => $enrolled,
            'withdrawn' => $withdrawn,
        ];
    }
}
