<?php

/*
 * This file is part of the Yabe package.
 *
 * (c) Joshua <id@rosua.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
declare (strict_types=1);
namespace Fancy\Animations\Core;

use Fancy\Animations\Utils\Asset;
use Fancy\Animations\Utils\Common;
use Fancy\Animations\Utils\Notice;
use _FancyAnimations\FANCY_ANIMATIONS;
use _FancyAnimations\Sabberworm\CSS\CSSList\CSSList;
use _FancyAnimations\Sabberworm\CSS\CSSList\Document;
use _FancyAnimations\Sabberworm\CSS\CSSList\KeyFrame;
use _FancyAnimations\Sabberworm\CSS\Parser;
use _FancyAnimations\Sabberworm\CSS\RuleSet\DeclarationBlock;
use _FancyAnimations\Spatie\Color\Factory as ColorFactory;
/**
 * Manage the cache of fonts for the frontpage.
 *
 * @author Joshua <id@rosua.org>
 */
class Cache
{
    /**
     * @var string
     */
    public const CACHE_DIR = '/fancy-animations/cache/';
    /**
     * @var string
     */
    public const CSS_CACHE_FILE = 'style.css';
    public function __construct()
    {
        \add_filter('cron_schedules', fn($schedules) => $this->filter_cron_schedules($schedules));
        \add_action('a!fancy/animations/core/cache:build_cache', fn() => $this->build_cache());
        \add_action('a!fancy/animations/core/cache:schedule_cache', static fn() => static::schedule_cache());
        // listen to Config change for cache build (async/scheduled)
        \add_action('a!fancy/animations/api/admin/dashboard:store.after', fn() => $this->build_cache(), 10, 1);
    }
    public function filter_cron_schedules($schedules)
    {
        $schedules['fancy_animations_cache'] = ['interval' => \MINUTE_IN_SECONDS, 'display' => \__('Every minute', 'fancy-animations')];
        return $schedules;
    }
    public static function schedule_cache(int $delay = 1)
    {
        if (!\wp_next_scheduled('a!fancy/animations/core/cache:build_cache')) {
            \wp_schedule_single_event(\time() + $delay, 'a!fancy/animations/core/cache:build_cache');
        }
    }
    public static function get_cache_path(string $file_path = '') : string
    {
        return \wp_upload_dir()['basedir'] . self::CACHE_DIR . $file_path;
    }
    public static function get_cache_url(string $file_path = '') : string
    {
        return \wp_upload_dir()['baseurl'] . self::CACHE_DIR . $file_path;
    }
    public function build_cache()
    {
        $fba_selectors = \file_get_contents(\dirname(FANCY_ANIMATIONS::FILE) . '/build/builder-selectors.json');
        $fba_selectors = \json_decode($fba_selectors, \true, 512, \JSON_THROW_ON_ERROR)['classes'];
        $selectors = \apply_filters('f!fancy/animations/core/cache:selectors', []);
        // get the intersection of $fba_selectors and $selectors
        $intersect = \array_intersect($fba_selectors, $selectors);
        $iframeCssManifest = Asset::read_manifest()['builder-iframe.css'];
        if (\strpos($iframeCssManifest, 'http') === 0) {
            $styleCss = \file_get_contents($iframeCssManifest);
        } else {
            $styleCss = \file_get_contents(\dirname(FANCY_ANIMATIONS::FILE) . '/build/' . $iframeCssManifest);
        }
        $css = self::composeCustomCss();
        $css .= "\n" . self::collect_css($styleCss, $intersect);
        $payload = \sprintf("/*\n! %s v%s | %s\n*/\n\n%s", Common::plugin_data('Name'), FANCY_ANIMATIONS::VERSION, \date('Y-m-d H:i:s', \time()), $css);
        // write the collected css to cache
        try {
            Common::save_file($payload, self::get_cache_path(self::CSS_CACHE_FILE));
            $this->purge_cache_plugin();
        } catch (\Throwable $throwable) {
            Notice::error(\sprintf('Failed to build Fonts CSS cache: %s', $throwable->getMessage()));
        }
    }
    public static function collect_css($raw, $selectors) : string
    {
        $css = '';
        $parser = new Parser($raw);
        $rawCssDocument = $parser->parse();
        $newCssDocument = new Document();
        $eligibleItems = [];
        static::eligibleCss($rawCssDocument, $selectors, $eligibleItems);
        foreach ($eligibleItems as $eligibleItem) {
            $newCssDocument->append($eligibleItem);
        }
        return $newCssDocument->render();
    }
    public static function eligibleCss(&$document, $mSelectors, &$eligibles = []) : array
    {
        foreach ($document->getContents() as $iKey => &$content) {
            if (!$content instanceof DeclarationBlock && !$content instanceof CSSList) {
                continue;
            }
            if ($content instanceof DeclarationBlock) {
                $itemSelectors = $content->getSelectors();
                foreach ($mSelectors as $mSelector) {
                    foreach ($itemSelectors as $itemSelector) {
                        $pattern = '#%s(?![a-zA-Z0-9\\_\\-\\,])#';
                        if (\preg_match(\sprintf($pattern, \sprintf('\\.%s', $mSelector)), $itemSelector->getSelector())) {
                            $eligibles[] = $content;
                        }
                    }
                }
            } elseif ($content instanceof KeyFrame) {
                foreach ($mSelectors as $mSelector) {
                    if ($mSelector === $content->getAnimationName()) {
                        $eligibles[] = $content;
                    }
                }
            }
        }
        return $eligibles;
    }
    public static function composeCustomCss() : string
    {
        $options = \json_decode(\get_option(FANCY_ANIMATIONS::WP_OPTION . '_options', \json_encode((object) FANCY_ANIMATIONS::DEFAULT_SETTINGS, \JSON_THROW_ON_ERROR)), null, 512, \JSON_THROW_ON_ERROR);
        $options = \apply_filters('f!fancy/animations/api/admin/setting:index', $options);
        $props = [];
        try {
            $props[] = \sprintf('--fba-delay: %ss;', $options->animation_delay);
            $props[] = \sprintf('--fba-duration: %ss;', $options->animation_time);
            $colors = ['primary' => ColorFactory::fromString($options->primary_color)->toRgba(), 'secondary' => ColorFactory::fromString($options->secondary_color)->toRgba(), 'white' => ColorFactory::fromString($options->white_color)->toRgba(), 'black' => ColorFactory::fromString($options->black_color)->toRgba()];
            foreach ($colors as $colorName => $color) {
                $props[] = \sprintf('--fba-%s-r: %s;', $colorName, $color->red());
                $props[] = \sprintf('--fba-%s-g: %s;', $colorName, $color->green());
                $props[] = \sprintf('--fba-%s-b: %s;', $colorName, $color->blue());
                $props[] = \sprintf('--fba-%s-a: %s;', $colorName, $color->alpha());
                $props[] = \sprintf('--fba-%1$s-trans-30: rgba(var(--fba-%1$s-r), var(--fba-%1$s-g), var(--fba-%1$s-b), 0.3);', $colorName);
                $props[] = \sprintf('--fba-%1$s-trans-50: rgba(var(--fba-%1$s-r), var(--fba-%1$s-g), var(--fba-%1$s-b), 0.5);', $colorName);
                $props[] = \sprintf('--fba-%1$s-trans-80: rgba(var(--fba-%1$s-r), var(--fba-%1$s-g), var(--fba-%1$s-b), 0.8);', $colorName);
            }
        } catch (\Throwable $throwable) {
            //throw $th;
        }
        $css = \sprintf(':root{%s}', \implode('', $props));
        $frontendGlobalCssManifest = Asset::read_manifest()['frontend/global.css'];
        if (\strpos($frontendGlobalCssManifest, 'http') === 0) {
            $css .= "\n" . \file_get_contents($frontendGlobalCssManifest);
        } else {
            $css .= "\n" . \file_get_contents(\dirname(FANCY_ANIMATIONS::FILE) . '/build/' . $frontendGlobalCssManifest);
        }
        return $css;
    }
    /**
     * Clear the cache from various cache plugins.
     */
    private function purge_cache_plugin()
    {
        /**
         * WordPress Object Cache
         * @see https://developer.wordpress.org/reference/classes/wp_object_cache/
         */
        \wp_cache_flush();
        /**
         * WP Rocket
         * @see https://docs.wp-rocket.me/article/92-rocketcleandomain
         */
        if (\function_exists('rocket_clean_domain')) {
            \rocket_clean_domain();
        }
        /**
         * WP Super Cache
         * @see https://github.com/Automattic/wp-super-cache/blob/a0872032b1b3fc6847f490eadfabf74c12ad0135/wp-cache-phase2.php#L3013
         */
        if (\function_exists('wp_cache_clear_cache')) {
            \wp_cache_clear_cache();
        }
        /**
         * W3 Total Cache
         * @see https://github.com/BoldGrid/w3-total-cache/blob/3a094493064ea60d727b3389dee813639860ef49/w3-total-cache-api.php#L259
         */
        if (\function_exists('w3tc_flush_all')) {
            \w3tc_flush_all();
        }
        /**
         * WP Fastest Cache
         * @see https://www.wpfastestcache.com/tutorial/delete-the-cache-by-calling-the-function/
         */
        if (\function_exists('wpfc_clear_all_cache')) {
            \wpfc_clear_all_cache(\true);
        }
        /**
         * LiteSpeed Cache
         * @see https://docs.litespeedtech.com/lscache/lscwp/api/#purge-all-existing-caches
         */
        \do_action('litespeed_purge_all');
    }
}
