<?php

declare(strict_types=1);

namespace App\Administration\Infrastructure\Persistence\InMemory;

use App\Administration\Domain\Exception\ActivationTokenNotFoundException;
use App\Administration\Domain\Model\ActivationToken\ActivationToken;
use App\Administration\Domain\Model\ActivationToken\ActivationTokenId;
use App\Administration\Domain\Repository\ActivationTokenRepository;
use Override;

final class InMemoryActivationTokenRepository implements ActivationTokenRepository
{
    /** @var array<string, ActivationToken> Indexed by token value */
    private array $byTokenValue = [];

    /** @var array<string, string> Maps ID to token value */
    private array $idToTokenValue = [];

    #[Override]
    public function save(ActivationToken $token): void
    {
        $this->byTokenValue[$token->tokenValue] = $token;
        $this->idToTokenValue[(string) $token->id] = $token->tokenValue;
    }

    #[Override]
    public function findByTokenValue(string $tokenValue): ?ActivationToken
    {
        return $this->byTokenValue[$tokenValue] ?? null;
    }

    #[Override]
    public function get(ActivationTokenId $id): ActivationToken
    {
        $tokenValue = $this->idToTokenValue[(string) $id] ?? null;

        if ($tokenValue === null) {
            throw ActivationTokenNotFoundException::withId($id);
        }

        $token = $this->byTokenValue[$tokenValue] ?? null;

        if ($token === null) {
            throw ActivationTokenNotFoundException::withId($id);
        }

        return $token;
    }

    #[Override]
    public function delete(ActivationTokenId $id): void
    {
        $tokenValue = $this->idToTokenValue[(string) $id] ?? null;

        if ($tokenValue !== null) {
            unset($this->byTokenValue[$tokenValue]);
        }

        unset($this->idToTokenValue[(string) $id]);
    }

    #[Override]
    public function deleteByTokenValue(string $tokenValue): void
    {
        $token = $this->byTokenValue[$tokenValue] ?? null;

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

        unset($this->byTokenValue[$tokenValue]);
    }
}
