<?php

namespace App\Services;

use App\Models\SchoolYearModel;
use DateTimeImmutable;
use InvalidArgumentException;

final class SchoolYearValidationService
{
    public function __construct(
        private readonly SchoolYearModel $schoolYearModel,
    ) {
    }

    public function validateMetadata(array $payload, ?int $exceptId = null): void
    {
        $name = trim((string) ($payload['name'] ?? ''));

        if (! $this->isValidYearName($name)) {
            throw new InvalidArgumentException('School year must use YYYY-YYYY with consecutive years.');
        }

        $existing = $this->schoolYearModel->where('name', $name);
        if ($exceptId !== null) {
            $existing->where('id !=', $exceptId);
        }
        if ($existing->first() !== null) {
            throw new InvalidArgumentException('That school year already exists.');
        }

        $startsOn = $this->dateOrNull($payload['starts_on'] ?? null);
        $endsOn = $this->dateOrNull($payload['ends_on'] ?? null);
        if ($startsOn !== null && $endsOn !== null && $startsOn >= $endsOn) {
            throw new InvalidArgumentException('School year start date must be before the end date.');
        }

        $registrationStarts = $this->dateOrNull($payload['registration_starts_on'] ?? null);
        $registrationEnds = $this->dateOrNull($payload['registration_ends_on'] ?? null);
        if ($registrationStarts !== null && $registrationEnds !== null && $registrationStarts > $registrationEnds) {
            throw new InvalidArgumentException('Registration start date must be on or before the registration end date.');
        }
    }

    public function isValidYearName(string $value): bool
    {
        if (! preg_match('/^(\d{4})-(\d{4})$/', $value, $matches)) {
            return false;
        }

        return (int) $matches[2] === (int) $matches[1] + 1;
    }

    private function dateOrNull(mixed $value): ?DateTimeImmutable
    {
        $value = trim((string) $value);
        if ($value === '') {
            return null;
        }

        $date = DateTimeImmutable::createFromFormat('!Y-m-d', $value);
        if (! $date instanceof DateTimeImmutable || $date->format('Y-m-d') !== $value) {
            throw new InvalidArgumentException('Dates must use YYYY-MM-DD.');
        }

        return $date;
    }
}
