<?php

/*
 * This file is part of the VitiCore 2.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Imagine\Cache\Resolver;

use Liip\ImagineBundle\Binary\BinaryInterface;
use Liip\ImagineBundle\Imagine\Cache\Helper\PathHelper;
use Liip\ImagineBundle\Imagine\Cache\Resolver\ResolverInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Routing\RequestContext;

final class ImageResolverWithWebp implements ResolverInterface
{
    private string $webRoot;
    private string $cachePrefix;
    private string $cacheRoot;

    public function __construct(
        private readonly Filesystem $filesystem,
        private readonly RequestContext $requestContext,
        string $webRootDir,
        string $cachePrefix = 'media/cache',
    ) {
        $this->webRoot = mb_rtrim(str_replace('//', '/', $webRootDir), '/');
        $this->cachePrefix = mb_ltrim(str_replace('//', '/', $cachePrefix), '/');
        $this->cacheRoot = $this->webRoot.'/'.$this->cachePrefix;
    }

    public function resolve($path, $filter): string
    {
        return \sprintf(
            '%s/%s',
            mb_rtrim($this->getBaseUrl(), '/'),
            mb_ltrim($this->getFileUrl((string) $path, (string) $filter), '/')
        );
    }

    public function isStored($path, $filter): bool
    {
        return is_file($this->getFilePath((string) $path, (string) $filter));
    }

    public function store(BinaryInterface $binary, $path, $filter): void
    {
        $this->filesystem->dumpFile(
            $this->getFilePath((string) $path, (string) $filter),
            $binary->getContent()
        );
    }

    public function remove(array $paths, array $filters): void
    {
        if ([] === $paths && [] === $filters) {
            return;
        }

        if ([] === $paths) {
            $filtersCacheDir = [];
            foreach ($filters as $filter) {
                $filtersCacheDir[] = $this->cacheRoot.'/'.$filter;
            }
            $this->filesystem->remove($filtersCacheDir);

            return;
        }

        foreach ($paths as $path) {
            foreach ($filters as $filter) {
                $this->filesystem->remove($this->getFilePath((string) $path, (string) $filter));
            }
        }
    }

    protected function getFilePath(string $path, string $filter): string
    {
        if ($this->shouldUseWebp($path, $filter)) {
            return $this->webRoot.'/'.$this->getFullPath($path, $filter).'.webp';
        }

        return $this->webRoot.'/'.$this->getFullPath($path, $filter);
    }

    protected function getFileUrl(string $path, string $filter): string
    {
        if ($this->shouldUseWebp($path, $filter)) {
            return PathHelper::filePathToUrlPath($this->getFullPath($path, $filter).'.webp');
        }

        return PathHelper::filePathToUrlPath($this->getFullPath($path, $filter));
    }

    protected function getBaseUrl(): string
    {
        $port = '';

        if ('https' === $this->requestContext->getScheme() && 443 !== $this->requestContext->getHttpsPort()) {
            $port = ':'.$this->requestContext->getHttpsPort();
        }

        if ('http' === $this->requestContext->getScheme() && 80 !== $this->requestContext->getHttpPort()) {
            $port = ':'.$this->requestContext->getHttpPort();
        }

        $baseUrl = $this->requestContext->getBaseUrl();

        // si front controller dans l'URL (/index.php), on remonte d'un niveau
        if (str_ends_with($baseUrl, '.php')) {
            $baseUrl = pathinfo($baseUrl, \PATHINFO_DIRNAME);
        }

        $baseUrl = mb_rtrim((string) $baseUrl, '/\\');

        return \sprintf(
            '%s://%s%s%s',
            $this->requestContext->getScheme(),
            $this->requestContext->getHost(),
            $port,
            $baseUrl
        );
    }

    private function shouldUseWebp(string $path, string $filter): bool
    {
        if (!str_contains($filter, '_webp')) {
            return false;
        }

        // ne pas forcer webp pour svg
        return !str_ends_with(mb_strtolower($path), '.svg');
    }

    private function getFullPath(string $path, string $filter): string
    {
        // crude way of sanitizing URL scheme ("protocol") part
        $path = str_replace('://', '---', $path);

        return $this->cachePrefix.'/'.$filter.'/'.mb_ltrim($path, '/');
    }
}
