<?php
/**
 * Unknown-provider Application-layer exception.
 *
 * Raised by {@see \CommerceLinkBuilder\Application\Sync\ProviderResolver}
 * implementations when no registered provider matches the supplied
 * provider key, or when the matched provider does not implement
 * {@see \CommerceLinkBuilder\Domain\Provider\ItemLookupProviderInterface}
 * (i.e. cannot satisfy the §6.3 single-item lookup contract that the
 * Phase 9 sync pipeline depends on).
 *
 * Design notes:
 *
 *   - Extends {@see \RuntimeException} because the failure has no
 *     provider attribution at the Domain layer: the caller asked the
 *     resolver for a provider it cannot locate, which is purely an
 *     Application-layer registry-lookup outcome and would not map onto
 *     any of the §10.2 provider error codes.
 *
 *   - Carries the offending provider key so the sync handler can stamp
 *     the matching `clb_sync_jobs` row with enough context for the
 *     admin diagnostics surface to explain the failure without parsing
 *     the message body.
 *
 *   - Final because the sync handler pattern-matches on the exact
 *     type when deciding the failed-terminal outcome code; consumers
 *     that need additional context should compose rather than subclass.
 *
 * @package CommerceLinkBuilder\Application\Sync\Exception
 */

declare(strict_types=1);

namespace CommerceLinkBuilder\Application\Sync\Exception;

use RuntimeException;
use Throwable;

/**
 * Application-layer exception signalling the supplied provider key
 * could not be resolved to an item-lookup-capable provider.
 *
 * See the file-level docblock for the rationale for inheriting from
 * {@see RuntimeException} rather than from the Domain provider
 * exception hierarchy.
 */
final class UnknownProviderException extends RuntimeException {

	/**
	 * Provider key that failed to resolve.
	 */
	private string $providerKey;

	/**
	 * Construct an unknown-provider exception with explicit values
	 * for every cross-cutting field.
	 *
	 * @param string         $message     Human-readable summary.
	 * @param string         $providerKey Provider key that failed to resolve.
	 * @param Throwable|null $previous    Underlying cause, or null.
	 */
	public function __construct( string $message, string $providerKey, ?Throwable $previous = null ) {
		parent::__construct( $message, 0, $previous );
		$this->providerKey = $providerKey;
	}

	/**
	 * Provider key that failed to resolve.
	 */
	public function providerKey(): string {
		return $this->providerKey;
	}

	/**
	 * Convenience factory for the "no matching provider registered"
	 * case.
	 *
	 * @param string $providerKey Provider key that failed to resolve.
	 */
	public static function forKey( string $providerKey ): self {
		return new self(
			sprintf( 'No item-lookup provider registered for key "%s".', $providerKey ),
			$providerKey
		);
	}
}
