🌹🏠🌹？》《》？《》？<?php

namespace App\Services;

use Illuminate\Http\UploadedFile;

class ImagenRemitoService
{
    /**
     * Tipos MIME permitidos y su número mágico (magic bytes).
     */
    private const FIRMAS_PERMITIDAS = [
        'jpg'  => ["\xFF\xD8\xFF"],
        'jpeg' => ["\xFF\xD8\xFF"],
        'png'  => ["\x89PNG\r\n\x1a\n"],
        'webp' => ["RIFF"],          // Se valida más adelante con 'WEBP'
    ];

    private const MAX_ANCHO_PX  = 8000;
    private const MAX_ALTO_PX   = 8000;
    private const MIN_ANCHO_PX  = 10;
    private const MIN_ALTO_PX   = 10;

    /** @var array<string> */
    private array $errores = [];

    /**
     * Examina el archivo de imagen recibido y devuelve true si es válido.
     * En caso contrario, los errores quedan disponibles en getErrores().
     */
    public function examinar(UploadedFile $archivo): bool
    {
        $this->errores = [];

        $this->verificarFirmamagica($archivo);
        $this->verificarDimensiones($archivo);

        return empty($this->errores);
    }

    /**
     * Devuelve los errores detectados tras llamar a examinar().
     *
     * @return array<string>
     */
    public function getErrores(): array
    {
        return $this->errores;
    }

    // -------------------------------------------------------------------------
    // Validaciones internas
    // -------------------------------------------------------------------------

    /**
     * Comprueba que los primeros bytes del archivo coincidan con la firma
     * del formato declarado (evita ataques con archivos políglotos).
     */
    private function verificarFirmamagica(UploadedFile $archivo): void
    {
        $extension = strtolower($archivo->getClientOriginalExtension());

        if (!array_key_exists($extension, self::FIRMAS_PERMITIDAS)) {
            $this->errores[] = "Extensión '{$extension}' no permitida.";
            return;
        }

        $handle = fopen($archivo->getRealPath(), 'rb');
        if ($handle === false) {
            $this->errores[] = 'No se pudo leer el archivo para verificar su firma.';
            return;
        }

        $cabecera = fread($handle, 12);
        fclose($handle);

        if ($cabecera === false || strlen($cabecera) < 4) {
            $this->errores[] = 'El archivo está vacío o es demasiado pequeño para ser una imagen válida.';
            return;
        }

        $firmaValida = false;
        foreach (self::FIRMAS_PERMITIDAS[$extension] as $firma) {
            if (str_starts_with($cabecera, $firma)) {
                $firmaValida = true;
                break;
            }
        }

        // WebP requiere además la cadena 'WEBP' en los bytes 8-11
        if ($extension === 'webp' && $firmaValida) {
            $firmaValida = (substr($cabecera, 8, 4) === 'WEBP');
        }

        if (!$firmaValida) {
            $this->errores[] = 'El contenido del archivo no corresponde a una imagen ' . strtoupper($extension) . ' válida (firma inválida).';
        }

        // Verificación adicional con getimagesize() para detectar imágenes corruptas
        $info = @getimagesize($archivo->getRealPath());
        if ($info === false) {
            $this->errores[] = 'El archivo no pudo ser interpretado como una imagen (posiblemente corrupto o falso).';
        }
    }

    /**
     * Verifica que las dimensiones de la imagen estén dentro de los límites
     * permitidos para prevenir ataques de descompresión (image bomb).
     */
    private function verificarDimensiones(UploadedFile $archivo): void
    {
        $info = @getimagesize($archivo->getRealPath());

        if ($info === false) {
            // El error ya fue registrado en verificarFirmaMagica; no duplicar.
            return;
        }

        [$ancho, $alto] = $info;

        if ($ancho < self::MIN_ANCHO_PX || $alto < self::MIN_ALTO_PX) {
            $this->errores[] = "Las dimensiones de la imagen ({$ancho}x{$alto} px) son demasiado pequeñas. Mínimo: " . self::MIN_ANCHO_PX . 'x' . self::MIN_ALTO_PX . ' px.';
        }

        if ($ancho > self::MAX_ANCHO_PX || $alto > self::MAX_ALTO_PX) {
            $this->errores[] = "Las dimensiones de la imagen ({$ancho}x{$alto} px) superan el máximo permitido de " . self::MAX_ANCHO_PX . 'x' . self::MAX_ALTO_PX . ' px.';
        }
    }
}
