<?php

namespace Velis\Image\Processor\Decorator;

use Exception;
use RuntimeException;
use Velis\Filesystem\FilesystemInterface;

final class ConvertDecorator extends ImageProcessorDecorator
{
    public function __construct(
        protected FilesystemInterface $filesystem,
        protected readonly array $mimeTypes,
        protected readonly string $toExt,
    ) {
        parent::__construct($filesystem);
    }

    public function process(string $key): void
    {
        $mimeType = $this->filesystem->mimeType($key);

        if (!$this->shouldConvertFile($mimeType)) {
            return;
        }

        if (!$this->isSupportedFormat($this->toExt)) {
            throw new RuntimeException("Imagick does not support the format: {$this->toExt}");
        }

        try {
            $srcTmpPath = tempnam(DATA_PATH . 'temp', uniqid());
            $destTmpPath = tempnam(DATA_PATH . 'temp', uniqid());
            rename($destTmpPath, $destTmpPath . '.' . strtolower($this->toExt));
            $destTmpPath .= '.' . strtolower($this->toExt);

            file_put_contents($srcTmpPath, $this->filesystem->read($key));

            exec(sprintf('magick %s %s', $srcTmpPath, $destTmpPath));

            $this->filesystem->write($key, file_get_contents($destTmpPath));

            unlink($srcTmpPath);
            unlink($destTmpPath);
        } catch (Exception $ex) {
            throw new RuntimeException(sprintf('Failed to convert image (%s): %s', $key, $ex->getMessage()), 0, $ex);
        } finally {
            if (file_exists($srcTmpPath)) {
                unlink($srcTmpPath);
            }
            if (file_exists($destTmpPath)) {
                unlink($destTmpPath);
            }
        }
    }

    /**
     * Check if the image format is supported by Imagick.
     */
    private function isSupportedFormat(string $ext): bool
    {
        $ext = strtoupper($ext);

        $output = null;
        $returnVar = null;
        exec("magick -list format | grep {$ext}", $output, $returnVar);

        if ($returnVar !== 0) {
            return false;
        }

        return !empty(array_map('trim', $output));
    }

    private function shouldConvertFile(string $mimeType): bool
    {
        return in_array(strtolower($mimeType), $this->mimeTypes);
    }
}
