<?php

declare(strict_types=1);

namespace Drupal\flowdrop_runtime\Service\Logging;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Psr\Log\LoggerInterface;

/**
 * Logger channel factory decorator that filters the FlowDrop runtime channels.
 *
 * Decorating the factory (rather than only the channel services) ensures the
 * filter applies no matter how a service obtained its channel: whether it
 * injected "@logger.channel.<name>" (which is itself built via
 * logger.factory:get) or injected "@logger.factory" and called get('<name>')
 * directly. Every non-runtime channel is returned untouched.
 *
 * The filtered channels are the FlowDrop execution engines, which all log
 * routine execution events that should obey the central logging settings. They
 * all depend on flowdrop_runtime, so this decorator (registered by
 * flowdrop_runtime on the core logger.factory) is always present for them.
 *
 * @see \Drupal\flowdrop_runtime\Service\Logging\FilteredLoggerChannel
 *
 * @internal This class is not part of the public API and may change without notice.
 */
final class FilteredLoggerChannelFactory implements LoggerChannelFactoryInterface {

  /**
   * The FlowDrop execution-engine channels to filter.
   */
  private const FILTERED_CHANNELS = [
    'flowdrop_runtime',
    'flowdrop_stategraph',
    'flowdrop_workflow_executor',
  ];

  /**
   * Cached filtering wrappers, keyed by channel name.
   *
   * @var array<string, \Drupal\flowdrop_runtime\Service\Logging\FilteredLoggerChannel>
   */
  private array $wrappers = [];

  /**
   * Constructs a FilteredLoggerChannelFactory.
   *
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $inner
   *   The decorated logger channel factory.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory used to read the FlowDrop logging settings.
   */
  public function __construct(
    private readonly LoggerChannelFactoryInterface $inner,
    private readonly ConfigFactoryInterface $configFactory,
  ) {}

  /**
   * {@inheritdoc}
   */
  public function get($channel) {
    $channelLogger = $this->inner->get($channel);

    if (!in_array($channel, self::FILTERED_CHANNELS, TRUE)) {
      return $channelLogger;
    }

    return $this->wrappers[$channel] ??= new FilteredLoggerChannel($channelLogger, $this->configFactory);
  }

  /**
   * {@inheritdoc}
   */
  public function addLogger(LoggerInterface $logger, $priority = 0) {
    $this->inner->addLogger($logger, $priority);
  }

}
