<?php

namespace App\Services\ScssCdn;

use App\Models\ScssCdn\ScssCdnBundle;
use App\Models\ScssCdn\ScssCdnFile;
use Illuminate\Support\Str;

class ScssCdnImportParser
{
    /**
     * Detecta todas las directivas @import en un contenido
     *
     * @param string $content
     * @return array Array de imports encontrados ['original' => string, 'path' => string, 'line' => int]
     */
    public static function parseImports(string $content): array
    {
        $imports = [];
        $lines = explode("\n", $content);

        // Patrones para detectar @import
        $patterns = [
            // @import "file";
            '/@import\s+["\']([^"\']+)["\']\s*;/',
            // @import url('file');
            '/@import\s+url\(["\']?([^"\'()]+)["\']?\)\s*;/',
            // @import 'file'
            '/@import\s+["\']([^"\']+)["\']\s*$/',
        ];

        foreach ($lines as $lineNumber => $line) {
            $line = trim($line);
            
            // Saltar comentarios
            if (Str::startsWith($line, '//') || Str::startsWith($line, '/*')) {
                continue;
            }

            foreach ($patterns as $pattern) {
                if (preg_match($pattern, $line, $matches)) {
                    $imports[] = [
                        'original' => $line,
                        'path' => $matches[1],
                        'line' => $lineNumber + 1,
                        'full_match' => $matches[0],
                    ];
                    break; // Solo un import por línea
                }
            }
        }

        return $imports;
    }

    /**
     * Busca un archivo en el bundle basado en una ruta relativa
     *
     * @param ScssCdnBundle $bundle
     * @param string $importPath Ruta del import (puede ser relativa o absoluta)
     * @param string $currentFileRelativePath Ruta del archivo actual
     * @return ScssCdnFile|null
     */
    public static function findFileInBundle(
        ScssCdnBundle $bundle,
        string $importPath,
        string $currentFileRelativePath
    ): ?ScssCdnFile {
        // Normalizar ruta del import
        $importPath = trim($importPath, '"\'');
        
        // Extraer directorio y nombre del archivo
        $pathParts = explode('/', $importPath);
        $fileName = array_pop($pathParts);
        $directory = implode('/', $pathParts);
        
        // Si la ruta ya tiene extensión .scss, quitarla para procesar
        $fileNameWithoutExt = $fileName;
        if (Str::endsWith($fileNameWithoutExt, '.scss')) {
            $fileNameWithoutExt = substr($fileNameWithoutExt, 0, -5);
        }
        
        // En SCSS, los partials pueden tener guión bajo al inicio
        // Intentar primero sin guión bajo, luego con guión bajo
        $possibleFileNames = [
            $fileNameWithoutExt . '.scss',
            '_' . $fileNameWithoutExt . '.scss',
        ];
        
        // Resolver ruta relativa desde el archivo actual
        $resolvedPath = self::resolveRelativePath($importPath . '.scss', $currentFileRelativePath);
        
        // También intentar desde la raíz del bundle (los imports pueden ser relativos a la raíz)
        $rootPath = $directory ? $directory . '/' . $fileNameWithoutExt . '.scss' : $fileNameWithoutExt . '.scss';
        
        // Lista de rutas a intentar
        $pathsToTry = [];
        
        // 1. Ruta resuelta desde el archivo actual (con y sin guión bajo)
        foreach ($possibleFileNames as $possibleFileName) {
            $dir = dirname($resolvedPath);
            if ($dir === '.' || $dir === '') {
                $pathsToTry[] = $possibleFileName;
            } else {
                $pathsToTry[] = $dir . '/' . $possibleFileName;
            }
        }
        
        // 2. Ruta desde la raíz del bundle (con y sin guión bajo)
        foreach ($possibleFileNames as $possibleFileName) {
            if ($directory) {
                $pathsToTry[] = $directory . '/' . $possibleFileName;
            } else {
                $pathsToTry[] = $possibleFileName;
            }
        }
        
        // 3. Si el archivo actual está en una subcarpeta (ej: scss/), intentar desde esa subcarpeta
        $currentDir = dirname($currentFileRelativePath);
        if ($currentDir !== '.' && $currentDir !== '') {
            foreach ($possibleFileNames as $possibleFileName) {
                if ($directory) {
                    $pathsToTry[] = $currentDir . '/' . $directory . '/' . $possibleFileName;
                } else {
                    $pathsToTry[] = $currentDir . '/' . $possibleFileName;
                }
            }
        }
        
        // Eliminar duplicados y valores vacíos
        $pathsToTry = array_unique(array_filter($pathsToTry));
        
        // Intentar cada ruta
        foreach ($pathsToTry as $path) {
            $file = $bundle->files()
                ->where('relative_path', $path)
                ->first();
            
            if ($file) {
                return $file;
            }
        }
        
        return null;
    }

