<?php
/**
 * Scheduler launch/version terminal lifecycle transitions.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Scheduler;

use ScheduledChanges\Domain\Launch\LaunchStatus;
use ScheduledChanges\Domain\Launch\LaunchVersionRole;
use ScheduledChanges\Domain\Launch\LaunchVersionStatus;
use ScheduledChanges\Domain\Run\RunStatus;
use ScheduledChanges\Domain\Shared\UtcTimestamp;
use ScheduledChanges\Repository\LaunchRepository;
use ScheduledChanges\Repository\LaunchVersionRepository;

/** Coordinates compare-and-set terminal transitions for worker outcomes. */
final class SchedulerLifecycleFinalizer {
	private LaunchRepository $launches;
	private LaunchVersionRepository $versions;

	public function __construct( LaunchRepository $launches, LaunchVersionRepository $versions ) {
		$this->launches = $launches;
		$this->versions = $versions;
	}

	public function finalize( int $launch_id, int $version_id, string $status ): bool {
		$version        = $this->versions->findById( $version_id );
		$status_mapping = $this->statusMapping( $status );
		$launch_status  = $status_mapping['launch'];
		$version_status = $status_mapping['version'];

		if ( ! $this->versions->transitionStatus( $version_id, array( LaunchVersionStatus::RUNNING ), $version_status ) ) {
			return false;
		}

		if (
			in_array( $status, array( RunStatus::SUCCESSFUL, RunStatus::SUCCESSFUL_WITH_WARNINGS ), true )
			&& null !== $version
			&& LaunchVersionRole::START === $version->role()
		) {
			$end_version = $this->versions->findLinkedEndVersion( $version_id );
			if ( null !== $end_version && in_array( $end_version->status(), array( LaunchVersionStatus::SCHEDULED, LaunchVersionStatus::RUNNING ), true ) ) {
				$this->launches->updateStatus( $launch_id, LaunchStatus::SCHEDULED );

				return true;
			}
		}

		$this->launches->updateStatus( $launch_id, $launch_status, UtcTimestamp::now() );

		return true;
	}

	/** @return array{launch:string,version:string} */
	private function statusMapping( string $status ): array {
		switch ( $status ) {
			case RunStatus::SUCCESSFUL:
				return array(
					'launch'  => LaunchStatus::SUCCESSFUL,
					'version' => LaunchVersionStatus::COMPLETED,
				);
			case RunStatus::SUCCESSFUL_WITH_WARNINGS:
				return array(
					'launch'  => LaunchStatus::SUCCESSFUL_WITH_WARNINGS,
					'version' => LaunchVersionStatus::COMPLETED,
				);
			case RunStatus::PARTIALLY_FAILED:
				return array(
					'launch'  => LaunchStatus::PARTIALLY_FAILED,
					'version' => LaunchVersionStatus::FAILED,
				);
			case RunStatus::FAILED:
				return array(
					'launch'  => LaunchStatus::FAILED,
					'version' => LaunchVersionStatus::FAILED,
				);
			case RunStatus::STALE:
				return array(
					'launch'  => LaunchStatus::STALE,
					'version' => LaunchVersionStatus::STALE,
				);
			case RunStatus::DEAD_LETTER:
				return array(
					'launch'  => LaunchStatus::DEAD_LETTER,
					'version' => LaunchVersionStatus::DEAD_LETTER,
				);
			default:
				throw new \InvalidArgumentException( 'Unsupported terminal run status: ' . esc_html( $status ) );
		}
	}
}
