<?php

declare(strict_types=1);

namespace App\Scolarite\Infrastructure\Persistence\InMemory;

use App\Scolarite\Domain\Model\Schedule\ScheduleException;
use App\Scolarite\Domain\Model\Schedule\ScheduleExceptionId;
use App\Scolarite\Domain\Model\Schedule\ScheduleSlotId;
use App\Scolarite\Domain\Repository\ScheduleExceptionRepository;
use App\Shared\Domain\Tenant\TenantId;

use function array_filter;
use function array_values;

use DateTimeImmutable;
use Override;

final class InMemoryScheduleExceptionRepository implements ScheduleExceptionRepository
{
    /** @var array<string, ScheduleException> */
    private array $byId = [];

    #[Override]
    public function save(ScheduleException $exception): void
    {
        $this->byId[(string) $exception->id] = $exception;
    }

    #[Override]
    public function findById(ScheduleExceptionId $id, TenantId $tenantId): ?ScheduleException
    {
        $exception = $this->byId[(string) $id] ?? null;

        if ($exception !== null && !$exception->tenantId->equals($tenantId)) {
            return null;
        }

        return $exception;
    }

    #[Override]
    public function findForSlotAndDate(
        ScheduleSlotId $slotId,
        DateTimeImmutable $date,
        TenantId $tenantId,
    ): ?ScheduleException {
        $dateStr = $date->format('Y-m-d');

        foreach ($this->byId as $exception) {
            if ($exception->tenantId->equals($tenantId)
                && $exception->slotId->equals($slotId)
                && $exception->exceptionDate->format('Y-m-d') === $dateStr
            ) {
                return $exception;
            }
        }

        return null;
    }

    #[Override]
    public function findForSlotBetweenDates(
        ScheduleSlotId $slotId,
        DateTimeImmutable $startDate,
        DateTimeImmutable $endDate,
        TenantId $tenantId,
    ): array {
        $start = $startDate->format('Y-m-d');
        $end = $endDate->format('Y-m-d');

        return array_values(array_filter(
            $this->byId,
            static fn (ScheduleException $e): bool => $e->tenantId->equals($tenantId)
                && $e->slotId->equals($slotId)
                && $e->exceptionDate->format('Y-m-d') >= $start
                && $e->exceptionDate->format('Y-m-d') <= $end,
        ));
    }

    #[Override]
    public function findForDateRange(
        TenantId $tenantId,
        DateTimeImmutable $startDate,
        DateTimeImmutable $endDate,
    ): array {
        $start = $startDate->format('Y-m-d');
        $end = $endDate->format('Y-m-d');

        return array_values(array_filter(
            $this->byId,
            static fn (ScheduleException $e): bool => $e->tenantId->equals($tenantId)
                && $e->exceptionDate->format('Y-m-d') >= $start
                && $e->exceptionDate->format('Y-m-d') <= $end,
        ));
    }

    #[Override]
    public function delete(ScheduleExceptionId $id, TenantId $tenantId): void
    {
        $exception = $this->findById($id, $tenantId);

        if ($exception !== null) {
            unset($this->byId[(string) $id]);
        }
    }
}
