<?php declare(strict_types=1);

namespace App\Twig\Extension;

use Exception;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
use Twig\TwigFilter;
use App\Tool\Utils;
use Pimcore\Cache\RuntimeCache;

class UtilsExtension extends AbstractExtension
{
    public function getFunctions(): array
    {
        return [
            new TwigFunction('utils_url', [$this, 'url']),
            new TwigFunction('utils_image', [$this, 'utilsImage'], ['is_safe' => ['html']]),
            new TwigFunction('utils_thumbnail', [$this, 'utilsThumbnail'], ['is_safe' => ['html']]),
            new TwigFunction('utils_cut_string', [$this, 'utilsCutString']),
            new TwigFunction('utils_encode', [$this, 'utilsEncode']),
            new TwigFunction('utils_webalize', [$this, 'utilsWebalize']),
            new TwigFunction('utils_get_file_extension', [$this, 'utilsGetFileExtension']),
            new TwigFunction('utils_format_size_units', [$this, 'utilsFormatSizeUnits']),
            new TwigFunction('utils_call_static', [$this, 'utilsCallStatic']),
            new TwigFunction('utils_get_from_runtime_cache', [$this, 'getFromRuntimeCache']),
        ];
    }

    public function getFilters(): array
    {
        return [
            new TwigFilter('safe_email', [$this, 'safeEmail']),
            new TwigFilter('typo', [$this, 'typo'], ['is_safe' => ['html']]),
            new TwigFilter('ucfirst', [$this, 'ucfirst'], ['is_safe' => ['html']]),
        ];
    }

    public function safeEmail(string $email): string
    {
        return str_replace(['@', '.'], ['&#x00040;', '&#x0002E;'], $email);
    }

    public function typo(?string $text): string
    {
        $filtered = preg_replace(['/(\s+|&nbsp;)([aouiksvz])(\s+)/i'], ['$1$2&nbsp;'], $text);
        return preg_replace('/<p[^>]*>(\s|&nbsp;)*<\/p>/', '', $filtered);
    }

    public function ucfirst(?string $text): string
    {
        return ucfirst($text);
    }

    public function url(string $staticRoute, array $params): string
    {
        return Utils::url($staticRoute, $params);
    }

    public function utilsImage(mixed $image, string $thumbnail, mixed $fallbackImage = null, array $imgOptions = [], array $pictureOptions = []): string
    {
        return Utils::image($image, $thumbnail, $fallbackImage, $imgOptions, $pictureOptions);
    }

    public function utilsThumbnail(mixed $image, string $thumbnail, mixed $fallbackImage = null): string
    {
        return Utils::thumbnail($image, $thumbnail, $fallbackImage);
    }

    public function utilsCutString(string $string, int $length, string $suffix = '...'): string
    {
        return Utils::cutStringRespectingWhitespace($string, $length, $suffix);
    }

    public function utilsEncode(string $string, bool $isForJavaScript = false, bool $isForJavaScriptHTMLAttribute = false): string
    {
        if ($isForJavaScript) {
            return $isForJavaScriptHTMLAttribute ? htmlspecialchars(json_encode($string), ENT_QUOTES) : json_encode($string);
        }
        return htmlspecialchars($string, ENT_QUOTES);
    }

    public function utilsWebalize(mixed $path): string
    {
        return $path ? Utils::webalize($path) : '';
    }

    public function utilsGetFileExtension(string $filename): string
    {
        return Utils::getFileExtension($filename);
    }

    public function utilsFormatSizeUnits(int $size): string
    {
        return Utils::formatSizeUnits($size);
    }

    /**
     * @throws Exception
     */
    public function utilsCallStatic(string $class, string $method, mixed ...$args): mixed
    {
        if (!class_exists($class) || !method_exists($class, $method)) {
            throw new Exception("Cannot call static method $method on Class $class: Invalid Class or method");
        }
        return forward_static_call_array([$class, $method], $args);
    }

    public function getFromRuntimeCache(string $key): mixed
    {
        return RuntimeCache::isRegistered($key) ? RuntimeCache::get($key) : null;
    }
}
