<?php
/**
 * Launch aggregate.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Domain\Launch;

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

/**
 * User-facing schedule container.
 */
final class Launch {
	private ?int $id;
	private Uuid $uuid;
	private string $name;
	private string $description;
	private int $owner_id;
	private string $status;
	private NamedTimezone $timezone;
	private ?UtcTimestamp $start_at;
	private ?UtcTimestamp $end_at;
	private ?string $recurrence_rule;
	private ?int $current_version_id;
	private string $conflict_policy;
	private string $failure_policy;
	private string $creation_source;
	private UtcTimestamp $created_at;
	private UtcTimestamp $updated_at;
	private ?UtcTimestamp $scheduled_at;
	private ?UtcTimestamp $completed_at;
	/**
	 * Creates a launch.
	 *
	 * @param int|null          $id Internal ID.
	 * @param Uuid              $uuid Public UUID.
	 * @param string            $name Launch name.
	 * @param string            $description Launch description.
	 * @param int               $owner_id Owner user ID.
	 * @param string            $status Lifecycle status.
	 * @param NamedTimezone     $timezone Display timezone.
	 * @param UtcTimestamp|null $start_at Start time.
	 * @param UtcTimestamp|null $end_at End time.
	 * @param string|null       $recurrence_rule Recurrence rule.
	 * @param int|null          $current_version_id Current immutable version.
	 * @param string            $conflict_policy Default conflict policy.
	 * @param string            $failure_policy Failure policy.
	 * @param string            $creation_source Creation source.
	 * @param UtcTimestamp      $created_at Creation time.
	 * @param UtcTimestamp      $updated_at Update time.
	 * @param UtcTimestamp|null $scheduled_at Scheduled time.
	 * @param UtcTimestamp|null $completed_at Completion time.
	 */
	public function __construct(
		?int $id,
		Uuid $uuid,
		string $name,
		string $description,
		int $owner_id,
		string $status,
		NamedTimezone $timezone,
		?UtcTimestamp $start_at,
		?UtcTimestamp $end_at,
		?string $recurrence_rule,
		?int $current_version_id,
		string $conflict_policy,
		string $failure_policy,
		string $creation_source,
		UtcTimestamp $created_at,
		UtcTimestamp $updated_at,
		?UtcTimestamp $scheduled_at,
		?UtcTimestamp $completed_at
	) {
		$this->id                 = $id;
		$this->uuid               = $uuid;
		$this->name               = $name;
		$this->description        = $description;
		$this->owner_id           = $owner_id;
		$this->status             = $status;
		$this->timezone           = $timezone;
		$this->start_at           = $start_at;
		$this->end_at             = $end_at;
		$this->recurrence_rule    = $recurrence_rule;
		$this->current_version_id = $current_version_id;
		$this->conflict_policy    = $conflict_policy;
		$this->failure_policy     = $failure_policy;
		$this->creation_source    = $creation_source;
		$this->created_at         = $created_at;
		$this->updated_at         = $updated_at;
		$this->scheduled_at       = $scheduled_at;
		$this->completed_at       = $completed_at;
		$name_length              = function_exists( 'mb_strlen' ) ? mb_strlen( $name ) : strlen( $name );

		if ( '' === trim( $name ) || $name_length > 191 ) {
			throw new \InvalidArgumentException( 'Launch name must contain 1 to 191 characters.' );
		}

		if ( $owner_id < 0 ) {
			throw new \InvalidArgumentException( 'Launch owner ID cannot be negative.' );
		}

		if ( null !== $start_at && null !== $end_at && $end_at->native() <= $start_at->native() ) {
			throw new \InvalidArgumentException( 'Launch end time must be after its start time.' );
		}
	}

	/**
	 * Creates a new draft launch.
	 *
	 * @param string        $name Launch name.
	 * @param string        $description Launch description.
	 * @param int           $owner_id Owner user ID.
	 * @param NamedTimezone $timezone Display timezone.
	 * @param string        $source Creation source.
	 */
	public static function draft(
		string $name,
		string $description,
		int $owner_id,
		NamedTimezone $timezone,
		string $source
	): self {
		$now = UtcTimestamp::now();

		return new self(
			null,
			Uuid::generate(),
			$name,
			$description,
			$owner_id,
			LaunchStatus::DRAFT,
			$timezone,
			null,
			null,
			null,
			null,
			ConflictPolicy::FAIL,
			FailurePolicy::STOP,
			$source,
			$now,
			$now,
			null,
			null
		);
	}

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

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

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

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

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

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

	public function timezone(): NamedTimezone {
		return $this->timezone;
	}

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

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

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

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

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

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

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

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

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

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

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