<?php
/**
 * Declarative taxonomy capability registration.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Taxonomy;

// phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception messages are escaped at UI boundaries.

/**
 * Describes one provider-owned taxonomy assignment capability.
 */
final class TaxonomyRegistration {
	private string $id;
	private string $provider_id;
	private string $taxonomy;
	/** @var string[] */
	private array $target_types;
	private string $label;
	private string $capability;
	private bool $hierarchical;
	private bool $term_creation;

	/**
	 * @param string[] $target_types Supported target types.
	 */
	public function __construct(
		string $id,
		string $provider_id,
		string $taxonomy,
		array $target_types,
		string $label,
		string $capability,
		bool $hierarchical,
		bool $term_creation = false
	) {
		$this->id            = self::slug( $id, 'registration ID' );
		$this->provider_id   = self::slug( $provider_id, 'provider ID' );
		$this->taxonomy      = self::slug( $taxonomy, 'taxonomy' );
		$this->target_types  = array_values( array_unique( array_map( static fn ( string $type ): string => self::slug( $type, 'target type' ), $target_types ) ) );
		$this->label         = trim( $label );
		$this->capability    = trim( $capability );
		$this->hierarchical  = $hierarchical;
		$this->term_creation = $term_creation;

		if ( array() === $this->target_types || '' === $this->label || '' === $this->capability ) {
			throw new \InvalidArgumentException( 'Taxonomy registrations require target types, a label, and a capability.' );
		}
	}

	/** Returns the stable registration ID. */
	public function id(): string {
		return $this->id;
	}

	/** Returns the owning provider ID. */
	public function providerId(): string {
		return $this->provider_id;
	}

	/** Returns the registered taxonomy name. */
	public function taxonomy(): string {
		return $this->taxonomy;
	}

	/** @return string[] */
	public function targetTypes(): array {
		return $this->target_types;
	}

	/** Returns the customer-facing label. */
	public function label(): string {
		return $this->label;
	}

	/** Returns the capability required to assign terms. */
	public function capability(): string {
		return $this->capability;
	}

	/** Returns whether references are hierarchical. */
	public function hierarchical(): bool {
		return $this->hierarchical;
	}

	/** Returns whether the registration permits creating terms. */
	public function allowsTermCreation(): bool {
		return $this->term_creation;
	}

	/** Determines whether the registration supports a provider context. */
	public function supports( string $provider_id, string $target_type ): bool {
		return $this->provider_id === $provider_id && in_array( $target_type, $this->target_types, true );
	}

	/** Normalizes and validates an identity slug. */
	private static function slug( string $value, string $label ): string {
		$value = strtolower( trim( $value ) );
		if ( ! preg_match( '/^[a-z][a-z0-9_-]*$/', $value ) ) {
			throw new \InvalidArgumentException( 'Invalid taxonomy ' . $label . '.' );
		}

		return $value;
	}
}
