<?php

declare(strict_types=1);

namespace FleekDash\Frontend;

/**
 * LoginStylesGuard - Blocks theme and plugin CSS/JS from loading on custom login page.
 *
 * Uses multiple layers to ensure no third-party assets interfere:
 * 1. style_loader_tag / script_loader_tag: Returns empty string for non-whitelisted handles
 * 2. wp_enqueue_scripts (9999) + wp_print_styles (1): Dequeue right before output
 * 3. wp_head output buffering: Strips link tags that themes/plugins inject directly
 *    (e.g. Divi's et-divi-customizer.min.css via wp_head callback)
 */
class LoginStylesGuard
{
    /** @var array<int, string> */
    private static array $allowedStyleHandles = [
        'admin-bar',
        'wp-auth-check',
        'colors',
        'dashicons',
    ];

    /** @var array<int, string> */
    private static array $allowedScriptHandles = [
        'fleekdash-login',
        'wp-polyfill',
        'wp-i18n',
        'wp-hooks',
        'wp-api-fetch',
        'wp-url',
        'wp-element',
        'react',
        'react-dom',
        'lodash',
        'jquery',
        'jquery-core',
        'jquery-migrate',
        'vite-client',
    ];

    /**
     * Register all style/script-blocking hooks. Must run early in bootstrap.
     */
    public static function bootstrap(): void
    {
        \add_filter('style_loader_tag', [self::class, 'filterStyleLoaderTag'], 999, 4);
        \add_filter('script_loader_tag', [self::class, 'filterScriptLoaderTag'], 999, 3);
        \add_action('wp_enqueue_scripts', [self::class, 'dequeueThemeAndPluginAssets'], 9999);
        \add_action('wp_print_styles', [self::class, 'dequeueThemeAndPluginStyles'], 1);
        \add_action('wp_print_scripts', [self::class, 'dequeueThemeAndPluginAssets'], 1);
        \add_action('wp_head', [self::class, 'startHeadOutputBuffer'], 1);
        \add_action('wp_head', [self::class, 'flushAndFilterHeadOutput'], 99999);
        \add_action('wp_footer', [self::class, 'startFooterOutputBuffer'], 1);
        \add_action('wp_footer', [self::class, 'flushAndFilterFooterOutput'], 99999);
    }

    /**
     * Check if we're on the FleekDash custom login page.
     */
    public static function isLoginPage(): bool
    {
        if (isset($_GET['fleek_login']) && $_GET['fleek_login'] === '1') {
            return true;
        }
        if (isset($_GET['fleekpage']) && $_GET['fleekpage'] === 'login') {
            return true;
        }

        $page_id = \get_option('fleekdash_login_page_id');
        if ($page_id && \is_page((int) $page_id)) {
            return true;
        }
        if (!$page_id && \is_page('login')) {
            return true;
        }

        global $wp_query;
        if ($page_id && isset($wp_query->queried_object_id) && (int) $wp_query->queried_object_id === (int) $page_id) {
            return true;
        }

        $queried_object = \get_queried_object();
        if ($queried_object && isset($queried_object->ID) && $page_id && (int) $queried_object->ID === (int) $page_id) {
            return true;
        }

        return false;
    }

    /**
     * style_loader_tag: Block non-whitelisted styles.
     *
     * @param string $tag    The link tag for the enqueued style.
     * @param string $handle The style's registered handle.
     * @param string $href   The stylesheet's source URL.
     * @param string $media  The stylesheet's media attribute.
     */
    public static function filterStyleLoaderTag(string $tag, string $handle, string $href, string $media): string
    {
        if (!self::isLoginPage()) {
            return $tag;
        }
        if (self::isAllowedStyleHandle($handle)) {
            return $tag;
        }
        return '';
    }

    /**
     * script_loader_tag: Block non-whitelisted scripts.
     */
    public static function filterScriptLoaderTag(string $tag, string $handle, string $src): string
    {
        if (!self::isLoginPage()) {
            return $tag;
        }
        if (self::isAllowedScriptHandle($handle)) {
            return $tag;
        }
        return '';
    }

    /**
     * Dequeue theme and plugin scripts and styles.
     */
    public static function dequeueThemeAndPluginAssets(): void
    {
        if (!self::isLoginPage()) {
            return;
        }

        global $wp_scripts;
        if ($wp_scripts instanceof \WP_Scripts) {
            $queue = isset($wp_scripts->queue) && \is_array($wp_scripts->queue) ? $wp_scripts->queue : [];
            foreach ($queue as $handle) {
                if (self::isAllowedScriptHandle($handle)) {
                    continue;
                }
                \wp_dequeue_script($handle);
                \wp_deregister_script($handle);
            }
        }

        self::dequeueThemeAndPluginStyles();
    }

    /**
     * Dequeue theme and plugin styles from the queue.
     */
    public static function dequeueThemeAndPluginStyles(): void
    {
        if (!self::isLoginPage()) {
            return;
        }

        global $wp_styles;
        if (!($wp_styles instanceof \WP_Styles)) {
            return;
        }

        $queue = isset($wp_styles->queue) && \is_array($wp_styles->queue) ? $wp_styles->queue : [];
        foreach ($queue as $handle) {
            if (self::isAllowedStyleHandle($handle)) {
                continue;
            }
            \wp_dequeue_style($handle);
            \wp_deregister_style($handle);
        }
    }

    /**
     * Start output buffering to capture wp_head output for filtering.
     */
    public static function startHeadOutputBuffer(): void
    {
        if (!self::isLoginPage()) {
            return;
        }

        \ob_start(static function (string $html): string {
            return self::filterHeadAssets($html);
        });
    }

