<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media\Service;

use Drupal\Core\Config\ConfigFactoryInterface;

/**
 * Provides cached access to frequently-read ffmpeg_media config values.
 *
 * Loads config once per request and caches individual values to avoid
 * repeated ConfigFactory::get() calls across multiple services.
 *
 * @internal
 */
final class ConfigValueProvider implements ConfigValueProviderInterface {

  /**
   * Config name.
   */
  private const string CONFIG_NAME = 'ffmpeg_media.settings';

  /**
   * Per-request cache of config values.
   *
   * @var array<string, mixed>
   */
  private array $cache = [];

  /**
   * Constructs a ConfigValueProvider object.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   Config factory service.
   */
  public function __construct(
    protected readonly ConfigFactoryInterface $configFactory,
  ) {}

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function getHardwareAcceleration(): string {
    return (string) $this->getCached('hardware_acceleration', 'auto');
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function getOutputDirectory(): string {
    return (string) $this->getCached('output_directory', 'public://ffmpeg_media');
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function getFfmpegTimeout(): int {
    return (int) $this->getCached('ffmpeg_timeout', 300);
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function getMaxConcurrent(): int {
    return (int) $this->getCached('max_concurrent', 2);
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function getFfmpegPath(): string {
    return (string) $this->getCached('ffmpeg_path', '/usr/bin/ffmpeg');
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function getFfprobePath(): string {
    return (string) $this->getCached('ffprobe_path', '/usr/bin/ffprobe');
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  #[\NoDiscard]
  public function isHardwareFallbackEnabled(): bool {
    return (bool) $this->getCached('hardware_fallback_enabled', TRUE);
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-return array<int, string>
   */
  #[\Override]
  #[\NoDiscard]
  public function getEnabledProcessors(): array {
    $value = $this->getCached('enabled_processors', ['thumbnail', 'video_info']);

    return is_array($value) ? array_values($value) : ['thumbnail', 'video_info'];
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function resetCache(): void {
    $this->cache = [];
  }

  /**
   * Gets a cached config value, loading from config on first access.
   *
   * @param string $key
   *   Config key.
   * @param mixed $default
   *   Default value if not set.
   *
   * @return mixed
   *   Config value.
   */
  private function getCached(string $key, mixed $default): mixed {
    if (!array_key_exists($key, $this->cache)) {
      $value = $this->configFactory->get(self::CONFIG_NAME)->get($key);
      $this->cache[$key] = $value ?? $default;
    }

    return $this->cache[$key];
  }

}
