<?php
declare(strict_types=1);

namespace App\Framework\Discovery;

use App\Framework\Cache\Cache;
use App\Framework\Core\InterfaceImplementationVisitor;
use App\Framework\Core\PathProvider;
use App\Framework\Core\RouteDiscoveryVisitor;
use App\Framework\Discovery\Results\DiscoveryResults;
use App\Framework\Discovery\Visitors\AttributeDiscoveryVisitor;
use App\Framework\View\TemplateDiscoveryVisitor;

/**
 * Einheitlicher Discovery-Service der alle Visitor koordiniert
 * Eliminiert doppelte Dateisystem-Iteration durch einmaligen Scan
 */
final readonly class UnifiedDiscoveryService
{
    private FileScannerService $fileScannerService;

    public function __construct(
        private PathProvider $pathProvider,
        private Cache $cache,
        private array $attributeMappers = [],
        private array $targetInterfaces = [],
        private bool $useCache = true,
        private bool $showProgress = false
    ) {
        // FileScannerService mit den richtigen Abhängigkeiten initialisieren
        $this->fileScannerService = new FileScannerService(
            new FileScanner(),
            $pathProvider,
            $cache,
            $this->useCache
        );
    }

    /**
     * Führt die einheitliche Discovery durch
     * Ein einziger Scan für alle Discovery-Typen
     */
    public function discover(): DiscoveryResults
    {
        $cacheKey = 'unified_discovery_results';

        // Prüfe Cache nur wenn aktiviert
        if ($this->useCache) {
            $cached = $this->cache->get($cacheKey);
            if ($cached->isHit) {
                return DiscoveryResults::fromArray($cached->value);
            }
        }

        // Registriere alle Visitors
        $this->registerVisitors();

        // Ein einziger Scan für alle Discovery-Typen
        $this->fileScannerService->scan($this->showProgress);

        // Sammle Ergebnisse von allen Visitors
        $results = $this->collectResults();


        // Cache für nächsten Aufruf speichern
        if ($this->useCache) {
            $this->cache->set($cacheKey, $results->toArray());
        }

        return $results;
    }

    /**
     * Führt einen inkrementellen Scan durch
     */
    public function incrementalDiscover(): DiscoveryResults
    {
        // Registriere alle Visitors
        $this->registerVisitors();

        // Inkrementeller Scan
        $this->fileScannerService->incrementalScan($this->showProgress);

        // Sammle aktualisierte Ergebnisse
        $results = $this->collectResults();

        // Cache aktualisieren
        if ($this->useCache) {
            $this->cache->set('unified_discovery_results', $results->toArray());
        }

        return $results;
    }

    /**
     * Registriert alle benötigten Visitors
     */
    private function registerVisitors(): void
    {
        // Attribute Discovery Visitor
        if (!empty($this->attributeMappers)) {
            $this->fileScannerService->registerVisitor(
                new AttributeDiscoveryVisitor($this->attributeMappers)
            );
        }

        // Interface Implementation Visitor
        if (!empty($this->targetInterfaces)) {
            $this->fileScannerService->registerVisitor(
                new InterfaceImplementationVisitor($this->targetInterfaces)
            );
        }

        // Route Discovery Visitor
        $this->fileScannerService->registerVisitor(
            new RouteDiscoveryVisitor()
        );

        // Template Discovery Visitor
        $this->fileScannerService->registerVisitor(
            new TemplateDiscoveryVisitor()
        );

        // Hier können weitere Visitors hinzugefügt werden
    }

    /**
     * Sammelt Ergebnisse von allen registrierten Visitors
     */
    private function collectResults(): DiscoveryResults
    {
        $results = new DiscoveryResults();

        foreach ($this->fileScannerService->getVisitors() as $visitor) {
            if ($visitor instanceof AttributeDiscoveryVisitor) {
                $results->setAttributeResults($visitor->getAllResults());
            } elseif ($visitor instanceof InterfaceImplementationVisitor) {
                $results->setInterfaceImplementations($visitor->getAllImplementations());
            } elseif ($visitor instanceof RouteDiscoveryVisitor) {
                $results->setRoutes($visitor->getRoutes());
            } elseif ($visitor instanceof TemplateDiscoveryVisitor) {
                $results->setTemplates($visitor->getAllTemplates());
            }
        }

        // Sortiere Interface-Implementierungen für konsistente Ergebnisse
        $results->sortInterfaceImplementations();

        return $results;
    }


    /**
     * Gibt die Anzahl der verarbeiteten Dateien zurück
     */
    public function getProcessedFileCount(): int
    {
        return $this->fileScannerService->getProcessedFileCount() ?? 0;
    }

    /**
     * Prüft, ob ein Rescan notwendig ist
     */
    public function shouldRescan(): bool
    {
        return $this->fileScannerService->shouldRescan();
    }
}
