<?php
declare(strict_types=1);

namespace ROITheme\Shared\Infrastructure\Validators;

/**
 * Validador de llamadas a roi_render_component() en templates
 *
 * Verifica que:
 * - Los nombres de componentes usen kebab-case (guiones, no underscores)
 * - Los componentes llamados estén registrados en functions-addon.php
 * - No haya llamadas con nombres inválidos
 */
final class TemplateCallsValidator implements PhaseValidatorInterface
{
    public function getPhaseNumber(): int|string
    {
        return 'templates';
    }

    public function getPhaseDescription(): string
    {
        return 'Template Calls (roi_render_component)';
    }

    public function validate(string $componentName, string $themePath): ValidationResult
    {
        $result = new ValidationResult();
        $result->addInfo("Validando llamadas a roi_render_component() para: {$componentName}");

        // 1. Obtener componentes registrados en functions-addon.php
        $registeredComponents = $this->getRegisteredComponents($themePath);
        $result->addInfo("Componentes registrados: " . count($registeredComponents));

        // 2. Buscar todas las llamadas en templates
        $templateFiles = $this->getTemplateFiles($themePath);
        $allCalls = [];
        $invalidCalls = [];
        $unregisteredCalls = [];

        foreach ($templateFiles as $file) {
            $calls = $this->findRenderCalls($file);
            foreach ($calls as $call) {
                $allCalls[] = [
                    'file' => basename($file),
                    'line' => $call['line'],
                    'component' => $call['component']
                ];

                // Verificar si usa underscore en lugar de guión
                if (strpos($call['component'], '_') !== false) {
                    $invalidCalls[] = $call + ['file' => basename($file)];
                }

                // Verificar si está registrado
                if (!in_array($call['component'], $registeredComponents)) {
                    // Solo marcar como no registrado si no tiene underscore
                    // (los de underscore ya se marcan como inválidos)
                    if (strpos($call['component'], '_') === false) {
                        $unregisteredCalls[] = $call + ['file' => basename($file)];
                    }
                }
            }
        }

        // 3. Verificar específicamente el componente que se está validando
        $componentFound = false;
        $componentCallsCorrect = true;

        foreach ($allCalls as $call) {
            // Buscar variantes del componente (con guión o underscore)
            $kebabName = $componentName;
            $snakeName = str_replace('-', '_', $componentName);

            if ($call['component'] === $kebabName) {
                $componentFound = true;
                $result->addInfo("✓ Componente '{$componentName}' llamado correctamente en {$call['file']}:{$call['line']}");
            } elseif ($call['component'] === $snakeName) {
                $componentFound = true;
                $componentCallsCorrect = false;
                $result->addError(
                    "Llamada incorrecta en {$call['file']}:{$call['line']}: " .
                    "usa '{$snakeName}' (underscore) en lugar de '{$kebabName}' (kebab-case)"
                );
            }
        }

        // 4. Reportar errores generales de formato
        foreach ($invalidCalls as $call) {
            // Solo reportar si no es el componente actual (ya se reportó arriba)
            $snakeName = str_replace('-', '_', $componentName);
            if ($call['component'] !== $snakeName) {
                $suggestedName = str_replace('_', '-', $call['component']);
                $result->addWarning(
                    "Llamada con underscore en {$call['file']}:{$call['line']}: " .
                    "'{$call['component']}' debería ser '{$suggestedName}'"
                );
            }
        }

        // 5. Reportar componentes no registrados
        foreach ($unregisteredCalls as $call) {
            $result->addWarning(
                "Componente no registrado en {$call['file']}:{$call['line']}: '{$call['component']}'"
            );
        }

        // 6. Advertir si el componente no se llama en ningún template
        if (!$componentFound) {
            $result->addWarning(
                "El componente '{$componentName}' no se llama en ningún template. " .
                "Verifica que esté incluido en single.php, header.php, footer.php u otro template."
            );
        }

        // Estadísticas
        $result->setStat('Templates escaneados', count($templateFiles));
        $result->setStat('Llamadas totales encontradas', count($allCalls));
        $result->setStat('Componentes registrados', count($registeredComponents));

        if (!empty($invalidCalls)) {
            $result->setStat('Llamadas con underscore (error)', count($invalidCalls));
        }

        return $result;
    }

    /**
     * Obtiene la lista de componentes registrados en functions-addon.php
     */
    private function getRegisteredComponents(string $themePath): array
    {
        $functionsFile = $themePath . '/functions-addon.php';
        $components = [];

        if (!file_exists($functionsFile)) {
            return $components;
        }

        $content = file_get_contents($functionsFile);

        // Buscar patrones: case 'nombre-componente':
        if (preg_match_all("/case\s+'([a-z0-9-]+)':/", $content, $matches)) {
            $components = $matches[1];
        }

        return array_unique($components);
    }

    /**
     * Obtiene los archivos de template PHP del tema
     */
    private function getTemplateFiles(string $themePath): array
    {
        $templates = [];

        // Archivos principales de template
        $mainTemplates = [
            'header.php',
            'footer.php',
            'single.php',
            'page.php',
            'index.php',
            'archive.php',
            'search.php',
            'sidebar.php',
            '404.php',
            'front-page.php',
            'home.php',
        ];

        foreach ($mainTemplates as $template) {
            $path = $themePath . '/' . $template;
            if (file_exists($path)) {
                $templates[] = $path;
            }
        }

        // Buscar en template-parts/
        $templatePartsDir = $themePath . '/template-parts';
        if (is_dir($templatePartsDir)) {
            $iterator = new \RecursiveIteratorIterator(
                new \RecursiveDirectoryIterator($templatePartsDir)
            );

            foreach ($iterator as $file) {
                if ($file->isFile() && $file->getExtension() === 'php') {
                    $templates[] = $file->getPathname();
                }
            }
        }

        // Buscar templates personalizados (page-*.php, single-*.php)
        $customTemplates = glob($themePath . '/{page-*.php,single-*.php}', GLOB_BRACE);
        if ($customTemplates) {
            $templates = array_merge($templates, $customTemplates);
        }

        return $templates;
    }

    /**
     * Busca llamadas a roi_render_component() en un archivo
     */
    private function findRenderCalls(string $filePath): array
    {
        $calls = [];
        $content = file_get_contents($filePath);
        $lines = explode("\n", $content);

        foreach ($lines as $lineNum => $line) {
            // Buscar: roi_render_component('nombre') o roi_render_component("nombre")
            if (preg_match_all("/roi_render_component\s*\(\s*['\"]([^'\"]+)['\"]\s*\)/", $line, $matches, PREG_SET_ORDER)) {
                foreach ($matches as $match) {
                    $calls[] = [
                        'line' => $lineNum + 1,
                        'component' => $match[1]
                    ];
                }
            }
        }

        return $calls;
    }
}
