<?php
/**
 * Launch execution outcome.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Execution;

use ScheduledChanges\Domain\Run\FailureClassification;
use ScheduledChanges\Domain\Run\RunStatus;

/**
 * Aggregated result for one bounded execution attempt.
 */
final class ExecutionOutcome {
	private string $status;
	private int $successfulCount;
	private int $skippedCount;
	private int $failedCount;
	private ?string $retryClassification;
	/**
	 * @var array<string, mixed>
	 */
	private array $summary;
	/**
	 * @var array{mutated:bool,blocking_conflict:bool,skipped_conflict:bool,failures:bool,warnings:bool,operator_intervention:bool,retry_eligible:bool,lifecycle_classification:?string}
	 */
	private array $semantics;
	/**
	 * @param array<string,mixed> $summary Redacted execution summary.
	 * @param array<string,mixed> $semantics Lifecycle semantic flags.
	 */
	public function __construct(
		string $status,
		int $successfulCount,
		int $skippedCount,
		int $failedCount,
		?string $retryClassification,
		array $summary,
		array $semantics = array()
	) {
		$this->status              = $status;
		$this->successfulCount     = $successfulCount;
		$this->skippedCount        = $skippedCount;
		$this->failedCount         = $failedCount;
		$this->retryClassification = $retryClassification;
		$this->summary             = $summary;
		$this->semantics           = array_merge(
			array(
				'mutated'                  => $successfulCount > 0,
				'blocking_conflict'        => false,
				'skipped_conflict'         => false,
				'failures'                 => $failedCount > 0,
				'warnings'                 => false,
				'operator_intervention'    => false,
				'retry_eligible'           => null !== $retryClassification,
				'lifecycle_classification' => null,
			),
			$semantics
		);
		if ( $successfulCount < 0 || $skippedCount < 0 || $failedCount < 0 ) {
			throw new \InvalidArgumentException( 'Execution outcome counts cannot be negative.' );
		}
	}

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

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

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

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

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

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

	public function mutated(): bool {
		return $this->semantics['mutated'];
	}

	public function blockingConflict(): bool {
		return $this->semantics['blocking_conflict'];
	}

	public function skippedConflict(): bool {
		return $this->semantics['skipped_conflict'];
	}

	public function failures(): bool {
		return $this->semantics['failures'];
	}

	public function warnings(): bool {
		return $this->semantics['warnings'];
	}

	public function operatorInterventionRequired(): bool {
		return $this->semantics['operator_intervention'];
	}

	public function retryEligible(): bool {
		return $this->semantics['retry_eligible'];
	}

	public function lifecycleClassification(): ?string {
		return $this->semantics['lifecycle_classification'];
	}
}
