<?php
/**
 * Immutable launch version.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Domain\Launch;

use ScheduledChanges\Domain\Shared\UtcTimestamp;

/**
 * Persistence identity and creator metadata for an operation plan.
 */
final class LaunchVersion {
	private ?int $id;
	private int $launchId;
	private int $versionNumber;
	private OperationPlan $plan;
	private int $creatorId;
	private UtcTimestamp $createdAt;
	private string $status              = LaunchVersionStatus::DRAFT;
	private ?int $actionSchedulerId     = null;
	private ?UtcTimestamp $scheduledAt  = null;
	private ?UtcTimestamp $supersededAt = null;
	private string $role                = LaunchVersionRole::START;
	private ?int $linkedVersionId       = null;
	public function __construct(
		?int $id,
		int $launchId,
		int $versionNumber,
		OperationPlan $plan,
		int $creatorId,
		UtcTimestamp $createdAt,
		string $status = LaunchVersionStatus::DRAFT,
		?int $actionSchedulerId = null,
		?UtcTimestamp $scheduledAt = null,
		?UtcTimestamp $supersededAt = null,
		string $role = LaunchVersionRole::START,
		?int $linkedVersionId = null
	) {
		$this->id                = $id;
		$this->launchId          = $launchId;
		$this->versionNumber     = $versionNumber;
		$this->plan              = $plan;
		$this->creatorId         = $creatorId;
		$this->createdAt         = $createdAt;
		$this->status            = $status;
		$this->actionSchedulerId = $actionSchedulerId;
		$this->scheduledAt       = $scheduledAt;
		$this->supersededAt      = $supersededAt;
		$this->role              = $role;
		$this->linkedVersionId   = $linkedVersionId;
		if ( null !== $this->id && $this->id <= 0 ) {
			throw new \InvalidArgumentException( 'Launch version IDs must be positive.' );
		}

		if ( $this->launchId <= 0 || $this->versionNumber <= 0 || $this->creatorId < 0 ) {
			throw new \InvalidArgumentException( 'Launch version identifiers are invalid.' );
		}

		if ( null !== $this->actionSchedulerId && $this->actionSchedulerId <= 0 ) {
			throw new \InvalidArgumentException( 'Action Scheduler IDs must be positive.' );
		}

		if ( null !== $this->linkedVersionId && $this->linkedVersionId <= 0 ) {
			throw new \InvalidArgumentException( 'Linked launch version IDs must be positive.' );
		}

		if ( LaunchVersionRole::END === $this->role && null === $this->linkedVersionId ) {
			throw new \InvalidArgumentException( 'End versions must link to their start version.' );
		}
	}

	public static function create(
		int $launchId,
		int $versionNumber,
		OperationPlan $plan,
		int $creatorId
	): self {
		return new self(
			null,
			$launchId,
			$versionNumber,
			$plan,
			$creatorId,
			UtcTimestamp::now()
		);
	}

	public static function createEnd(
		int $launchId,
		int $versionNumber,
		OperationPlan $plan,
		int $creatorId,
		int $linkedVersionId
	): self {
		return new self(
			null,
			$launchId,
			$versionNumber,
			$plan,
			$creatorId,
			UtcTimestamp::now(),
			LaunchVersionStatus::DRAFT,
			null,
			null,
			null,
			LaunchVersionRole::END,
			$linkedVersionId
		);
	}

	public function id(): ?int {
		return $this->id;
	}

	public function launchId(): int {
		return $this->launchId;
	}

	public function versionNumber(): int {
		return $this->versionNumber;
	}

	public function plan(): OperationPlan {
		return $this->plan;
	}

	public function creatorId(): int {
		return $this->creatorId;
	}

	public function createdAt(): UtcTimestamp {
		return $this->createdAt;
	}

	public function status(): string {
		return $this->status;
	}

	public function actionSchedulerId(): ?int {
		return $this->actionSchedulerId;
	}

	/**
	 * Returns the queued Action Scheduler fire time, not the logical occurrence.
	 */
	public function scheduledAt(): ?UtcTimestamp {
		return $this->scheduledAt;
	}

	public function supersededAt(): ?UtcTimestamp {
		return $this->supersededAt;
	}

	public function role(): string {
		return $this->role;
	}

	public function linkedVersionId(): ?int {
		return $this->linkedVersionId;
	}
}
