<?php
declare(strict_types=1);

namespace Help4BuilderSuite\Modules\Performance;

use Help4BuilderSuite\Contracts\ModuleContract;
use Help4BuilderSuite\Support\Settings;
use WP_REST_Response;

if (! defined('ABSPATH')) {
    exit;
}

final class Module implements ModuleContract
{
    public function key(): string
    {
        return 'performance';
    }

    public function boot(): void
    {
        add_filter('script_loader_tag', [$this, 'deferScriptTag'], 20, 3);
        add_filter('wp_get_attachment_image_attributes', [$this, 'lazyloadAttributes'], 20, 3);
        add_action('send_headers', [$this, 'sendCacheHeaders']);
        add_action('save_post', [$this, 'purgeCachesOnChange'], 20);
        add_action('delete_post', [$this, 'purgeCachesOnChange'], 20);
        add_action('rest_api_init', [$this, 'registerRestRoutes']);
    }

    public function registerRestRoutes(): void
    {
        register_rest_route(
            'h4bs/v1',
            '/performance/status',
            [
                'methods'             => 'GET',
                'callback'            => [$this, 'statusRoute'],
                'permission_callback' => static fn (): bool => current_user_can('manage_options'),
            ]
        );
    }

    public function statusRoute(): WP_REST_Response
    {
        return new WP_REST_Response(
            [
                'imagick'            => extension_loaded('imagick'),
                'litespeed_detected' => defined('LSCWP_V'),
                'w3tc_detected'      => defined('W3TC'),
                'redis_object_cache' => function_exists('redis_object_cache_enable') || class_exists('RedisObjectCache'),
                'settings'           => [
                    'defer_scripts' => Settings::bool('perf_defer_scripts', true),
                    'lazyload'      => Settings::bool('perf_lazyload_images', true),
                    'cache_headers' => Settings::bool('perf_cache_headers', true),
                ],
            ]
        );
    }

    public function deferScriptTag(string $tag, string $handle, string $src): string
    {
        if (! Settings::bool('perf_defer_scripts', true)) {
            return $tag;
        }

        $deferHandles = [
            'h4bs-search',
            'h4bs-slider',
            'h4bs-builder-runtime',
            'h4bs-builder-admin',
        ];

        if (! in_array($handle, $deferHandles, true)) {
            return $tag;
        }

        if (str_contains($tag, ' defer')) {
            return $tag;
        }

        return str_replace('<script ', '<script defer ', $tag);
    }

    /**
     * @param array<string, string> $attributes
     * @param mixed $attachment
     * @param string|array{0: int, 1: int} $size
     * @return array<string, string>
     */
    public function lazyloadAttributes(array $attributes, $attachment, string|array $size): array
    {
        if (! Settings::bool('perf_lazyload_images', true)) {
            return $attributes;
        }

        if (($attributes['loading'] ?? '') === '') {
            $attributes['loading'] = 'lazy';
        }
        if (($attributes['decoding'] ?? '') === '') {
            $attributes['decoding'] = 'async';
        }

        return $attributes;
    }

    public function sendCacheHeaders(): void
    {
        if (! Settings::bool('perf_cache_headers', true)) {
            return;
        }

        if (is_user_logged_in() || is_admin()) {
            return;
        }

        if (! is_singular() && ! is_home() && ! is_archive()) {
            return;
        }

        header('Cache-Control: public, max-age=300, stale-while-revalidate=60');
        header('Vary: Accept-Encoding, Cookie');
    }

    public function purgeCachesOnChange(): void
    {
        if (get_transient('h4bs_cache_purge_recent')) {
            return;
        }
        set_transient('h4bs_cache_purge_recent', '1', 30);

        if (Settings::bool('perf_integrate_litespeed', true)) {
            // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Third-party LiteSpeed cache purge hook.
            do_action('litespeed_purge_all');
        }

        if (Settings::bool('perf_integrate_w3tc', true) && function_exists('w3tc_flush_all')) {
            w3tc_flush_all();
        }

        if (Settings::bool('perf_integrate_redis', true) && function_exists('wp_cache_flush')) {
            wp_cache_flush();
        }
    }
}
