<?php
/**
 * Execution run aggregate.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Domain\Run;

use ScheduledChanges\Domain\Shared\UtcTimestamp;
use ScheduledChanges\Domain\Shared\Uuid;

/**
 * One durable execution attempt for an immutable launch version.
 */
final class Run {
	private ?int $id;
	private Uuid $uuid;
	private int $launchId;
	private int $launchVersionId;
	private ?int $actionSchedulerId;
	private string $triggerSource;
	private int $attemptNumber;
	private ?UtcTimestamp $scheduledAt;
	private ?UtcTimestamp $startedAt;
	private ?UtcTimestamp $completedAt;
	private string $status;
	private ?string $lockToken;
	private ?string $environmentFingerprint;
	/**
	 * @var array<string, mixed>
	 */
	private array $validation;
	/**
	 * @var array<string, mixed>
	 */
	private array $result;
	private int $warningCount;
	private int $errorCount;
	private ?int $rollbackRunId = null;
	/**
	 * @param array<string,mixed> $validation Validation report.
	 * @param array<string,mixed> $result Execution summary.
	 */
	public function __construct(
		?int $id,
		Uuid $uuid,
		int $launchId,
		int $launchVersionId,
		?int $actionSchedulerId,
		string $triggerSource,
		int $attemptNumber,
		?UtcTimestamp $scheduledAt,
		?UtcTimestamp $startedAt,
		?UtcTimestamp $completedAt,
		string $status,
		?string $lockToken,
		?string $environmentFingerprint,
		array $validation,
		array $result,
		int $warningCount,
		int $errorCount,
		?int $rollbackRunId = null
	) {
		$this->id                     = $id;
		$this->uuid                   = $uuid;
		$this->launchId               = $launchId;
		$this->launchVersionId        = $launchVersionId;
		$this->actionSchedulerId      = $actionSchedulerId;
		$this->triggerSource          = $triggerSource;
		$this->attemptNumber          = $attemptNumber;
		$this->scheduledAt            = $scheduledAt;
		$this->startedAt              = $startedAt;
		$this->completedAt            = $completedAt;
		$this->status                 = $status;
		$this->lockToken              = $lockToken;
		$this->environmentFingerprint = $environmentFingerprint;
		$this->validation             = $validation;
		$this->result                 = $result;
		$this->warningCount           = $warningCount;
		$this->errorCount             = $errorCount;
		$this->rollbackRunId          = $rollbackRunId;
		if ( null !== $this->id && $this->id <= 0 ) {
			throw new \InvalidArgumentException( 'Run IDs must be positive.' );
		}

		if ( $this->launchId <= 0 || $this->launchVersionId <= 0 || $this->attemptNumber <= 0 ) {
			throw new \InvalidArgumentException( 'Run launch, version, and attempt identifiers must be positive.' );
		}

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

		if ( $this->warningCount < 0 || $this->errorCount < 0 ) {
			throw new \InvalidArgumentException( 'Run warning and error counts cannot be negative.' );
		}
	}

	public static function pending(
		int $launchId,
		int $launchVersionId,
		?int $actionSchedulerId,
		string $triggerSource,
		int $attemptNumber,
		?UtcTimestamp $scheduledAt,
		string $lockToken,
		string $environmentFingerprint
	): self {
		return new self(
			null,
			Uuid::generate(),
			$launchId,
			$launchVersionId,
			$actionSchedulerId,
			$triggerSource,
			$attemptNumber,
			$scheduledAt,
			null,
			null,
			RunStatus::PENDING,
			$lockToken,
			$environmentFingerprint,
			array(),
			array(),
			0,
			0
		);
	}

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

	public function uuid(): Uuid {
		return $this->uuid;
	}

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

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

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

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

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

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

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

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

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

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

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

	/**
	 * @return array<string,mixed>
	 */
	public function validation(): array {
		return $this->validation;
	}

	/**
	 * @return array<string,mixed>
	 */
	public function result(): array {
		return $this->result;
	}

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

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

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