<?php

declare(strict_types=1);

namespace App\Administration\Infrastructure\Persistence\InMemory;

use App\Administration\Domain\Exception\StudentGuardianNotFoundException;
use App\Administration\Domain\Model\StudentGuardian\StudentGuardian;
use App\Administration\Domain\Model\StudentGuardian\StudentGuardianId;
use App\Administration\Domain\Model\User\UserId;
use App\Administration\Domain\Repository\StudentGuardianRepository;
use App\Shared\Domain\Tenant\TenantId;

use function count;

use Override;

final class InMemoryStudentGuardianRepository implements StudentGuardianRepository
{
    /** @var array<string, StudentGuardian> */
    private array $byId = [];

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

    #[Override]
    public function get(StudentGuardianId $id, TenantId $tenantId): StudentGuardian
    {
        $link = $this->byId[(string) $id] ?? null;

        if ($link === null || !$link->tenantId->equals($tenantId)) {
            throw StudentGuardianNotFoundException::withId($id);
        }

        return $link;
    }

    #[Override]
    public function findGuardiansForStudent(UserId $studentId, TenantId $tenantId): array
    {
        return array_values(array_filter(
            $this->byId,
            static fn (StudentGuardian $link) => $link->studentId->equals($studentId)
                && $link->tenantId->equals($tenantId),
        ));
    }

    #[Override]
    public function findStudentsForGuardian(UserId $guardianId, TenantId $tenantId): array
    {
        return array_values(array_filter(
            $this->byId,
            static fn (StudentGuardian $link) => $link->guardianId->equals($guardianId)
                && $link->tenantId->equals($tenantId),
        ));
    }

    #[Override]
    public function countGuardiansForStudent(UserId $studentId, TenantId $tenantId): int
    {
        return count($this->findGuardiansForStudent($studentId, $tenantId));
    }

    #[Override]
    public function findByStudentAndGuardian(
        UserId $studentId,
        UserId $guardianId,
        TenantId $tenantId,
    ): ?StudentGuardian {
        foreach ($this->byId as $link) {
            if ($link->studentId->equals($studentId)
                && $link->guardianId->equals($guardianId)
                && $link->tenantId->equals($tenantId)) {
                return $link;
            }
        }

        return null;
    }

    #[Override]
    public function delete(StudentGuardianId $id, TenantId $tenantId): void
    {
        unset($this->byId[(string) $id]);
    }
}
