<?php

declare(strict_types=1);

namespace Drupal\flowdrop_runtime\Service\Storage;

use Drupal\flowdrop_orchestration\Service\Orchestrator\OrchestratorInterface;
use Drupal\flowdrop_runtime\Service\Orchestrator\PipelineAwareOrchestratorInterface;

/**
 * Registry mapping pipeline bundle names to their storage implementations.
 *
 * @internal
 */
class PipelineStorageRegistry implements PipelineStorageRegistryInterface {

  /**
   * Constructs a new PipelineStorageRegistry.
   *
   * @param \Drupal\flowdrop_runtime\Service\Storage\PipelineStorageInterface[] $storages
   *   Keyed by bundle name.
   */
  public function __construct(private array $storages = []) {}

  /**
   * Registers a storage for a bundle (called by the compiler pass).
   */
  public function addStorage(string $bundle, PipelineStorageInterface $storage): void {
    $this->storages[$bundle] = $storage;
  }

  /**
   * {@inheritdoc}
   */
  public function getStorage(string $bundle): PipelineStorageInterface {
    return $this->storages[$bundle]
      ?? throw new \InvalidArgumentException(
          "No pipeline storage registered for bundle '{$bundle}'. " .
          "Tag your storage service with 'flowdrop_runtime.pipeline_storage' and bundle='{$bundle}'."
        );
  }

  /**
   * Returns the pipeline bundle preferred by the given orchestrator.
   *
   * Resolves via PipelineAwareOrchestratorInterface when implemented;
   * falls back to 'default' for orchestrators that do not declare a preference.
   *
   * @param \Drupal\flowdrop_orchestration\Service\Orchestrator\OrchestratorInterface $orchestrator
   *   The orchestrator instance.
   *
   * @return string
   *   The pipeline bundle name.
   */
  public function getBundleForOrchestrator(OrchestratorInterface $orchestrator): string {
    return $orchestrator instanceof PipelineAwareOrchestratorInterface
      ? $orchestrator->getPreferredPipelineBundle()
      : 'default';
  }

  /**
   * Returns the pipeline storage preferred by the given orchestrator.
   *
   * Convenience wrapper over getBundleForOrchestrator() + getStorage().
   *
   * @param \Drupal\flowdrop_orchestration\Service\Orchestrator\OrchestratorInterface $orchestrator
   *   The orchestrator instance.
   *
   * @return \Drupal\flowdrop_runtime\Service\Storage\PipelineStorageInterface
   *   The storage for the orchestrator's preferred bundle.
   *
   * @throws \InvalidArgumentException
   *   If no storage is registered for the resolved bundle.
   */
  public function getStorageForOrchestrator(OrchestratorInterface $orchestrator): PipelineStorageInterface {
    return $this->getStorage($this->getBundleForOrchestrator($orchestrator));
  }

}
