<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media;

use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Plugin\DefaultPluginManager;
use Drupal\ffmpeg_media\Attribute\FFmpegOutput;
use Drupal\ffmpeg_media\Plugin\FFmpegOutput\FFmpegOutputInterface;

/**
 * Plugin manager for FFmpeg output format plugins.
 *
 * @internal Runtime service, not part of the supported contrib extension API.
 */
class FFmpegOutputPluginManager extends DefaultPluginManager {

  /**
   * Constructs an FFmpegOutputPluginManager object.
   *
   * @param \Traversable $namespaces
   *   An object that implements \Traversable which contains the root paths
   *   keyed by the corresponding namespace.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   Cache backend instance to use.
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
   *   The module handler to invoke alter hooks.
   */
  public function __construct(
    \Traversable $namespaces,
    CacheBackendInterface $cache_backend,
    ModuleHandlerInterface $module_handler,
  ) {
    parent::__construct(
      'Plugin/FFmpegOutput',
      $namespaces,
      $module_handler,
      FFmpegOutputInterface::class,
      FFmpegOutput::class,
    );

    $this->alterInfo('ffmpeg_output_info');
    $this->setCacheBackend($cache_backend, 'ffmpeg_output_plugins');
  }

  /**
   * Gets all available output format plugins.
   *
   * @return array<\Drupal\ffmpeg_media\Plugin\FFmpegOutput\FFmpegOutputInterface>
   *   Array of output format instances.
   */
  #[\NoDiscard]
  public function getAvailableOutputs(): array {
    $outputs = [];
    foreach ($this->getDefinitions() as $id => $definition) {
      $instance = $this->createInstance($id);
      if (!$instance instanceof FFmpegOutputInterface) {
        continue;
      }
      $outputs[$id] = $instance;
    }
    return $outputs;
  }

  /**
   * Gets outputs that support a specific codec.
   *
   * @param string $codecId
   *   Codec plugin ID.
   *
   * @return array<\Drupal\ffmpeg_media\Plugin\FFmpegOutput\FFmpegOutputInterface>
   *   Array of compatible output instances.
   */
  #[\NoDiscard]
  public function getOutputsForCodec(string $codecId): array {
    $outputs = [];
    foreach ($this->getAvailableOutputs() as $id => $output) {
      if ($output->supportsCodec($codecId)) {
        $outputs[$id] = $output;
      }
    }
    return $outputs;
  }

  /**
   * Gets output by extension.
   *
   * @param string $extension
   *   File extension (e.g., 'mp4', 'webm').
   *
   * @return \Drupal\ffmpeg_media\Plugin\FFmpegOutput\FFmpegOutputInterface|null
   *   Output instance or NULL if not found.
   */
  #[\NoDiscard]
  public function getOutputByExtension(string $extension): ?FFmpegOutputInterface {
    foreach ($this->getDefinitions() as $id => $definition) {
      if (($definition['extension'] ?? '') === $extension) {
        $instance = $this->createInstance($id);
        if (!$instance instanceof FFmpegOutputInterface) {
          return NULL;
        }
        return $instance;
      }
    }
    return NULL;
  }

  /**
   * Gets output options for form select.
   *
   * @return array<string, string>
   *   Array of output labels keyed by ID.
   */
  #[\NoDiscard]
  public function getOutputOptions(): array {
    $options = [];
    foreach ($this->getAvailableOutputs() as $id => $output) {
      $options[$id] = $output->getLabel();
    }
    return $options;
  }

}
