<?php
/**
 * Audit event.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Domain\Audit;

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

/**
 * Append-only structured audit record.
 */
final class AuditEvent {
	private Uuid $uuid;
	private ?int $launch_id;
	private ?int $run_id;
	private int $actor_id;
	private string $event_type;
	private string $severity;
	/**
	 * @var array<string, mixed>
	 */
	private array $context;
	private UtcTimestamp $created_at;
	/**
	 * Creates an event.
	 *
	 * @param Uuid                $uuid Event UUID.
	 * @param int|null            $launch_id Related launch.
	 * @param int|null            $run_id Related run.
	 * @param int                 $actor_id Actor user ID.
	 * @param string              $event_type Stable event type.
	 * @param string              $severity Severity.
	 * @param array<string,mixed> $context Redacted event context.
	 * @param UtcTimestamp        $created_at Event time.
	 */
	public function __construct(
		Uuid $uuid,
		?int $launch_id,
		?int $run_id,
		int $actor_id,
		string $event_type,
		string $severity,
		array $context,
		UtcTimestamp $created_at
	) {
		$this->uuid       = $uuid;
		$this->launch_id  = $launch_id;
		$this->run_id     = $run_id;
		$this->actor_id   = $actor_id;
		$this->event_type = $event_type;
		$this->severity   = $severity;
		$this->context    = $context;
		$this->created_at = $created_at;
		if ( '' === trim( $event_type ) || strlen( $event_type ) > 64 ) {
			throw new \InvalidArgumentException( 'Audit event type must contain 1 to 64 characters.' );
		}
	}

	/**
	 * Creates a current-time informational event.
	 *
	 * @param string              $event_type Event type.
	 * @param int                 $actor_id Actor user ID.
	 * @param array<string,mixed> $context Event context.
	 * @param int|null            $launch_id Launch ID.
	 */
	public static function info(
		string $event_type,
		int $actor_id,
		array $context = array(),
		?int $launch_id = null
	): self {
		return new self(
			Uuid::generate(),
			$launch_id,
			null,
			$actor_id,
			$event_type,
			AuditSeverity::INFO,
			$context,
			UtcTimestamp::now()
		);
	}

	/**
	 * Creates a current-time warning event.
	 *
	 * @param string              $event_type Event type.
	 * @param int                 $actor_id Actor user ID.
	 * @param array<string,mixed> $context Event context.
	 * @param int|null            $launch_id Launch ID.
	 */
	public static function warning(
		string $event_type,
		int $actor_id,
		array $context = array(),
		?int $launch_id = null
	): self {
		return new self(
			Uuid::generate(),
			$launch_id,
			null,
			$actor_id,
			$event_type,
			AuditSeverity::WARNING,
			$context,
			UtcTimestamp::now()
		);
	}

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

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

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

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

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

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

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

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