<?php
/**
 * System clock contract.
 *
 * Narrow Domain-layer port that abstracts "what time is it now?"
 * away from PHP's `time()` / `date()` / `new DateTimeImmutable('now')`
 * primitives. Implementations supply the current UTC instant; the
 * production implementation
 * ({@see \Affilun\Infrastructure\Clock\SystemClock}) wraps
 * `new DateTimeImmutable('now', new DateTimeZone('UTC'))`, while
 * test doubles (typically a `FrozenClock` carrying a fixed
 * `DateTimeImmutable`) let unit tests drive timestamp-dependent code
 * paths deterministically.
 *
 * Design notes:
 *
 *   - The contract is a one-method port. The single
 *     {@see self::now()} surface is the only operation provider
 *     implementations and the sync layer need; broader date / time
 *     utilities (formatting, arithmetic, timezone conversion) belong
 *     on the {@see \DateTimeImmutable} value the port returns, not
 *     on this interface.
 *
 *   - The returned value MUST be a UTC `\DateTimeImmutable`. The
 *     entire AFFILUN Domain layer canonicalizes timestamps to UTC at
 *     every storage and equality boundary (per
 *     {@see \Affilun\Infrastructure\Persistence\ProductRecord},
 *     {@see \Affilun\Domain\Pricing\PriceInfo},
 *     {@see \Affilun\Domain\Product\ProductSnapshot},
 *     etc.); a clock that returned a local-timezone instant would
 *     force every downstream call site to re-normalize, defeating
 *     the purpose of having a clock port at all.
 *
 *   - The contract gives no guarantee about clock resolution
 *     beyond what `\DateTimeImmutable` carries (microsecond
 *     precision on most modern PHP builds). Implementations MAY
 *     return cached values on repeated calls within a single
 *     "tick" — typical for test doubles — but production
 *     implementations SHOULD return a fresh instant per call so
 *     downstream observers can detect monotonic progress.
 *
 *   - Implementations live outside the Domain layer per
 *     `specifications/coding-standards.md` §1.3 B
 *     ("Domain / Application 層に WordPress 関数を直接持ち込ま
 *     ない"). The production
 *     {@see \Affilun\Infrastructure\Clock\SystemClock}
 *     does not depend on WordPress either, but the convention
 *     places concrete adapter classes in `Infrastructure/` so a
 *     future timezone-aware variant or a test-double registry can
 *     slot in without touching the Domain layer.
 *
 *   - The contract is consumed primarily by:
 *
 *       * Provider implementations (Phase 4+) that stamp
 *         {@see \Affilun\Domain\Product\ProductSnapshot::fetchedAt()}
 *         and {@see \Affilun\Domain\Pricing\PriceInfo::observedAt()}
 *         from the clock so each fetch produces a self-consistent
 *         observation timestamp.
 *
 *       * Sync workers (Phase 9) that consult the clock for
 *         "now" when deciding whether a snapshot's fetchedAt is
 *         past its TTL, and that stamp
 *         {@see \Affilun\Infrastructure\Persistence\SyncJobRecord}
 *         transitions (lockedAt, finishedAt) from it.
 *
 *       * Diagnostics surfaces and audit-log writers that need a
 *         deterministic "what time did this entry happen?" axis
 *         independent of the host wall clock.
 *
 *     Each consumer accepts the {@see Clock} via constructor
 *     injection so a test can swap in a frozen variant without
 *     binding to the production implementation.
 *
 * @package Affilun\Domain
 */

declare(strict_types=1);

namespace Affilun\Domain;

use DateTimeImmutable;

/**
 * Abstract "what time is it now?" port.
 *
 * See the file-level docblock for the UTC normalization rule, the
 * single-method scope, and the consumer pattern that binds Phase 4+
 * provider implementations and Phase 9 sync workers to this
 * interface rather than to PHP's built-in time primitives.
 */
interface Clock {

	/**
	 * Current UTC instant.
	 *
	 * Implementations MUST return a {@see \DateTimeImmutable} whose
	 * timezone is UTC. Production implementations SHOULD return a
	 * fresh instant per call so downstream observers can detect
	 * monotonic progress; test doubles MAY return a cached / frozen
	 * value for deterministic timestamping.
	 *
	 * Repeated calls within a single transaction are NOT required
	 * to return the same instant; consumers that need a stable
	 * "fetch this once, stamp it everywhere" timestamp call
	 * {@see self::now()} once at the boundary and forward the
	 * resulting value to every downstream operation rather than
	 * re-reading the clock.
	 *
	 * @return DateTimeImmutable Current UTC instant.
	 */
	public function now(): DateTimeImmutable;
}
