<?php

declare(strict_types=1);

namespace App\Framework\Logging;

/**
 * Verwaltet die Log-Processors und wendet sie auf Log-Records an.
 */
final readonly class ProcessorManager
{
    /** @var array<LogProcessor> Liste der Processors, sortiert nach Priorität */
    private array $processors;

    public function __construct(LogProcessor ...$processors)
    {
        $this->processors = $processors;
    }

    public function addProcessor(LogProcessor $processor): self
    {
        $allProcessors = [...$this->processors, $processor];
        $sorted = $this->sortProcessorsList($allProcessors);

        return new self(...$sorted);
    }

    /**
     * Wendet alle Processors auf einen Log-Record an
     */
    public function processRecord(LogRecord $record): LogRecord
    {
        foreach ($this->processors as $processor) {
            $record = $processor->processRecord($record);
        }

        return $record;
    }

    /**
     * Sortiert die Processors nach Priorität (höhere Priorität = frühere Ausführung)
     */
    private function sortProcessors(): array
    {
        $processors = $this->processors;

        usort($processors, function (LogProcessor $a, LogProcessor $b) {
            return $b->getPriority() <=> $a->getPriority(); // Absteigend sortieren
        });

        return $processors;
    }

    /**
     * Sortiert eine Liste von Processors
     */
    private function sortProcessorsList(array $processors): array
    {
        usort($processors, function (LogProcessor $a, LogProcessor $b) {
            return $b->getPriority() <=> $a->getPriority(); // Absteigend sortieren
        });

        return $processors;
    }

    /**
     * Gibt alle registrierten Processors zurück
     *
     * @return array<string, int> Array mit Processor-Namen als Schlüssel und Prioritäten als Werte
     */
    public function getProcessorList(): array
    {
        $result = [];

        foreach ($this->processors as $processor) {
            $result[$processor->getName()] = $processor->getPriority();
        }

        return $result;
    }

    public function hasProcessor(string $name): bool
    {
        return array_any($this->processors, fn ($processor) => $processor->getName() === $name);

    }

    public function getProcessor(string $name): ?LogProcessor
    {
        return array_find($this->processors, fn ($processor) => $processor->getName() === $name);

    }
}
