<?php

declare(strict_types=1);

namespace App\Scolarite\Infrastructure\Persistence\InMemory;

use App\Administration\Domain\Model\SchoolClass\ClassId;
use App\Administration\Domain\Model\Subject\SubjectId;
use App\Administration\Domain\Model\User\UserId;
use App\Scolarite\Domain\Exception\RemplacementNotFoundException;
use App\Scolarite\Domain\Model\TeacherReplacement\ClassSubjectPair;
use App\Scolarite\Domain\Model\TeacherReplacement\ReplacementStatus;
use App\Scolarite\Domain\Model\TeacherReplacement\TeacherReplacement;
use App\Scolarite\Domain\Model\TeacherReplacement\TeacherReplacementId;
use App\Scolarite\Domain\Repository\TeacherReplacementRepository;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use Override;

final class InMemoryTeacherReplacementRepository implements TeacherReplacementRepository
{
    /** @var array<string, TeacherReplacement> */
    private array $byId = [];

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

    #[Override]
    public function get(TeacherReplacementId $id, TenantId $tenantId): TeacherReplacement
    {
        $replacement = $this->findById($id, $tenantId);

        if ($replacement === null) {
            throw RemplacementNotFoundException::withId($id);
        }

        return $replacement;
    }

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

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

        return $replacement;
    }

    #[Override]
    public function findActiveReplacement(
        UserId $replacementTeacherId,
        ClassId $classId,
        SubjectId $subjectId,
        DateTimeImmutable $at,
        TenantId $tenantId,
    ): ?TeacherReplacement {
        $pair = new ClassSubjectPair($classId, $subjectId);

        foreach ($this->byId as $replacement) {
            if ($replacement->tenantId->equals($tenantId)
                && $replacement->replacementTeacherId->equals($replacementTeacherId)
                && $replacement->isActive($at)
                && $replacement->couvreClasseMatiere($pair)
            ) {
                return $replacement;
            }
        }

        return null;
    }

    #[Override]
    public function findActiveByTenant(TenantId $tenantId, DateTimeImmutable $at): array
    {
        return array_values(array_filter(
            $this->byId,
            static fn (TeacherReplacement $r) => $r->tenantId->equals($tenantId)
                && $r->isActive($at),
        ));
    }

    #[Override]
    public function findActiveByReplacementTeacher(
        UserId $replacementTeacherId,
        TenantId $tenantId,
        DateTimeImmutable $at,
    ): array {
        return array_values(array_filter(
            $this->byId,
            static fn (TeacherReplacement $r) => $r->tenantId->equals($tenantId)
                && $r->replacementTeacherId->equals($replacementTeacherId)
                && $r->isActive($at),
        ));
    }

    #[Override]
    public function findExpired(DateTimeImmutable $at): array
    {
        return array_values(array_filter(
            $this->byId,
            static fn (TeacherReplacement $r) => $r->status === ReplacementStatus::ACTIVE
                && $r->isExpired($at),
        ));
    }
}
