<?php

declare(strict_types=1);

namespace App\Auth;

/**
 * Storage abstraction for {@see LoginThrottle} bucket state.
 *
 * State is two named buckets — `ip` (per-(username, ip) tuple) and
 * `username` (cross-IP per-username) — each an opaque key→entry map.
 * `mutate()` is an atomic read-modify-write; `load()` returns a snapshot
 * for read-only paths.
 *
 * Two implementations exist:
 *   - {@see InMemoryThrottleStore} — single-process, used by unit tests
 *     and as the documented "no-persistence" fallback.
 *   - {@see FileThrottleStore} — flock-protected JSON file on the
 *     container's writable layer. Survives FrankenPHP worker recycling
 *     and is shared across all workers in one container, but is cleared
 *     by container restart (the documented operator-unlock path; see
 *     SEC_REVIEW F6).
 */
interface ThrottleStore
{
    /**
     * @return array{
     *     ip: array<string, array{count: int, lockedUntil: int}>,
     *     username: array<string, array{count: int, lockedUntil: int}>
     * }
     */
    public function load(): array;

    /**
     * Atomic read-modify-write. The callable receives the current state and
     * returns the next state. Implementations MUST serialise concurrent
     * mutations and MUST NOT make partial writes visible to other readers.
     *
     * @param callable(array{
     *     ip: array<string, array{count: int, lockedUntil: int}>,
     *     username: array<string, array{count: int, lockedUntil: int}>
     * }): array{
     *     ip: array<string, array{count: int, lockedUntil: int}>,
     *     username: array<string, array{count: int, lockedUntil: int}>
     * } $fn
     */
    public function mutate(callable $fn): void;

    public function reset(): void;
}
