<?php

namespace Openguru\OpenCartFramework\ImageTool;

use Intervention\Image\ImageManager;
use InvalidArgumentException;

class ImageTool implements ImageToolInterface
{
    private string $imageDir;
    private string $siteUrl;
    private ImageManager $manager;

    public function __construct(string $imageDir, string $siteUrl = '/')
    {
        $this->imageDir = rtrim($imageDir, '/') . '/';
        $this->siteUrl = $siteUrl;

        $driver = extension_loaded('imagick') ? 'imagick' : 'gd';
        $this->manager = new ImageManager(['driver' => $driver]);
    }

    public function resize(
        string $path,
        ?int $width = null,
        ?int $height = null,
        ?string $default = null,
        string $format = 'webp'
    ): ?string {
        $filename = is_file($this->imageDir . $path) ? $path : $default;

        if (! $width && ! $height) {
            throw new InvalidArgumentException('Width or height must be set');
        }

        if (! $filename || ! is_file($this->imageDir . $filename)) {
            return null;
        }

        $realPath = realpath($this->imageDir . $filename);
        if (strpos($realPath, realpath($this->imageDir)) !== 0) {
            return null; // безопасность
        }

        $extless = substr($filename, 0, strrpos($filename, '.'));
        $imageNew = 'cache/' . $extless . '-' . $width . 'x' . $height . '.' . $format;

        $fullNewPath = $this->imageDir . $imageNew;
        $fullOldPath = $this->imageDir . $filename;

        if (! is_file($fullNewPath) || filemtime($fullOldPath) > filemtime($fullNewPath)) {
            $dirPath = dirname($fullNewPath);
            if (! is_dir($dirPath)) {
                mkdir($dirPath, 0777, true);
            }

            $image = $this->manager->make($fullOldPath)
                ->resize($width, $height, function ($constraint) {
                    $constraint->aspectRatio();
                    // $constraint->upsize();
                })
                ->resizeCanvas($width, $height, 'center', false, null);

            $image->encode($format, 75)->save($fullNewPath, 75, $format);
        }

        return rtrim($this->siteUrl, '/') . '/image/' . str_replace($this->imageDir, '', $fullNewPath);
    }

    public function getUrl(string $path): string
    {
        return rtrim($this->siteUrl, '/') . '/image/' . str_replace($this->imageDir, '', $path);
    }

    public function getRealSize(string $path): array
    {
        $fullPath = $this->imageDir . $path;

        if (! is_file($fullPath)) {
            throw new \RuntimeException('Image file not found: ' . $path);
        }

        $img = $this->manager->make($fullPath);

        return [$img->getWidth(), $img->getHeight()];
    }

    public function cover(string $path, int $width, int $height, string $position = 'center'): ?string
    {
        $format = 'webp';

        if (! $width && ! $height) {
            throw new InvalidArgumentException('Width or height must be set');
        }

        if (! $path || ! is_file($this->imageDir . $path)) {
            return null;
        }

        $realPath = realpath($this->imageDir . $path);
        if (strpos($realPath, realpath($this->imageDir)) !== 0) {
            return null; // безопасность
        }

        $extless = substr($path, 0, strrpos($path, '.'));
        $imageNew = 'cache/' . $extless . '-' . $width . 'x' . $height . '.' . $format;

        $fullNewPath = $this->imageDir . $imageNew;
        $fullOldPath = $this->imageDir . $path;

        if (! is_file($fullNewPath) || filemtime($fullOldPath) > filemtime($fullNewPath)) {
            $dirPath = dirname($fullNewPath);
            if (! is_dir($dirPath)) {
                mkdir($dirPath, 0777, true);
            }

            $image = $this->manager->make($fullOldPath)
                ->fit($width, $height, function ($constraint) {
                    // $constraint->upsize();
                }, $position);

            $image->encode($format, 75)->save($fullNewPath, 75, $format);
        }

        return rtrim($this->siteUrl, '/') . '/image/' . str_replace($this->imageDir, '', $fullNewPath);
    }
}
