<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
use App\Service\ImageService;

class OptimizeImageCompression extends Command
{
    protected $signature = 'images:optimize-compression
                            {--max-size=1024 : 目标最大文件大小 (KB)}
                            {--quality=85 : 初始压缩质量}
                            {--min-quality=40 : 最低压缩质量}
                            {--max-iterations=10 : 最大压缩次数}';

    protected $description = '优化压缩目录下的图片，压缩到指定大小以下';

    public function handle()
    {
        // 不限制内存
        ini_set('memory_limit', -1);
        $disk = Storage::disk('public');
        $directory = 'images/compressed';
        $maxSizeKB = (int)$this->option('max-size');
        $maxSizeBytes = $maxSizeKB * 1024;

        $this->info("正在优化 {$directory} 目录下的图片...");
        $this->info("目标文件大小: {$maxSizeKB}KB");

        $images = $disk->allFiles($directory);
        $total = count($images);
        $count = 0;

        $progressBar = $this->output->createProgressBar($total);
        $progressBar->start();

        foreach ($images as $imagePath) {
            $originalSize = $disk->size($imagePath);
            $fileExtension = pathinfo($imagePath, PATHINFO_EXTENSION);

            // 只处理WEBP格式文件
            if (strtolower($fileExtension) !== 'webp') {
                $this->warn("跳过非WEBP文件: $imagePath");
                $progressBar->advance();
                continue;
            }

            // 如果已经小于目标大小，则跳过
            if ($originalSize <= $maxSizeBytes) {
                $progressBar->advance();
                continue;
            }

            // 获取文件的绝对路径
            $filePath = $disk->path($imagePath);

            // 创建压缩实例
            $imageService = app(ImageService::class);
            $tempPath = storage_path('app/temp/'.basename($imagePath));

            // 创建目标目录
            if (!file_exists(dirname($tempPath))) {
                mkdir(dirname($tempPath), 0755, true);
            }

            // 多轮压缩策略
            $currentSize = $originalSize;
            $iterations = 0;
            $currentQuality = (int)$this->option('quality');
            $minQuality = (int)$this->option('min-quality');
            $maxIterations = (int)$this->option('max-iterations');

            while ($currentSize > $maxSizeBytes && $iterations < $maxIterations && $currentQuality >= $minQuality) {
                // 使用服务类进行压缩
                $optimizedContent = $this->recompressImage(
                    $filePath,
                    $currentQuality
                );

                file_put_contents($tempPath, $optimizedContent);
                $newSize = filesize($tempPath);

                // 如果新文件大小没有减小，则停止优化
                if ($newSize >= $currentSize) {
                    $this->warn("无法进一步压缩: $imagePath (质量: $currentQuality)");
                    break;
                }

                $currentSize = $newSize;
                $iterations++;

                // 降低质量进行下一轮尝试
                if ($currentSize > $maxSizeBytes) {
                    $currentQuality -= 5;
                }
            }

            // 替换原始文件
            if ($currentSize < $originalSize) {
                rename($tempPath, $filePath);
                $this->info("优化成功: $imagePath 从 {$this->formatBytes($originalSize)} 压缩到 {$this->formatBytes($currentSize)}");
            } else {
                @unlink($tempPath);
                $this->warn("压缩失败: $imagePath 无法达到目标大小");
            }

            $progressBar->advance();
            $count++;
        }

        $progressBar->finish();
        $this->info("\n{$count}/{$total} 个图片已优化完成");
    }

    /**
     * 重新压缩图片
     */
    protected function recompressImage($filePath, $quality)
    {
        // 读取原始图片
        $image = imagecreatefromwebp($filePath);

        // 捕捉错误
        if (!$image) {
            throw new \Exception("无法读取图片: $filePath");
        }

        // 捕捉输出
        ob_start();
        $success = imagewebp($image, null, $quality);

        if (!$success) {
            throw new \Exception("压缩失败: $filePath");
        }

        $compressedContent = ob_get_clean();
        imagedestroy($image);

        return $compressedContent;
    }

    /**
     * 格式化字节大小
     */
    protected function formatBytes($bytes)
    {
        if ($bytes < 1024) return $bytes . 'B';
        if ($bytes < 1048576) return round($bytes / 1024, 1) . 'KB';
        return round($bytes / 1048576, 1) . 'MB';
    }
}
