<?php
/**
 * Single-item lookup cache port.
 *
 * Phase 9 cache surface for provider single-item lookup
 * payloads, keyed by the canonical lookup key produced by
 * {@see \Affilun\Application\Cache\CacheKeyFactory::lookupKey()}.
 * Implementations back the cache layer described in
 * `specifications/sync-and-cache-strategy.md` §4 (cache layers)
 * and §6.3 (cache-key forms).
 *
 * The payload is a normalized provider lookup result whose
 * concrete shape is caller-defined: this port treats it as an
 * opaque associative array so a future evolution of the
 * normalized lookup shape does not force changes to every cache
 * adapter. Callers serialize on write and receive the same array
 * back on hit.
 *
 * Eviction is TTL-driven: writes carry an explicit TTL in
 * seconds; reads return null on miss or once the entry's TTL
 * has elapsed. The clock used to apply the TTL is wired into
 * the implementation (typically a
 * {@see \Affilun\Domain\Clock}), not into this
 * port, so consumers do not have to thread "now" through every
 * call.
 *
 * @package Affilun\Application\Cache
 */

declare(strict_types=1);

namespace Affilun\Application\Cache;

use InvalidArgumentException;

/**
 * Phase 9 single-item lookup cache contract.
 *
 * See the file-level docblock for the spec citations, the
 * payload-opacity rule, and the TTL semantics that gate
 * {@see self::get()} hits.
 */
interface LookupCache {

	/**
	 * Read the lookup payload stored under `$key`.
	 *
	 * Returns null on miss, on expiry, or when the implementation
	 * has had its layer flushed since the entry was written.
	 *
	 * @param string $key Cache key, typically produced by
	 *                    {@see CacheKeyFactory::lookupKey()}.
	 *
	 * @return array<string, mixed>|null Cached payload, or null on miss / expired.
	 */
	public function get( string $key ): ?array;

	/**
	 * Write the lookup payload under `$key` with the given TTL
	 * in seconds.
	 *
	 * Implementations MUST reject `$ttlSeconds <= 0` with
	 * {@see \InvalidArgumentException}; a non-positive TTL has no
	 * meaningful semantics for this layer (it would either store
	 * an entry that is born expired or invite a "store forever"
	 * misinterpretation that the spec deliberately does not grant).
	 *
	 * @param string               $key        Cache key.
	 * @param array<string, mixed> $payload    Normalized provider lookup result;
	 *                                         caller-defined shape.
	 * @param int                  $ttlSeconds TTL in seconds; must be > 0.
	 *
	 * @throws InvalidArgumentException When `$ttlSeconds` is non-positive.
	 */
	public function put( string $key, array $payload, int $ttlSeconds ): void;

	/**
	 * Remove the entry stored under `$key`.
	 *
	 * Idempotent: a call against an unknown key is a no-op.
	 *
	 * @param string $key Cache key.
	 */
	public function forget( string $key ): void;

	/**
	 * Drop every entry stored in this cache layer.
	 *
	 * Scope is the layer instance, not the underlying store; if
	 * an implementation shares storage with another layer, the
	 * shared backend MUST still partition entries so flushing
	 * one layer does not also drop a sibling layer's entries.
	 */
	public function flush(): void;
}
