<?php
declare(strict_types=1);

namespace ProRank\SEO\Integrations\Divi;

use ProRank\SEO\Plugin;

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

/**
 * Divi Builder integration for ProRank SEO.
 *
 * Enqueues the SEO meta-box panel inside the Divi Visual Builder (frontend)
 * and ensures the content bridge works in the Backend Builder (BFB).
 *
 * BFB runs inside wp-admin post.php, so the standard meta-box already loads;
 * only VB needs explicit asset enqueuing and panel rendering.
 */
class DiviIntegration {

    private static ?self $instance = null;

    public static function get_instance(): self {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        if (!$this->is_divi_active()) {
            return;
        }

        $this->init_hooks();
    }

    private function is_divi_active(): bool {
        return defined('ET_BUILDER_VERSION');
    }

    /**
     * Is this a Divi Visual Builder (frontend) request?
     */
    private function is_visual_builder(): bool {
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        return isset($_GET['et_fb']) && $_GET['et_fb'] === '1';
    }

    private function init_hooks(): void {
        // VB: enqueue assets on the frontend when ?et_fb=1
        add_action('wp_enqueue_scripts', [$this, 'enqueue_vb_scripts'], 20);

        // VB: render floating panel in footer
        add_action('wp_footer', [$this, 'render_vb_panel'], 90);

        // Prevent our script from loading inside Divi's content iframe + add type="module"
        add_filter('script_loader_tag', [$this, 'add_iframe_ignore_class'], 10, 2);

        // VB: render importmap for Vite ESM bare specifiers (@wordpress/*, react)
        add_action('wp_head', [$this, 'render_import_map'], 1);
    }

    /**
     * Enqueue meta-box assets in the Visual Builder.
     */
    public function enqueue_vb_scripts(): void {
        if (!$this->is_visual_builder()) {
            return;
        }

        $post_id = get_the_ID();
        if (!$post_id || $post_id <= 0) {
            return;
        }

        $post_type = get_post_type($post_id);
        if (!is_string($post_type) || $post_type === '') {
            return;
        }

        $public_post_types = get_post_types(['public' => true], 'names');
        if (!in_array($post_type, $public_post_types, true)) {
            return;
        }

        if (!$this->is_meta_box_enabled($post_type)) {
            return;
        }

        $script_path = PRORANK_PLUGIN_DIR . 'build/meta-box.js';
        if (!file_exists($script_path)) {
            return;
        }

        $script_url = PRORANK_PLUGIN_URL . 'build/meta-box.js';
        $asset_file = PRORANK_PLUGIN_DIR . 'build/meta-box.asset.php';
        $asset_data = file_exists($asset_file) ? require $asset_file : [];
        $dependencies = $asset_data['dependencies'] ?? ['wp-element', 'wp-components', 'wp-i18n', 'wp-data', 'wp-api-fetch', 'wp-dom-ready', 'lodash'];
        $version = \ProRank\SEO\Admin\MetaBox::resolve_meta_box_script_version();

        wp_enqueue_script('prorank-seo-meta-box', $script_url, $dependencies, $version, true);
        wp_enqueue_style('prorank-seo-meta-box', \ProRank\SEO\Admin\MetaBox::resolve_meta_box_css(), [], $version);

        [$license_tier, $is_premium_active] = $this->resolve_license_context();

        wp_localize_script(
            'prorank-seo-meta-box',
            'prorankMetaboxData',
            [
                'licenseTier'     => $license_tier,
                'isPremiumActive' => $is_premium_active,
                'postId'          => $post_id,
                'postType'        => $post_type,
                'nonce'           => wp_create_nonce('prorank_seo_metabox'),
                'apiUrl'          => rest_url('prorank-seo/v1'),
            ]
        );

        $inline = 'window.prorankSettings = window.prorankSettings || {};';
        $inline .= 'window.prorankSettings.adminUrl = ' . wp_json_encode(admin_url()) . ';';
        $inline .= 'window.prorankSettings.upgradeUrl = ' . wp_json_encode('https://prorank.io/pricing') . ';';
        $inline .= 'window.prorankSettings.isPremiumActive = ' . ($is_premium_active ? 'true' : 'false') . ';';
        $inline .= 'window.prorankSettings.license = window.prorankSettings.license || {};';
        $inline .= 'window.prorankSettings.license.tier = ' . wp_json_encode($license_tier) . ';';
        wp_add_inline_script('prorank-seo-meta-box', $inline, 'before');

        wp_set_script_translations('prorank-seo-meta-box', 'prorank-seo', PRORANK_PLUGIN_DIR . 'languages');
    }

