<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;

class OptimizeImages extends Command
{
    protected $signature = 'images:optimize
                            {--path=public : Base path to scan (relative to project root or absolute)}
                            {--max-kb= : Target max size in KB (default from IMAGE_MAX_KB)}
                            {--max-width= : Max width in px (default from IMAGE_MAX_WIDTH)}
                            {--max-height= : Max height in px (default from IMAGE_MAX_HEIGHT)}
                            {--min-width= : Min width in px for aggressive shrink (default from IMAGE_MIN_WIDTH)}
                            {--min-height= : Min height in px for aggressive shrink (default from IMAGE_MIN_HEIGHT)}
                            {--quality= : JPEG/WEBP quality (default from IMAGE_QUALITY)}
                            {--min-quality= : Minimum JPEG/WEBP quality (default from IMAGE_MIN_QUALITY)}
                            {--png-compression= : PNG compression 0-9 (default from IMAGE_PNG_COMPRESSION)}
                            {--limit= : Max number of files to process}
                            {--dry-run : Only show what would be processed}';

    protected $description = 'Optimize existing uploaded images to reduce file size.';

    public function handle(): int
    {
        if (!function_exists('optimize_uploaded_image')) {
            $this->error('optimize_uploaded_image helper not found.');
            return 1;
        }

        $inputPath = (string) $this->option('path');
        if ($inputPath === '') {
            $inputPath = 'public';
        }

        $absPath = $this->toAbsolutePath($inputPath);
        if (!is_dir($absPath)) {
            $this->error('Path not found: ' . $absPath);
            return 1;
        }

        $maxKb = $this->intOption('max-kb', (int) env('IMAGE_MAX_KB', 200));
        $maxWidth = $this->intOption('max-width', (int) env('IMAGE_MAX_WIDTH', 1600));
        $maxHeight = $this->intOption('max-height', (int) env('IMAGE_MAX_HEIGHT', 1600));
        $minWidth = $this->intOption('min-width', (int) env('IMAGE_MIN_WIDTH', 480));
        $minHeight = $this->intOption('min-height', (int) env('IMAGE_MIN_HEIGHT', 480));
        $quality = $this->intOption('quality', (int) env('IMAGE_QUALITY', 82));
        $minQuality = $this->intOption('min-quality', (int) env('IMAGE_MIN_QUALITY', 55));
        $pngCompression = $this->intOption('png-compression', (int) env('IMAGE_PNG_COMPRESSION', 7));
        $limit = $this->intOption('limit', 0);
        $dryRun = (bool) $this->option('dry-run');

        $maxBytes = $maxKb > 0 ? $maxKb * 1024 : 0;

        $options = [
            'max_width' => $maxWidth,
            'max_height' => $maxHeight,
            'max_kb' => $maxKb,
            'quality' => $quality,
            'min_quality' => $minQuality,
            'png_compression' => $pngCompression,
            'min_width' => $minWidth,
            'min_height' => $minHeight,
        ];

        $processed = 0;
        $optimized = 0;
        $skipped = 0;
        $errors = 0;
        $savedBytes = 0;

        $files = File::allFiles($absPath);

        foreach ($files as $file) {
            if ($limit > 0 && $processed >= $limit) {
                break;
            }

            $path = $file->getPathname();
            $type = @exif_imagetype($path);
            if (!in_array($type, [IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_WEBP], true)) {
                $skipped++;
                continue;
            }

            $sizeBefore = (int) $file->getSize();
            if ($maxBytes > 0 && $sizeBefore <= $maxBytes) {
                $skipped++;
                continue;
            }

            $processed++;

            if ($dryRun) {
                $this->line('DRY: ' . $path . ' (' . $this->formatBytes($sizeBefore) . ')');
                continue;
            }

            $ok = optimize_uploaded_image($path, $options);
            if (!$ok) {
                $errors++;
                continue;
            }

            clearstatcache(true, $path);
            $sizeAfter = (int) (@filesize($path) ?: $sizeBefore);
            if ($sizeAfter < $sizeBefore) {
                $savedBytes += ($sizeBefore - $sizeAfter);
            }
            $optimized++;
        }

        $this->info('Done.');
        $this->line('Processed: ' . $processed);
        $this->line('Optimized: ' . $optimized);
        $this->line('Skipped: ' . $skipped);
        $this->line('Errors: ' . $errors);
        $this->line('Saved: ' . $this->formatBytes($savedBytes));

        return 0;
    }

    private function toAbsolutePath(string $path): string
    {
        if (preg_match('/^(\/|[A-Za-z]:[\\\\\\/])/', $path)) {
            return $path;
        }

        return base_path($path);
    }

    private function intOption(string $name, int $fallback): int
    {
        $val = $this->option($name);
        if ($val === null || $val === '') {
            return $fallback;
        }
        return (int) $val;
    }

    private function formatBytes(int $bytes): string
    {
        if ($bytes <= 0) {
            return '0 B';
        }
        $units = ['B','KB','MB','GB','TB'];
        $i = (int) floor(log($bytes, 1024));
        $i = min($i, count($units) - 1);
        return round($bytes / (1024 ** $i), 2) . ' ' . $units[$i];
    }
}
