<?php
/**
 * Recording clone lifecycle context.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Recording;

use ScheduledChanges\Domain\Shared\Uuid;

/**
 * Immutable context passed to public recording clone lifecycle strategies.
 */
final class RecordingCloneContext {
	private Uuid $session_uuid;
	private int $source_product_id;
	private int $shadow_product_id;
	private int $owner_id;
	/**
	 * @var array<string,mixed>
	 */
	private array $variation_map;
	private string $phase;
	private string $product_type;
	/**
	 * @var array<string,mixed>
	 */
	private array $placeholder_map;
	private string $cleanup_policy;

	/**
	 * @param array<string,mixed> $variation_map Source/shadow variation mapping.
	 * @param array<string,mixed> $placeholder_map Unique placeholder mapping.
	 */
	public function __construct(
		Uuid $session_uuid,
		int $source_product_id,
		int $shadow_product_id,
		int $owner_id,
		array $variation_map = array(),
		string $phase = 'clone',
		string $product_type = '',
		array $placeholder_map = array(),
		string $cleanup_policy = 'delete_shadow'
	) {
		if ( $source_product_id <= 0 ) {
			throw new \InvalidArgumentException( 'Source product ID must be positive.' );
		}

		if ( $shadow_product_id <= 0 ) {
			throw new \InvalidArgumentException( 'Shadow product ID must be positive.' );
		}

		if ( $owner_id <= 0 ) {
			throw new \InvalidArgumentException( 'Recording owner ID must be positive.' );
		}

		$this->session_uuid      = $session_uuid;
		$this->source_product_id = $source_product_id;
		$this->shadow_product_id = $shadow_product_id;
		$this->owner_id          = $owner_id;
		$this->variation_map     = $variation_map;
		$this->phase             = $this->normalizeToken( $phase, 'clone' );
		$this->product_type      = $this->normalizeToken( $product_type, 'unknown' );
		$this->placeholder_map   = $placeholder_map;
		$this->cleanup_policy    = $this->normalizeToken( $cleanup_policy, 'delete_shadow' );
	}

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

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

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

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

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

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

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

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

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

	/**
	 * @return array<string,int>
	 */
	public function sourceToShadowVariationMap(): array {
		return $this->normalizeIdMap( $this->variation_map['source_to_shadow'] ?? array() );
	}

	/**
	 * @return array<string,int>
	 */
	public function shadowToSourceVariationMap(): array {
		return $this->normalizeIdMap( $this->variation_map['shadow_to_source'] ?? array() );
	}

	/**
	 * @param mixed $map Raw map.
	 * @return array<string,int>
	 */
	private function normalizeIdMap( $map ): array {
		if ( ! is_array( $map ) ) {
			return array();
		}

		$normalized = array();

		foreach ( $map as $source_id => $target_id ) {
			$target_id = (int) $target_id;

			if ( $target_id <= 0 ) {
				continue;
			}

			$normalized[ (string) $source_id ] = $target_id;
		}

		return $normalized;
	}

	private function normalizeToken( string $value, string $fallback ): string {
		$value = sanitize_key( $value );

		return '' === $value ? $fallback : $value;
	}
}
