<?php

declare(strict_types=1);

namespace App\Administration\Infrastructure\Persistence\InMemory;

use App\Administration\Domain\Exception\GradingConfigurationNotFoundException;
use App\Administration\Domain\Model\GradingConfiguration\SchoolGradingConfiguration;
use App\Administration\Domain\Model\GradingConfiguration\SchoolGradingConfigurationId;
use App\Administration\Domain\Model\SchoolClass\AcademicYearId;
use App\Administration\Domain\Model\SchoolClass\SchoolId;
use App\Administration\Domain\Repository\GradingConfigurationRepository;
use App\Shared\Domain\Tenant\TenantId;
use Override;

final class InMemoryGradingConfigurationRepository implements GradingConfigurationRepository
{
    /** @var array<string, SchoolGradingConfiguration> Indexed by ID */
    private array $byId = [];

    /** @var array<string, SchoolGradingConfiguration> Indexed by tenant:school:year */
    private array $byTenantSchoolYear = [];

    #[Override]
    public function save(SchoolGradingConfiguration $configuration): void
    {
        $idStr = (string) $configuration->id;
        $key = $this->compositeKey($configuration->tenantId, $configuration->schoolId, $configuration->academicYearId);

        $this->byId[$idStr] = $configuration;
        $this->byTenantSchoolYear[$key] = $configuration;
    }

    #[Override]
    public function findBySchoolAndYear(
        TenantId $tenantId,
        SchoolId $schoolId,
        AcademicYearId $academicYearId,
    ): ?SchoolGradingConfiguration {
        return $this->byTenantSchoolYear[$this->compositeKey($tenantId, $schoolId, $academicYearId)] ?? null;
    }

    #[Override]
    public function get(SchoolGradingConfigurationId $id, TenantId $tenantId): SchoolGradingConfiguration
    {
        $config = $this->byId[(string) $id] ?? throw GradingConfigurationNotFoundException::withId($id);

        if (!$config->tenantId->equals($tenantId)) {
            throw GradingConfigurationNotFoundException::withId($id);
        }

        return $config;
    }

    private function compositeKey(TenantId $tenantId, SchoolId $schoolId, AcademicYearId $academicYearId): string
    {
        return $tenantId . ':' . $schoolId . ':' . $academicYearId;
    }
}
