<?php
/**
 * System clock implementation.
 *
 * Production {@see \Affilun\Domain\Clock} implementation
 * that returns the host system's current UTC instant on every
 * {@see self::now()} call. The class is the canonical answer to
 * "what time is it?" for every Phase 4+ provider implementation and
 * Phase 9 sync worker that takes a {@see \Affilun\Domain\Clock}
 * via constructor injection.
 *
 * Design notes:
 *
 *   - The implementation is deliberately minimal: every call to
 *     {@see self::now()} constructs a fresh
 *     {@see \DateTimeImmutable} from the `now` symbolic timestamp
 *     in the UTC timezone. No caching, no monotonic-clock fallback,
 *     no NTP integration — the host's wall clock is the source of
 *     truth, and downstream observers are responsible for tolerating
 *     normal clock drift.
 *
 *   - The class extends nothing and depends on no WordPress symbols.
 *     This keeps it loadable in pure-unit test environments and
 *     portable to non-WordPress hosts (CLI workers, future PSR-3
 *     loggers) without rewriting call sites.
 *
 *   - The {@see \DateTimeImmutable} returned by every call is fresh
 *     — successive calls produce instances with strictly monotonic
 *     timestamps under normal conditions, matching the
 *     {@see \Affilun\Domain\Clock} contract's
 *     "production implementations SHOULD return a fresh instant per
 *     call" guidance. Tests that need a frozen / deterministic
 *     instant should swap in a test double rather than reach for
 *     this class.
 *
 *   - Construction is parameterless. There is no per-instance state
 *     to configure: the timezone is hard-coded to UTC per the
 *     {@see \Affilun\Domain\Clock} contract, and the
 *     "now" axis is implicit. Tests that want to drive
 *     timestamp-dependent code paths construct a `FrozenClock`
 *     (typically inline in the test file) rather than configuring
 *     this class.
 *
 *   - The class is final so a future regression that subclasses
 *     this implementation to "override" {@see self::now()} for
 *     test purposes cannot accidentally land in production. The
 *     {@see \Affilun\Domain\Clock} interface is the
 *     extension point; substitute a different implementation,
 *     never extend this one.
 *
 * @package Affilun\Infrastructure\Clock
 */

declare(strict_types=1);

namespace Affilun\Infrastructure\Clock;

use Affilun\Domain\Clock;
use DateTimeImmutable;
use DateTimeZone;

/**
 * Production {@see Clock} implementation that returns the host
 * system's current UTC instant on every {@see self::now()} call.
 *
 * See the file-level docblock for the UTC-only contract, the
 * fresh-instant-per-call guarantee, and the rationale for keeping
 * the class final and parameterless.
 */
final class SystemClock implements Clock {

	/**
	 * Cached UTC timezone instance reused across {@see self::now()}
	 * calls.
	 *
	 * Constructing a fresh `DateTimeZone('UTC')` per call would
	 * incur a small but unnecessary allocation cost on hot paths
	 * (the sync worker calls the clock several times per job).
	 * Holding a single instance keeps the per-call work bounded to
	 * the {@see DateTimeImmutable} construction itself.
	 */
	private DateTimeZone $utc;

	/**
	 * Construct a new {@see SystemClock}.
	 *
	 * The constructor is parameterless because the implementation
	 * has no configurable axes — UTC is the contractual timezone
	 * and "now" is the only supported instant. The
	 * {@see DateTimeZone} is constructed eagerly so subsequent
	 * {@see self::now()} calls do not pay the lookup cost.
	 */
	public function __construct() {
		$this->utc = new DateTimeZone( 'UTC' );
	}

	/**
	 * Return the host system's current UTC instant.
	 *
	 * Each call constructs a fresh {@see DateTimeImmutable} from
	 * the `now` symbolic timestamp in UTC. No caching, no monotonic
	 * fallback — successive calls observe the wall clock as it
	 * advances.
	 *
	 * The returned instance is independent of every prior call's
	 * return value, so callers can mutate it via the immutable
	 * {@see DateTimeImmutable} `with*()` methods without affecting
	 * subsequent {@see self::now()} results.
	 */
	public function now(): DateTimeImmutable {
		return new DateTimeImmutable( 'now', $this->utc );
	}
}