    /**
     * Resuelve una ruta relativa basada en el archivo actual
     *
     * @param string $importPath Ruta del import
     * @param string $currentFilePath Ruta del archivo actual
     * @return string Ruta resuelta
     */
    private static function resolveRelativePath(string $importPath, string $currentFilePath): string
    {
        // Si es ruta absoluta (empieza con /), quitar el /
        if (Str::startsWith($importPath, '/')) {
            return ltrim($importPath, '/');
        }

        // Obtener directorio del archivo actual
        $currentDir = dirname($currentFilePath);
        if ($currentDir === '.') {
            $currentDir = '';
        }

        // Si el import empieza con ../, subir directorios
        while (Str::startsWith($importPath, '../')) {
            $importPath = substr($importPath, 3);
            if ($currentDir === '') {
                // Ya estamos en la raíz, no podemos subir más
                break;
            }
            $currentDir = dirname($currentDir);
            if ($currentDir === '.') {
                $currentDir = '';
            }
        }

        // Construir ruta final
        if ($currentDir === '') {
            return $importPath;
        }

        return $currentDir . '/' . $importPath;
    }

    /*
    |--------------------------------------------------------------------------
    | Lo que se quitó el 2026-09-08, y por qué importa saberlo
    |--------------------------------------------------------------------------
    |
    | Aquí vivían `replaceImports()`, `processBundle()` y `processFile()`: sustituían los
    | `@import` por direcciones firmadas y **guardaban el resultado** —en la columna del
    | fichero y en el almacenamiento—.
    |
    | Esas direcciones se firmaban con la caducidad por defecto, **365 días**. O sea que un
    | bundle procesado con eso se quedaba con URLs escritas dentro que **mueren al año**, y
    | a partir de ahí el `@import` del cliente devuelve 403 y su CSS se rompe. Sin que nada
    | avise, y un año después de haberlo tocado.
    |
    | **No llegó a pasar, por dos casualidades**: nadie los llamaba, y encima usaban
    | `$file->content` y `imports_processed`, dos columnas que `scss_cdn_files` no tiene, así
    | que habrían reventado al primer uso. Se borran en vez de dejarlos ahí: el camino bueno
    | —`processImportsForApi()`— sustituye **en memoria** y con una hora, y se ejecuta en
    | cada petición, así que nada envejece nunca.
    |
    | La lección: una función que **persiste** una URL con caducidad es una bomba de
    | relojería, y la caducidad larga es justo lo que la hace parecer inofensiva.
    |
    */

    /**
     * Procesa imports para uso en API, generando URLs con expiración de 1 hora
     * NO guarda el contenido procesado, solo retorna el contenido procesado en memoria
     *
     * @param string $content Contenido del archivo
     * @param ScssCdnBundle $bundle Bundle al que pertenece el archivo
     * @param string $currentFileRelativePath Ruta del archivo actual
     * @return string Contenido procesado con imports reemplazados por URLs firmadas de 1h
     */
    public static function processImportsForApi(
        string $content,
        ScssCdnBundle $bundle,
        string $currentFileRelativePath
    ): string {
        $imports = self::parseImports($content);
        
        if (empty($imports)) {
            return $content;
        }

        // Procesar cada import usando el full_match para reemplazo directo
        foreach ($imports as $import) {
            $file = self::findFileInBundle($bundle, $import['path'], $currentFileRelativePath);

            if ($file) {
                // Generar URL firmada con expiración de 1 hora para API
                $url = ScssCdnUrlService::getFileUrlForApi($file);
                
                // Reemplazar usando preg_replace con el patrón que capturó el import
                $newImport = "@import url('{$url}');";
                
                // Usar los mismos patrones que en parseImports para hacer el reemplazo
                $patterns = [
                    '/@import\s+["\']([^"\']+)["\']\s*;/',
                    '/@import\s+url\(["\']?([^"\'()]+)["\']?\)\s*;/',
                    '/@import\s+["\']([^"\']+)["\']\s*$/',
                ];
                
                foreach ($patterns as $pattern) {
                    // Verificar si este patrón coincide con el import actual
                    if (preg_match($pattern, $import['full_match'])) {
                        // Reemplazar solo si el path coincide
                        $content = preg_replace_callback($pattern, function($matches) use ($import, $url, $newImport) {
                            // Solo reemplazar si el path coincide con el import que estamos procesando
                            if ($matches[1] === $import['path']) {
                                return $newImport;
                            }
                            return $matches[0]; // Mantener original si no coincide
                        }, $content);
                        break;
                    }
                }
            }
            // Si no se encuentra el archivo, dejamos el import original
        }

        return $content;
    }

}