    /**
     * Flush the head buffer (filtering happens in ob_start callback).
     */
    public static function flushAndFilterHeadOutput(): void
    {
        if (!self::isLoginPage()) {
            return;
        }

        if (\ob_get_level() > 0) {
            \ob_end_flush();
        }
    }

    /**
     * Start output buffering to capture wp_footer output.
     * Blocks scripts from WooCommerce Coming Soon, themes, etc.
     */
    public static function startFooterOutputBuffer(): void
    {
        if (!self::isLoginPage()) {
            return;
        }

        \ob_start(static function (string $html): string {
            return self::filterFooterScripts($html);
        });
    }

    /**
     * Flush the footer buffer (filtering happens in ob_start callback).
     */
    public static function flushAndFilterFooterOutput(): void
    {
        if (!self::isLoginPage()) {
            return;
        }

        if (\ob_get_level() > 0) {
            \ob_end_flush();
        }
    }

    /**
     * Filter out theme/plugin stylesheet links and script tags from head HTML.
     * Catches assets that bypass wp_enqueue (e.g. Divi, WooCommerce Coming Soon).
     */
    public static function filterHeadAssets(string $html): string
    {
        $contentUrl = \content_url();
        $fleekdashSlug = 'fleekdash';

        $html = (string) \preg_replace_callback(
            '/<link([^>]*)\s+rel\s*=\s*[\'"]stylesheet[\'"]([^>]*)>/i',
            static function (array $m) use ($contentUrl, $fleekdashSlug): string {
                $fullTag = $m[0];
                if (!\preg_match('/href\s*=\s*[\'"]([^\'"]+)[\'"]/i', $fullTag, $hrefMatch)) {
                    return $fullTag;
                }
                return self::shouldKeepStylesheet($hrefMatch[1], $contentUrl, $fleekdashSlug) ? $fullTag : '';
            },
            $html
        );

        $html = (string) \preg_replace_callback(
            '/<script\s+[^>]*src\s*=\s*[\'"]([^\'"]+)[\'"][^>]*>[\s\S]*?<\/script>/i',
            static function (array $m) use ($fleekdashSlug): string {
                $href = $m[1];
                return self::shouldKeepScript($href, $fleekdashSlug) ? $m[0] : '';
            },
            $html
        );

        return $html;
    }

    /**
     * Filter out theme/plugin script tags from footer HTML.
     * Catches WooCommerce Coming Soon, overlay scripts, etc.
     */
    public static function filterFooterScripts(string $html): string
    {
        $fleekdashSlug = 'fleekdash';

        return (string) \preg_replace_callback(
            '/<script\s+[^>]*src\s*=\s*[\'"]([^\'"]+)[\'"][^>]*>[\s\S]*?<\/script>/i',
            static function (array $m) use ($fleekdashSlug): string {
                return self::shouldKeepScript($m[1], $fleekdashSlug) ? $m[0] : '';
            },
            $html
        );
    }

    public static function shouldKeepScript(string $src, string $fleekdashSlug): bool
    {
        $srcLower = \strtolower($src);

        if (\strpos($srcLower, $fleekdashSlug) !== false) {
            return true;
        }
        if (\strpos($srcLower, 'wp-includes') !== false) {
            return true;
        }
        if (\strpos($srcLower, 'load-scripts.php') !== false) {
            return true;
        }
        if (\strpos($srcLower, 'wp-admin') !== false) {
            return true;
        }

        if (\strpos($srcLower, 'woocommerce') !== false && \strpos($srcLower, $fleekdashSlug) === false) {
            return false;
        }
        if (\strpos($srcLower, 'et-cache') !== false || \strpos($srcLower, 'et-divi') !== false) {
            return false;
        }
        if (\strpos($srcLower, '/themes/') !== false) {
            return false;
        }

        $contentUrl = \content_url();
        if (\strpos($src, $contentUrl) !== false && \strpos($srcLower, '/plugins/') !== false) {
            return false;
        }

        return true;
    }

    public static function shouldKeepStylesheet(string $href, string $contentUrl, string $fleekdashSlug): bool
    {
        $hrefLower = \strtolower($href);

        if (\strpos($hrefLower, $fleekdashSlug) !== false) {
            return true;
        }
        if (\strpos($hrefLower, 'wp-includes') !== false) {
            return true;
        }
        if (\strpos($hrefLower, 'load-styles.php') !== false) {
            return true;
        }
        if (\strpos($hrefLower, 'wp-admin') !== false) {
            return true;
        }

        if (\strpos($hrefLower, 'et-cache') !== false || \strpos($hrefLower, 'et-divi') !== false) {
            return false;
        }
        if (\strpos($hrefLower, '/themes/') !== false) {
            return false;
        }
        if (\strpos($href, $contentUrl) !== false && \strpos($hrefLower, '/plugins/') !== false) {
            return false;
        }

        return true;
    }

    private static function isAllowedStyleHandle(string $handle): bool
    {
        if (\strpos($handle, 'fleekdash') === 0) {
            return true;
        }
        if (\strpos($handle, 'query-monitor') === 0) {
            return true;
        }
        return \in_array($handle, self::$allowedStyleHandles, true);
    }

    private static function isAllowedScriptHandle(string $handle): bool
    {
        if (\strpos($handle, 'fleekdash') === 0) {
            return true;
        }
        if (\strpos($handle, 'query-monitor') === 0) {
            return true;
        }
        return \in_array($handle, self::$allowedScriptHandles, true);
    }
}
