<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class OptimizeImages extends Command
{
    protected $signature = 'optimize:images
                            {--apply : Aplica cambios. Sin esta flag corre en modo dry-run.}
                            {--folder= : Solo procesa esta carpeta (carousel|sponsors|qr|promos|noticias|clubes).}
                            {--no-backup : No crea backup de los originales.}';

    protected $description = 'Comprime y redimensiona imagenes en storage/app/public/. Por defecto dry-run.';

    private array $config = [
        'carousel' => ['maxWidth' => 1600, 'quality' => 82],
        'noticias' => ['maxWidth' => 1200, 'quality' => 82],
        'promos'   => ['maxWidth' => 1200, 'quality' => 82],
        'clubes'   => ['maxWidth' => 512,  'quality' => 85],
        'sponsors' => ['maxWidth' => 600,  'quality' => 85],
        'qr'       => ['maxWidth' => 800,  'quality' => 85],
    ];

    public function handle(): int
    {
        $apply    = (bool) $this->option('apply');
        $only     = $this->option('folder');
        $noBackup = (bool) $this->option('no-backup');

        if (!extension_loaded('gd')) {
            $this->error('La extension GD de PHP no esta instalada.');
            return self::FAILURE;
        }

        // Usa la config real del disk 'public' (respeta override de Hostinger)
        $base = realpath(config('filesystems.disks.public.root')) ?: config('filesystems.disks.public.root');
        if (!is_dir($base)) {
            $this->error("No existe: $base");
            return self::FAILURE;
        }
        $this->line("Base: $base");

        $backupBase = $base . '/_backup_optimize';
        if ($apply && !$noBackup && !is_dir($backupBase)) {
            mkdir($backupBase, 0755, true);
        }

        $this->line('');
        $this->line($apply
            ? '<fg=red>MODO APLICACION</> — los archivos seran reemplazados.'
            : '<fg=yellow>MODO DRY-RUN</> — no se modifica nada. Pasa --apply para aplicar.');
        $this->line('');

        $totalOrig = 0; $totalNew = 0; $totalProcessed = 0; $totalSkipped = 0;

        foreach ($this->config as $folder => $cfg) {
            if ($only && $only !== $folder) continue;

            $path = $base . '/' . $folder;
            if (!is_dir($path)) {
                $this->warn("  - $folder/  (no existe, skip)");
                continue;
            }

            $this->info("Carpeta: $folder/  (max {$cfg['maxWidth']}px, q={$cfg['quality']})");
            $files = glob($path . '/*.{jpg,jpeg,png,webp,JPG,JPEG,PNG,WEBP}', GLOB_BRACE);

            $folderOrig = 0; $folderNew = 0; $folderProcessed = 0; $folderSkipped = 0;

            foreach ($files as $file) {
                $origSize = filesize($file);
                $totalOrig += $origSize; $folderOrig += $origSize;

                $info = @getimagesize($file);
                if (!$info) { $folderSkipped++; $totalSkipped++; continue; }

                [$w, $h] = $info;
                $needsResize  = $w > $cfg['maxWidth'];
                $needsRecomp  = $origSize > 100 * 1024; // skip si ya pesa <100KB

                if (!$needsResize && !$needsRecomp) {
                    $folderSkipped++; $totalSkipped++; $totalNew += $origSize; $folderNew += $origSize;
                    continue;
                }

                $result = $this->processImage($file, $cfg['maxWidth'], $cfg['quality']);
                if ($result === null) {
                    $folderSkipped++; $totalSkipped++; $totalNew += $origSize; $folderNew += $origSize;
                    continue;
                }

                [$newBytes, $newW, $newH] = $result;

                if ($newBytes >= $origSize) {
                    $folderSkipped++; $totalSkipped++; $totalNew += $origSize; $folderNew += $origSize;
                    $this->line(sprintf("    - %-40s %dKB no mejora, skip", basename($file), $origSize / 1024));
                    continue;
                }

                $folderProcessed++; $totalProcessed++;
                $totalNew += $newBytes; $folderNew += $newBytes;

                $reduction = round((1 - $newBytes / $origSize) * 100, 1);
                $this->line(sprintf(
                    "    %s %-40s %dKB -> %dKB (-%s%%)  %dx%d -> %dx%d",
                    $apply ? '<fg=green>OK</>' : '<fg=cyan>--</>',
                    basename($file), $origSize / 1024, $newBytes / 1024, $reduction,
                    $w, $h, $newW, $newH
                ));

                if ($apply) {
                    if (!$noBackup) {
                        $backupDir = $backupBase . '/' . $folder;
                        if (!is_dir($backupDir)) mkdir($backupDir, 0755, true);
                        copy($file, $backupDir . '/' . basename($file));
                    }
                    file_put_contents($file, $result[3]);
                }
            }

            $this->line(sprintf(
                "  -> %s files procesados, %s skip, %s -> %s (-%s%%)",
                $folderProcessed, $folderSkipped,
                $this->fmt($folderOrig), $this->fmt($folderNew),
                $folderOrig > 0 ? round((1 - $folderNew / max($folderOrig, 1)) * 100, 1) : 0
            ));
            $this->line('');
        }

        $this->line(str_repeat('=', 60));
        $this->info(sprintf(
            'TOTAL: %d procesados, %d skip. %s -> %s  (ahorro: %s, -%s%%)',
            $totalProcessed, $totalSkipped,
            $this->fmt($totalOrig), $this->fmt($totalNew),
            $this->fmt($totalOrig - $totalNew),
            $totalOrig > 0 ? round((1 - $totalNew / max($totalOrig, 1)) * 100, 1) : 0
        ));

        if (!$apply && $totalProcessed > 0) {
            $this->line('');
            $this->warn('Para aplicar realmente: php artisan optimize:images --apply');
        }

        return self::SUCCESS;
    }

    private function processImage(string $file, int $maxWidth, int $quality): ?array
    {
        $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));

        $img = match ($ext) {
            'jpg', 'jpeg' => @imagecreatefromjpeg($file),
            'png'         => @imagecreatefrompng($file),
            'webp'        => @imagecreatefromwebp($file),
            default       => null,
        };
        if (!$img) return null;

        $w = imagesx($img); $h = imagesy($img);
        $newW = $w; $newH = $h;

        if ($w > $maxWidth) {
            $newW = $maxWidth;
            $newH = (int) round($h * ($maxWidth / $w));
            $resized = imagecreatetruecolor($newW, $newH);

            if (in_array($ext, ['png', 'webp'])) {
                imagealphablending($resized, false);
                imagesavealpha($resized, true);
                $transparent = imagecolorallocatealpha($resized, 0, 0, 0, 127);
                imagefilledrectangle($resized, 0, 0, $newW, $newH, $transparent);
            }

            imagecopyresampled($resized, $img, 0, 0, 0, 0, $newW, $newH, $w, $h);
            $img = $resized;
        }

        ob_start();
        match ($ext) {
            'jpg', 'jpeg' => imagejpeg($img, null, $quality),
            'png'         => imagepng($img, null, 9),
            'webp'        => imagewebp($img, null, $quality),
        };
        $bytes = ob_get_clean();

        return [strlen($bytes), $newW, $newH, $bytes];
    }

    private function fmt(int $bytes): string
    {
        if ($bytes < 1024) return $bytes . 'B';
        if ($bytes < 1024 * 1024) return round($bytes / 1024, 1) . 'KB';
        return round($bytes / 1024 / 1024, 2) . 'MB';
    }
}
