<?php

namespace App\Services;

use App\Models\ConfigurationModel;
use DateTimeImmutable;

class SemesterRangeService
{
    private ConfigurationModel $configModel;

    public function __construct(?ConfigurationModel $configModel = null)
    {
        $this->configModel = $configModel ?? new ConfigurationModel();
    }

    public function getSchoolYearRange(string $schoolYear): array
    {
        $startCfg = (string)($this->configModel->getConfig('fall_semester_start') ?? '');
        $endCfg   = (string)($this->configModel->getConfig('last_school_day') ?? '');

        $start = null;
        $end = null;
        try {
            if ($startCfg !== '') {
                $start = new DateTimeImmutable($startCfg);
            }
        } catch (\Throwable) {
            $start = null;
        }
        try {
            if ($endCfg !== '') {
                $end = new DateTimeImmutable($endCfg);
            }
        } catch (\Throwable) {
            $end = null;
        }

        if ($start === null || $end === null) {
            if (preg_match('/^(\d{4})-(\d{4})$/', $schoolYear, $m)) {
                $y1 = (int)$m[1];
                $y2 = (int)$m[2];
                if ($start === null) {
                    $start = new DateTimeImmutable($y1 . '-09-01');
                }
                if ($end === null) {
                    $end = new DateTimeImmutable($y2 . '-06-30');
                }
            } else {
                $currentYear = (int)date('Y');
                if ($start === null) {
                    $start = new DateTimeImmutable($currentYear . '-09-01');
                }
                if ($end === null) {
                    $end = new DateTimeImmutable(($currentYear + 1) . '-06-30');
                }
            }
        }

        if ($end < $start) {
            [$start, $end] = [$end, $start];
        }

        return [$start->format('Y-m-d'), $end->format('Y-m-d')];
    }

    public function getSemesterRange(string $schoolYear, string $semester): ?array
    {
        if (!preg_match('/^(\\d{4})-(\\d{4})$/', $schoolYear, $m)) {
            return null;
        }
        $y1 = (int)$m[1];
        $y2 = (int)$m[2];
        $normalized = ucfirst(strtolower(trim($semester)));

        $fallStartCfg   = (string)($this->configModel->getConfig('fall_semester_start')   ?? '');
        $fallEndCfg     = (string)($this->configModel->getConfig('fall_end_date')         ?? '');
        $springStartCfg = (string)($this->configModel->getConfig('spring_semester_start') ?? '');
        $springEndCfg   = (string)($this->configModel->getConfig('last_school_day')       ?? '');

        $md = static fn(string $cfg, int $year, string $fallback): string =>
            $cfg !== '' ? sprintf('%04d-%s', $year, date('m-d', strtotime($cfg))) : $fallback;

        if ($normalized === 'Fall') {
            return [
                $md($fallStartCfg, $y1, sprintf('%04d-09-21', $y1)),
                $md($fallEndCfg,   $y2, sprintf('%04d-01-18', $y2)),
            ];
        }
        if ($normalized === 'Spring') {
            return [
                $md($springStartCfg, $y2, sprintf('%04d-01-25', $y2)),
                $md($springEndCfg,   $y2, sprintf('%04d-05-31', $y2)),
            ];
        }
        return null;
    }

    public function normalizeSemester(?string $semester): string
    {
        $value = strtolower(trim((string)($semester ?? '')));
        if ($value === 'fall') {
            return 'Fall';
        }
        if ($value === 'spring') {
            return 'Spring';
        }
        return '';
    }

    public function getSemesterForDate(?string $date = null): string
    {
        $fallStartCfg   = (string)($this->configModel->getConfig('fall_semester_start')   ?? '');
        $springStartCfg = (string)($this->configModel->getConfig('spring_semester_start') ?? '');
        $lastDayCfg     = (string)($this->configModel->getConfig('last_school_day')
            ?? $this->configModel->getConfig('last_day_of_school') ?? '');

        try {
            $target = new DateTimeImmutable($date ?: 'now');
        } catch (\Throwable) {
            return '';
        }

        try {
            $fallStart = $fallStartCfg !== '' ? new DateTimeImmutable($fallStartCfg) : null;
        } catch (\Throwable) {
            $fallStart = null;
        }
        try {
            $springStart = $springStartCfg !== '' ? new DateTimeImmutable($springStartCfg) : null;
        } catch (\Throwable) {
            $springStart = null;
        }
        try {
            $lastDay = $lastDayCfg !== '' ? new DateTimeImmutable($lastDayCfg) : null;
        } catch (\Throwable) {
            $lastDay = null;
        }

        if ($fallStart === null || $springStart === null || $lastDay === null) {
            return '';
        }

        $target = $target->setTime(0, 0, 0);
        $fallStart = $fallStart->setTime(0, 0, 0);
        $springStart = $springStart->setTime(0, 0, 0);
        $lastDay = $lastDay->setTime(0, 0, 0);

        $nextFallStart = $fallStart <= $lastDay ? $fallStart->modify('+1 year') : $fallStart;

        if (($fallStart <= $target && $target < $springStart)
            || ($lastDay <= $target && $target < $nextFallStart)
        ) {
            return 'Fall';
        }

        if ($springStart <= $target && $target < $lastDay) {
            return 'Spring';
        }

        return '';
    }
}
