<?php

namespace App\Services\Features;

use App\Models\Features\Feature;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class FeatureImageService
{
    /**
     * Almacena la imagen miniatura de una feature
     *
     * @param Feature $feature
     * @param UploadedFile $file
     * @return string Ruta relativa de la imagen guardada
     */
    public function storeThumbnail(Feature $feature, UploadedFile $file): string
    {
        $path = $this->getFeatureDirectory($feature->id);
        $filename = $this->generateUniqueFilename($file, 'thumbnail');
        
        $file->storeAs($path, $filename, 'public');
        
        return $this->getRelativePath($feature->id, $filename);
    }

    /**
     * Almacena la imagen de cabecera de una feature
     *
     * @param Feature $feature
     * @param UploadedFile $file
     * @return string Ruta relativa de la imagen guardada
     */
    public function storeHeader(Feature $feature, UploadedFile $file): string
    {
        $path = $this->getFeatureDirectory($feature->id);
        $filename = $this->generateUniqueFilename($file, 'header');
        
        $file->storeAs($path, $filename, 'public');
        
        return $this->getRelativePath($feature->id, $filename);
    }

    /**
     * Almacena una imagen subida desde el editor
     *
     * @param Feature $feature
     * @param UploadedFile $file
     * @return string Ruta relativa de la imagen guardada
     */
    public function storeEditorImage(Feature $feature, UploadedFile $file): string
    {
        $path = $this->getFeatureDirectory($feature->id);
        $filename = $this->generateUniqueFilename($file, 'editor');

        $file->storeAs($path, $filename, 'public');

        return $this->getRelativePath($feature->id, $filename);
    }

    /**
     * Elimina una imagen
     * No borra imágenes que estén en la ruta images_static
     *
     * @param string $relativePath Ruta relativa de la imagen
     * @return bool
     */
    public function deleteImage(string $relativePath): bool
    {
        if (empty($relativePath)) {
            return false;
        }

        // No borrar imágenes que estén en images_static
        if (str_starts_with($relativePath, 'images_static/')) {
            return false;
        }

        return Storage::disk('public')->delete($relativePath);
    }

    /**
     * Elimina todas las imágenes de una feature
     *
     * @param Feature $feature
     * @return void
     */
    public function deleteAllFeatureImages(Feature $feature): void
    {
        $directory = $this->getFeatureDirectory($feature->id);
        
        if (Storage::disk('public')->exists($directory)) {
            Storage::disk('public')->deleteDirectory($directory);
        }
    }

    /**
     * Obtiene la URL pública de una imagen
     *
     * @param string $relativePath Ruta relativa de la imagen
     * @return string|null
     */
    public function getPublicUrl(string $relativePath): ?string
    {
        if (empty($relativePath)) {
            return null;
        }

        return Storage::disk('public')->url($relativePath);
    }

    /**
     * Obtiene el directorio de almacenamiento para una feature
     *
     * @param int $featureId
     * @return string
     */
    private function getFeatureDirectory(int $featureId): string
    {
        return "features/{$featureId}";
    }

    /**
     * Genera un nombre de archivo único
     *
     * @param UploadedFile $file
     * @param string $prefix
     * @return string
     */
    public function generateUniqueFilename(UploadedFile $file, string $prefix = ''): string
    {
        $extension = $file->getClientOriginalExtension();
        $originalName = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
        // Limpiar el nombre: eliminar caracteres especiales y espacios
        $name = Str::slug($originalName);
        // Si el nombre queda vacío después del slug, usar un nombre por defecto
        if (empty($name)) {
            $name = 'image';
        }
        $timestamp = now()->format('YmdHis');
        $random = Str::random(8);
        
        $prefix = $prefix ? $prefix . '_' : '';
        
        return "{$prefix}{$name}_{$timestamp}_{$random}.{$extension}";
    }

    /**
     * Obtiene la ruta relativa completa
     *
     * @param int $featureId
     * @param string $filename
     * @return string
     */
    private function getRelativePath(int $featureId, string $filename): string
    {
        return "features/{$featureId}/{$filename}";
    }

    /**
     * Migra imágenes temporales usadas en el HTML de una feature
     * desde features/temp/... a features/{id}/..., actualizando las URLs en el HTML.
     *
     * @param Feature $feature
     * @param string $html
     * @return string HTML actualizado
     */
    public function migrateTempImagesForFeature(Feature $feature, string $html): string
    {
        if (trim($html) === '') {
            return $html;
        }

        $disk = Storage::disk('public');
        $updatedHtml = $html;

        // Buscar todas las imágenes
        preg_match_all('/<img[^>]+src=["\']([^"\']+)["\'][^>]*>/i', $html, $matches);

        if (empty($matches[1])) {
            return $html;
        }

        foreach ($matches[1] as $url) {
            // Convertir URL pública a ruta relativa (similar a CleanupUnusedFeatureImages::urlToRelativePath)
            $relativePath = $this->urlToRelativePath($url);

            if (!$relativePath) {
                continue;
            }

            // Solo mover imágenes bajo features/temp
            if (!Str::startsWith($relativePath, 'features/temp/')) {
                continue;
            }

            if (!$disk->exists($relativePath)) {
                continue;
            }

            $filename = basename($relativePath);
            $targetDir = $this->getFeatureDirectory($feature->id);
            $targetRelative = $targetDir . '/' . $filename;

            // Evitar sobreescrituras accidentales
            if ($disk->exists($targetRelative)) {
                $pathInfo = pathinfo($filename);
                $newName = $pathInfo['filename'] . '_' . Str::random(6) . '.' . $pathInfo['extension'];
                $targetRelative = $targetDir . '/' . $newName;
            }

            // Asegurar directorio destino
            if (!$disk->exists($targetDir)) {
                $disk->makeDirectory($targetDir);
            }

            // Mover archivo
            if ($disk->move($relativePath, $targetRelative)) {
                $newUrl = $this->getPublicUrl($targetRelative);
                if ($newUrl) {
                    // Reemplazar URL antigua por la nueva en el HTML
                    $updatedHtml = str_replace($url, $newUrl, $updatedHtml);
                }
            }
        }

        return $updatedHtml;
    }

    /**
     * Convierte una URL pública de Storage a ruta relativa (storage/...)
     */
    private function urlToRelativePath(string $url): ?string
    {
        $url = str_replace(config('app.url'), '', $url);
        $url = ltrim($url, '/');

        if (Str::startsWith($url, 'storage/')) {
            return Str::after($url, 'storage/');
        }

        return null;
    }
}