    /**
     * Render importmap for Vite ESM bare specifiers on the frontend VB.
     *
     * In wp-admin this is handled by AdminScripts::render_import_map().
     * The VB runs on the frontend, so we output it here.
     */
    public function render_import_map(): void {
        if (!$this->is_visual_builder()) {
            return;
        }

        $base_url = PRORANK_PLUGIN_URL . 'build/shims/';

        $imports = [
            '@wordpress/dom-ready'          => $base_url . 'wp-dom-ready.js',
            '@wordpress/element'            => $base_url . 'wp-element.js',
            '@wordpress/components'         => $base_url . 'wp-components.js',
            '@wordpress/i18n'               => $base_url . 'wp-i18n.js',
            '@wordpress/api-fetch'          => $base_url . 'wp-api-fetch.js',
            '@wordpress/data'               => $base_url . 'wp-data.js',
            '@wordpress/hooks'              => $base_url . 'wp-hooks.js',
            '@wordpress/icons'              => $base_url . 'wp-icons.js',
            '@wordpress/compose'            => $base_url . 'wp-compose.js',
            '@wordpress/date'               => $base_url . 'wp-date.js',
            '@wordpress/block-editor'       => $base_url . 'wp-block-editor.js',
            '@wordpress/url'                => $base_url . 'wp-url.js',
            '@wordpress/plugins'            => $base_url . 'wp-data.js',
            '@wordpress/editor'             => $base_url . 'wp-data.js',
            '@wordpress/blocks'             => $base_url . 'wp-data.js',
            '@wordpress/edit-post'          => $base_url . 'wp-data.js',
            '@wordpress/rich-text'          => $base_url . 'wp-data.js',
            '@wordpress/server-side-render' => $base_url . 'wp-data.js',
            '@wordpress/notices'            => $base_url . 'wp-data.js',
            '@wordpress/primitives'         => $base_url . 'wp-data.js',
            'react'                         => $base_url . 'react.js',
            'react-dom'                     => $base_url . 'react-dom.js',
            'react/jsx-runtime'             => $base_url . 'jsx-runtime.js',
        ];

        echo '<script type="importmap">' . "\n";
        echo wp_json_encode(['imports' => $imports], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";
        echo '</script>' . "\n";
    }

    /**
     * Add et_fb_ignore_iframe class and type="module" for Vite ESM output.
     *
     * AdminScripts::add_module_type() only fires in is_admin() context.
     * The VB runs on the frontend, so we must add type="module" here.
     */
    public function add_iframe_ignore_class(string $tag, string $handle): string {
        if ($handle !== 'prorank-seo-meta-box') {
            return $tag;
        }

        if (!$this->is_visual_builder()) {
            return $tag;
        }

        // type="module" — required for Vite ESM import/import.meta.url
        if (strpos($tag, 'type="module"') === false && strpos($tag, "type='module'") === false) {
            $tag = str_replace(' src=', ' type="module" src=', $tag);
        }

        // et_fb_ignore_iframe — prevent Divi from mirroring into content iframe
        if (strpos($tag, 'et_fb_ignore_iframe') === false) {
            $tag = str_replace(' src=', ' class="et_fb_ignore_iframe" src=', $tag);
        }

        return $tag;
    }

    /**
     * Render floating SEO panel in the Visual Builder.
     */
    public function render_vb_panel(): void {
        if (!$this->is_visual_builder()) {
            return;
        }

        $post_id = get_the_ID();
        if (!$post_id || $post_id <= 0) {
            return;
        }

        ?>
        <style id="prorank-divi-seo-panel-style">
            #prorank-divi-seo-app {
                position: fixed;
                right: 18px;
                bottom: 18px;
                z-index: 100000;
                display: flex;
                flex-direction: column;
                align-items: flex-end;
                gap: 8px;
            }
            #prorank-divi-seo-toggle {
                background: #2563eb;
                color: #fff;
                border: 0;
                border-radius: 999px;
                padding: 8px 14px;
                font-size: 12px;
                font-weight: 600;
                cursor: pointer;
                box-shadow: 0 8px 24px rgba(0,0,0,.18);
                display: inline-flex;
                align-items: center;
                justify-content: center;
                width: 40px;
                height: 40px;
                min-width: 40px;
            }
            #prorank-divi-seo-toggle .prorank-divi-icon {
                width: 22px;
                height: 22px;
                display: block;
                border-radius: 4px;
            }
            #prorank-divi-seo-toggle .prorank-divi-fallback {
                display: none;
                font-size: 12px;
                font-weight: 700;
                line-height: 1;
            }
            #prorank-divi-seo-toggle.icon-fallback .prorank-divi-icon {
                display: none;
            }
            #prorank-divi-seo-toggle.icon-fallback .prorank-divi-fallback {
                display: block;
            }
            #prorank-divi-seo-panel {
                position: fixed;
                right: 14px;
                bottom: 70px;
                width: min(430px, calc(100vw - 32px));
                max-height: calc(100vh - 90px);
                overflow: auto;
                background: #fff;
                border: 1px solid #dcdcde;
                border-radius: 10px;
                box-shadow: 0 12px 38px rgba(0,0,0,.22);
                display: none;
            }
            #prorank-divi-seo-panel.is-open {
                display: block;
            }
            #prorank-divi-seo-head {
                display: flex;
                align-items: center;
                justify-content: space-between;
                padding: 10px 12px;
                border-bottom: 1px solid #dcdcde;
                font-weight: 600;
                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
                font-size: 13px;
            }
            #prorank-divi-seo-close {
                background: transparent;
                border: 0;
                color: #50575e;
                cursor: pointer;
                font-size: 18px;
                line-height: 1;
                padding: 0 4px;
            }
            #prorank-divi-seo-body {
                padding: 10px;
            }
        </style>
        <div id="prorank-divi-seo-app" class="et_fb_ignore_iframe">
            <div id="prorank-divi-seo-panel" aria-live="polite">
                <div id="prorank-divi-seo-head">
                    <span><?php esc_html_e('ProRank SEO', 'prorank-seo'); ?></span>
                    <button type="button" id="prorank-divi-seo-close" aria-label="<?php esc_attr_e('Close', 'prorank-seo'); ?>">&times;</button>
                </div>
                <div id="prorank-divi-seo-body">
                    <div id="prorank-seo-metabox-root"></div>
                </div>
            </div>
            <button type="button" id="prorank-divi-seo-toggle" aria-label="<?php esc_attr_e('Open ProRank SEO', 'prorank-seo'); ?>" title="<?php esc_attr_e('ProRank SEO', 'prorank-seo'); ?>">
                <img class="prorank-divi-icon" src="<?php echo esc_url(PRORANK_PLUGIN_URL . 'assets/images/favicon.png'); ?>" alt="" aria-hidden="true" />
                <span class="prorank-divi-fallback">PR</span>
            </button>
        </div>
        <script id="prorank-divi-seo-panel-script">
            (function () {
                var panel = document.getElementById('prorank-divi-seo-panel');
                var toggle = document.getElementById('prorank-divi-seo-toggle');
                var close = document.getElementById('prorank-divi-seo-close');
                var icon = toggle ? toggle.querySelector('.prorank-divi-icon') : null;

                if (!panel || !toggle || !close) return;

                if (icon) {
                    icon.addEventListener('error', function () { toggle.classList.add('icon-fallback'); });
                    if (icon.complete && (!icon.naturalWidth || icon.naturalWidth <= 0)) {
                        toggle.classList.add('icon-fallback');
                    }
                } else {
                    toggle.classList.add('icon-fallback');
                }

                toggle.addEventListener('click', function () {
                    var open = !panel.classList.contains('is-open');
                    panel.classList.toggle('is-open', open);
                    toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
                });

                close.addEventListener('click', function () {
                    panel.classList.remove('is-open');
                    toggle.setAttribute('aria-expanded', 'false');
                });
            })();
        </script>
        <?php
    }

    private function is_meta_box_enabled(string $post_type): bool {
        $settings = get_option('prorank_seo_titles_meta', []);
        if (!is_array($settings) || empty($settings)) {
            $settings = get_option('prorank_titles_meta_settings', []);
        }

        if (!is_array($settings)) {
            return true;
        }

        $post_type_settings = $settings['post_type_' . $post_type] ?? [];
        if (!is_array($post_type_settings)) {
            return true;
        }

        return $post_type_settings['show_meta_box'] ?? true;
    }

    private function resolve_license_context(): array {
        return ['free', false];
    }
}
