<?php


namespace Module\Vendor\Command;


use Illuminate\Console\Command;
use ModStart\Core\Exception\BizException;
use ModStart\Core\Input\Response;
use ModStart\Core\Util\FileUtil;
use ModStart\Core\Util\SerializeUtil;
use Module\DataImageCompressTecmz\Util\DataImageCompressTecmzUtil;
use Module\Vendor\Provider\ImageCompress\AbstractImageCompressProvider;
use Module\Vendor\Provider\ImageCompress\ImageCompressProvider;

class CompressDirImage extends Command
{
    protected $signature = 'CompressDirImage {statusFile} {file} {--provider=} {--minSizeKB=100}';

    private $statusFile = null;
    private $status = [];

    /**
     * @var AbstractImageCompressProvider
     */
    private $imageCompressProvider;

    public function handle()
    {
        $provider = $this->option('provider');
        if ($provider) {
            $this->imageCompressProvider = ImageCompressProvider::get($provider);
        } else {
            $this->imageCompressProvider = ImageCompressProvider::first();
        }
        BizException::throwsIf('图片压缩服务未配置', empty($this->imageCompressProvider));
        $this->info("图片压缩 Provider:" . $this->imageCompressProvider->name() . ', ' . $this->imageCompressProvider->title());
        $this->statusFile = $this->argument('statusFile');
        if (!file_exists($this->statusFile)) {
            $this->status = [
                'map' => [],
            ];
            $this->syncStatusFile();
        } else {
            $this->status = SerializeUtil::jsonDecode(file_get_contents($this->statusFile));
        }
        $file = $this->argument('file');
        BizException::throwsIf('目录或文件不存在', !file_exists($file));
        $minSizeKB = intval($this->option('minSizeKB'));
        $this->process($file . (is_dir($file) ? '/' : ''), [
            'minSizeKB' => $minSizeKB,
        ]);
    }

    private function syncStatusFile()
    {
        file_put_contents($this->statusFile, SerializeUtil::jsonEncode($this->status));
    }

    protected function process($file, $param)
    {
        $param = array_merge([
            // 超过多少KB才压缩
            'minSizeKB' => 100,
        ], $param);
        if (is_file($file)) {
            $file = realpath($file);
            if (isset($this->status['map'][$file])) {
                $this->warn("跳过已处理文件: $file");
                return;
            }
            $ext = FileUtil::extension($file);
            if (!in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
                return;
            }
            $content = file_get_contents($file);
            $contentSize = strlen($content);
            if ($contentSize < $param['minSizeKB'] * 1024) {
                $this->warn("跳过小于{$param['minSizeKB']}KB的文件: $file, 大小:" . FileUtil::formatByteSimple($contentSize));
                return;
            }
            $ret = $this->imageCompressProvider->process($ext, $content);
            if (Response::isSuccess($ret)) {
                if ($ret['data']['compressSize'] >= $ret['data']['originalSize']) {
                    $this->warn(join(', ', [
                        "图片:$file",
                        "未能压缩到更小",
                        "原大小:" . FileUtil::formatByteSimple($ret['data']['originalSize']),
                        "压缩后:" . FileUtil::formatByteSimple($ret['data']['compressSize']),
                    ]));
                } else {
                    $rate = sprintf('%.2f', $ret['data']['compressSize'] * 100 / $ret['data']['originalSize']);
                    $this->info(join(', ', [
                        "图片:$file",
                        "压缩比:$rate%",
                        "原大小:" . FileUtil::formatByteSimple($ret['data']['originalSize']),
                        "压缩后:" . FileUtil::formatByteSimple($ret['data']['compressSize']),
                    ]));
                    file_put_contents($file, $ret['data']['data']);
                }
                $this->status['map'][$file] = true;
                $this->syncStatusFile();
            } else {
                $this->warn("压缩图片: $file, 错误:{$ret['msg']}");
            }
        } else {
            $files = FileUtil::listFiles($file);
            foreach ($files as $file) {
                $this->process($file['pathname'], $param);
            }
        }
    }
}