<?php
/**
 * Launch version repository contract.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Repository;

use ScheduledChanges\Domain\Launch\LaunchVersion;
use ScheduledChanges\Domain\Launch\LaunchVersionStatus;
use ScheduledChanges\Domain\Shared\UtcTimestamp;

/**
 * Storage port retained for wpdb and deterministic test implementations.
 * Persists immutable plans and their normalized graph indexes. Finders return
 * `null` for not-found; write and integrity failures throw `RepositoryException`.
 */
interface LaunchVersionRepository {
	/**
	 * Inserts an immutable launch version.
	 *
	 * @param LaunchVersion $version Version to insert.
	 */
	public function create( LaunchVersion $version ): int;

	/**
	 * Finds a version by internal ID.
	 *
	 * @param int $id Internal version ID.
	 */
	public function findById( int $id ): ?LaunchVersion;

	/**
	 * Finds the newest version number for a launch.
	 *
	 * @param int $launch_id Internal launch ID.
	 */
	public function findLatestForLaunch( int $launch_id ): ?LaunchVersion;

	/**
	 * Finds the end version linked to a start version.
	 */
	public function findLinkedEndVersion( int $start_version_id ): ?LaunchVersion;

	/**
	 * Marks a version as the active queued callback document.
	 *
	 * @param int          $id Internal version ID.
	 * @param int          $action_scheduler_id Action Scheduler action ID.
	 * @param UtcTimestamp $fire_at Action Scheduler fire time.
	 * @param UtcTimestamp $occurrence_at Logical occurrence represented by the callback.
	 * @param int          $attempt_number Queue attempt number.
	 * @param string       $trigger_source TriggerSource value.
	 */
	public function markQueuedCallback( int $id, int $action_scheduler_id, UtcTimestamp $fire_at, UtcTimestamp $occurrence_at, int $attempt_number, string $trigger_source ): void;

	/**
	 * Replaces a claimed queued callback only when its current identity matches.
	 *
	 * Used after scheduling a replacement Action Scheduler action so callers can
	 * compensate by canceling the replacement when persistence loses the race.
	 *
	 * @param int          $id Internal version ID.
	 * @param int          $expected_action_scheduler_id Currently claimed action ID.
	 * @param UtcTimestamp $expected_occurrence_at Currently claimed logical occurrence.
	 * @param int          $expected_attempt_number Currently claimed attempt number.
	 * @param string       $expected_trigger_source Currently claimed trigger source.
	 * @param int          $action_scheduler_id Replacement Action Scheduler action ID.
	 * @param UtcTimestamp $fire_at Replacement fire time.
	 * @param UtcTimestamp $occurrence_at Replacement logical occurrence.
	 * @param int          $attempt_number Replacement attempt number.
	 * @param string       $trigger_source Replacement trigger source.
	 */
	public function replaceQueuedCallback( int $id, int $expected_action_scheduler_id, UtcTimestamp $expected_occurrence_at, int $expected_attempt_number, string $expected_trigger_source, int $action_scheduler_id, UtcTimestamp $fire_at, UtcTimestamp $occurrence_at, int $attempt_number, string $trigger_source ): bool;

	/**
	 * Returns active queued callback identities for repair diagnostics.
	 *
	 * @return array<int,array{id:int,status:string,action_scheduler_id:int,occurrence_at_utc:string,attempt_number:int,trigger_source:string}>
	 */
	public function queuedCallbacks(): array;

	/**
	 * Atomically claims the active queued callback before creating a run.
	 *
	 * The predicate must match the queued callback identity exactly. Fire time is
	 * intentionally excluded because retry fire time can differ from occurrence.
	 *
	 * @param int          $id Internal version ID.
	 * @param int          $action_scheduler_id Action Scheduler action ID.
	 * @param UtcTimestamp $occurrence_at Logical occurrence represented by the callback.
	 * @param int          $attempt_number Queue attempt number.
	 * @param string       $trigger_source TriggerSource value.
	 */
	public function claimQueuedCallback( int $id, int $action_scheduler_id, UtcTimestamp $occurrence_at, int $attempt_number, string $trigger_source ): bool;

	/**
	 * Atomically transitions a launch version when its current status is allowed.
	 *
	 * @param int      $id Internal version ID.
	 * @param string[] $expected_statuses Allowed current LaunchVersionStatus values.
	 * @param string   $status New LaunchVersionStatus value.
	 */
	public function transitionStatus( int $id, array $expected_statuses, string $status ): bool;

	/**
	 * Marks a replaced immutable version superseded.
	 */
	public function markSuperseded( int $id, UtcTimestamp $superseded_at ): void;

	/**
	 * Updates mutable execution metadata without changing the plan.
	 */
	public function updateStatus( int $id, string $status ): void;

	/**
	 * Resolves a normalized operation row ID.
	 */
	public function operationId( int $version_id, string $operation_uuid ): ?int;

	/**
	 * Deletes a version and its normalized graph rows.
	 *
	 * Used by explicit cleanup and repeatable fixtures only.
	 *
	 * @param int $id Internal version ID.
	 */
	public function deleteById( int $id ): bool;
}
