<?php

namespace WPSN\Modules\PageBuilders;

use WPSN\Core\AbstractModule;
use WPSN\Core\Branding;
use WPSN\SEO\MetaKeys;
use WPSN\SEO\SeoMetaRepository;
use WPSN\Domain\SeoDocumentContext;

defined('ABSPATH') || exit;

/**
 * Page Builders Integration (Elementor / Divi / Beaver)
 *
 * MVP scope:
 * - Provide rendered HTML for content extraction (analysis/excerpt/AI prompts).
 * - Optional: expose SEO Title/Description controls inside Elementor editor.
 * - Extra adapters can be toggled in Settings → Integrations.
 */
final class PageBuildersModule extends AbstractModule
{
    public function id(): string
    {
        return 'page_builders';
    }

    public function name(): string
    {
        return __('Page Builders Integration', 'wp-seo-next');
    }

    public function description(): string
    {
        return __('Extracts page builder content (Elementor/Divi/Beaver) for better descriptions/readability and (optionally) adds Elementor editor controls.', 'wp-seo-next');
    }

    public function defaultEnabled(): bool
    {
        return true;
    }

    public function register(): void
    {
        // Elementor content adapter.
        if ((bool) $this->settings->get('integrations.elementor.enabled', true)) {
            add_filter('wpsn/content/builder_html', [$this, 'elementorBuilderHtml'], 10, 3);
        }

        // Divi content adapter.
        if ((bool) $this->settings->get('integrations.divi.enabled', true)) {
            add_filter('wpsn/content/builder_html', [$this, 'diviBuilderHtml'], 11, 3);
        }

        // Beaver Builder content adapter.
        if ((bool) $this->settings->get('integrations.beaver.enabled', true)) {
            add_filter('wpsn/content/builder_html', [$this, 'beaverBuilderHtml'], 12, 3);
        }

        // Optional: Elementor editor controls.
        if (is_admin() && (bool) $this->settings->get('integrations.elementor.editor_controls', true)) {
            add_action('elementor/documents/register_controls', [$this, 'registerElementorControls']);
            add_action('elementor/document/after_save', [$this, 'saveElementorControls'], 10, 2);
        }

        // Universal SEO panel inside front-end builders (Divi/Beaver).
        add_action('wp_enqueue_scripts', [$this, 'maybeEnqueueUniversalMetabox'], 999);
        add_action('wp_footer', [$this, 'maybeRenderUniversalMetabox'], 999);
    }

    public function maybeEnqueueUniversalMetabox(): void
    {
        if (is_admin()) {
            return;
        }

        $ctx = $this->universalMetaboxContext();
        if (!$ctx) {
            return;
        }

        $postId = (int) ($ctx['post_id'] ?? 0);
        if ($postId <= 0 || !current_user_can('edit_post', $postId)) {
            return;
        }

        // If Automation REST is disabled, the overlay cannot load/save.
        if (!(bool) $this->settings->get('automation.rest.enabled', true)) {
            return;
        }

        wp_enqueue_style(
            'wpsn-universal-metabox',
            WPSN_PLUGIN_URL . 'assets/admin/universal-metabox.css',
            [],
            WPSN_VERSION
        );

        wp_enqueue_script(
            'wpsn-universal-metabox',
            WPSN_PLUGIN_URL . 'assets/admin/universal-metabox.js',
            [],
            WPSN_VERSION,
            true
        );

        $brand = Branding::labelWithBrand($this->settings, __('SEO', 'wp-seo-next'));

        // Deep links into WP admin tools for this post.
        $auditUrl = (string) add_query_arg([
            'page' => 'wpsn-audit',
            'object_type' => 'post',
            'object_id' => $postId,
        ], admin_url('tools.php'));

        $bulkUrl = (string) add_query_arg([
            'page' => 'wpsn-seo-bulk',
            'view' => 'draft',
            'post_id' => $postId,
        ], admin_url('tools.php'));

        $linksIncomingUrl = (string) add_query_arg([
            'page' => 'wpsn-search-console',
            'view' => 'links',
            'status' => 'draft',
            'target_id' => $postId,
        ], admin_url('tools.php'));

        $linksOutgoingUrl = (string) add_query_arg([
            'page' => 'wpsn-search-console',
            'view' => 'links',
            'status' => 'draft',
            'source_id' => $postId,
        ], admin_url('tools.php'));

        wp_add_inline_script('wpsn-universal-metabox', 'window.WPSN_UMETA=' . wp_json_encode([
            'postId' => $postId,
            'builder' => (string) ($ctx['builder'] ?? ''),
            'restUrl' => rest_url('wpsn/v1/automation/meta/post/' . $postId),
            'nonce' => wp_create_nonce('wp_rest'),
            'label' => wp_strip_all_tags($brand),
            'links' => [
                'audit' => $auditUrl,
                'aiDrafts' => $bulkUrl,
                'internalLinksIncoming' => $linksIncomingUrl,
                'internalLinksOutgoing' => $linksOutgoingUrl,
                'editPost' => (string) add_query_arg([
                    'post' => $postId,
                    'action' => 'edit',
                ], admin_url('post.php')),
            ],
        ]) . ';', 'before');
    }

    public function maybeRenderUniversalMetabox(): void
    {
        if (is_admin()) {
            return;
        }

        $ctx = $this->universalMetaboxContext();
        if (!$ctx) {
            return;
        }

        $postId = (int) ($ctx['post_id'] ?? 0);
        if ($postId <= 0 || !current_user_can('edit_post', $postId)) {
            return;
        }

        echo '<div id="wpsn-universal-metabox-root" data-post-id="' . esc_attr((string) $postId) . '" data-builder="' . esc_attr((string) ($ctx['builder'] ?? '')) . '"></div>';
    }

    /**
     * Detect whether we are inside a supported front-end builder context.
     *
     * @return array{builder:string,post_id:int}|null
     */
    private function universalMetaboxContext(): ?array
    {
        $postId = (int) get_queried_object_id();
        if ($postId <= 0) {
            return null;
        }

        // Divi Visual Builder (front-end) typically uses ?et_fb=1.
        if (BuilderDetector::hasDivi() && (bool) $this->settings->get('integrations.divi.universal_metabox', true)) {
            if (isset($_GET['et_fb']) || isset($_GET['et_pb_preview'])) {
                return ['builder' => 'divi', 'post_id' => $postId];
            }
        }

        // Beaver Builder (front-end) typically uses ?fl_builder (or fl_builder=1).
        if (BuilderDetector::hasBeaver() && (bool) $this->settings->get('integrations.beaver.universal_metabox', true)) {
            if (isset($_GET['fl_builder']) || isset($_GET['fl_builder_ui'])) {
                return ['builder' => 'beaver', 'post_id' => $postId];
            }
        }

        return null;
    }

    /**
     * @param string $html
     */
    public function elementorBuilderHtml(string $html, int $postId, string $context): string
    {
        if ($postId <= 0) {
            return $html;
        }

        if (!class_exists('\\Elementor\\Plugin')) {
            return $html;
        }

        // Only handle posts that are built with Elementor.
        if (!$this->isBuiltWithElementor($postId)) {
            return $html;
        }

        try {
            $plugin = \Elementor\Plugin::instance();
            if (!isset($plugin->frontend) || !is_object($plugin->frontend) || !method_exists($plugin->frontend, 'get_builder_content_for_display')) {
                return $html;
            }

            // get_builder_content_for_display($post_id, $with_css)
            $withCss = false;
            $rendered = $plugin->frontend->get_builder_content_for_display($postId, $withCss);
            if (is_string($rendered) && trim($rendered) !== '') {
                return $rendered;
            }
        } catch (\Throwable $e) {
            // ignore
        }

        return $html;
    }

    /**
     * Divi builder HTML extraction.
     */
    public function diviBuilderHtml(string $html, int $postId, string $context): string
    {
        if ($postId <= 0) {
            return $html;
        }

        if (!$this->isBuiltWithDivi($postId)) {
            return $html;
        }

        $content = (string) get_post_field('post_content', $postId);
        if ($content === '') {
            return $html;
        }

        // Divi stores layouts as shortcodes in post_content.
        if (function_exists('do_blocks')) {
            $content = (string) do_blocks($content);
        }
        $content = (string) do_shortcode($content);
        $content = (string) wpautop($content);

        return trim($content) !== '' ? $content : $html;
    }

    /**
     * Beaver Builder HTML extraction.
     */
    public function beaverBuilderHtml(string $html, int $postId, string $context): string
    {
        if ($postId <= 0) {
            return $html;
        }

        if (!$this->isBuiltWithBeaver($postId)) {
            return $html;
        }

        if (!class_exists('\\FLBuilder')) {
            return $html;
        }

        try {
            // Many Beaver versions provide render_content_by_id() which may echo or return HTML.
            if (method_exists('\\FLBuilder', 'render_content_by_id')) {
                ob_start();
                $returned = \FLBuilder::render_content_by_id($postId);
                $echoed = (string) ob_get_clean();

                if (is_string($returned) && trim($returned) !== '') {
                    return $returned;
                }
                if (trim($echoed) !== '') {
                    return $echoed;
                }
            }
        } catch (\Throwable $e) {
            // ignore
        }

        // Fallback: let WP render post_content normally.
        $content = (string) get_post_field('post_content', $postId);
        if ($content === '') {
            return $html;
        }

        if (function_exists('do_blocks')) {
            $content = (string) do_blocks($content);
        }
        $content = (string) do_shortcode($content);
        $content = (string) wpautop($content);

        return trim($content) !== '' ? $content : $html;
    }

    private function isBuiltWithElementor(int $postId): bool
    {
        if ($postId <= 0 || !BuilderDetector::hasElementor()) {
            return false;
        }

        try {
            $plugin = \Elementor\Plugin::instance();
            if (isset($plugin->db) && is_object($plugin->db) && method_exists($plugin->db, 'is_built_with_elementor')) {
                return (bool) $plugin->db->is_built_with_elementor($postId);
            }
        } catch (\Throwable $e) {
            // ignore
        }

        // Fallback heuristics.
        $data = get_post_meta($postId, '_elementor_data', true);
        return is_string($data) && trim($data) !== '';
    }

    /**
     * Detect if Divi Builder is available on this site.
     *
     * Best-effort only: we prefer false negatives over false positives.
     */
    private function isDiviEnabled(): bool
    {
        return BuilderDetector::hasDivi();
    }

    /**
     * Detect if Beaver Builder is available on this site.
     */
    private function isBeaverEnabled(): bool
    {
        return BuilderDetector::hasBeaver();
    }

    private function isBuiltWithDivi(int $postId): bool
    {
        if ($postId <= 0) {
            return false;
        }

        // Best-effort detection.
        if (function_exists('et_pb_is_pagebuilder_used')) {
            try {
                return (bool) et_pb_is_pagebuilder_used($postId);
            } catch (\Throwable $e) {
                // ignore
            }
        }

        $flag = (string) get_post_meta($postId, '_et_pb_use_builder', true);
        if (in_array($flag, ['on', '1', 'yes', 'true'], true)) {
            return true;
        }

        // Heuristic: Divi shortcodes in post_content.
        $content = (string) get_post_field('post_content', $postId);
        return (strpos($content, '[et_pb_') !== false);
    }

    private function isBuiltWithBeaver(int $postId): bool
    {
        if ($postId <= 0) {
            return false;
        }

        $enabled = (string) get_post_meta($postId, '_fl_builder_enabled', true);
        if (in_array($enabled, ['1', 'yes', 'on', 'true'], true)) {
            return true;
        }

        // Some versions store layout data.
        $data = get_post_meta($postId, '_fl_builder_data', true);
        if (!empty($data)) {
            return true;
        }

        return false;
    }

    /**
     * Add a minimal "WP SEO Next" section into Elementor Document settings.
     *
     * @param mixed $document
     */
    public function registerElementorControls($document): void
    {
        if (!is_object($document) || !method_exists($document, 'get_main_id')) {
            return;
        }

        if (!class_exists('\\Elementor\\Controls_Manager')) {
            return;
        }

        $postId = (int) $document->get_main_id();
        if ($postId <= 0) {
            return;
        }

        // Capability check.
        if (!current_user_can('edit_post', $postId)) {
            return;
        }

        $seoTitle = (string) get_post_meta($postId, MetaKeys::TITLE, true);
        $seoDesc  = (string) get_post_meta($postId, MetaKeys::DESCRIPTION, true);

        // Render current computed preview.
        $previewTitle = '';
        $previewDesc = '';
        try {
            /** @var SeoMetaRepository $repo */
            $repo = $this->container->get('meta_repo');
            $ctx = new SeoDocumentContext(
                SeoDocumentContext::TYPE_SINGULAR,
                $postId,
                get_post_type($postId) ?: null,
                get_permalink($postId) ?: home_url('/'),
                1
            );
            $meta = $repo->forContext($ctx);
            $previewTitle = $meta->title;
            $previewDesc = $meta->description;
        } catch (\Throwable $e) {
            // ignore
        }

        // Controls.
        $document->start_controls_section(
            'wpsn_seo_section',
            [
                'label' => __('SEO (WP SEO Next)', 'wp-seo-next'),
                'tab' => \Elementor\Controls_Manager::TAB_SETTINGS,
            ]
        );

        $document->add_control(
            'wpsn_seo_title',
            [
                'label' => __('SEO Title', 'wp-seo-next'),
                'type' => \Elementor\Controls_Manager::TEXT,
                'default' => $seoTitle,
                'label_block' => true,
            ]
        );

        $document->add_control(
            'wpsn_seo_description',
            [
                'label' => __('Meta Description', 'wp-seo-next'),
                'type' => \Elementor\Controls_Manager::TEXTAREA,
                'default' => $seoDesc,
                'rows' => 4,
            ]
        );

        $html = '';
        if ($previewTitle !== '' || $previewDesc !== '') {
            $html .= '<div style="padding:8px 0;">';
            $html .= '<strong>' . esc_html__('Preview', 'wp-seo-next') . '</strong><br/>';
            if ($previewTitle !== '') {
                $html .= '<div style="margin:6px 0 2px 0; font-size:13px;">' . esc_html($previewTitle) . '</div>';
            }
            if ($previewDesc !== '') {
                $html .= '<div style="opacity:0.85; font-size:12px;">' . esc_html($previewDesc) . '</div>';
            }
            $html .= '</div>';
        }

        $document->add_control(
            'wpsn_seo_preview',
            [
                'type' => \Elementor\Controls_Manager::RAW_HTML,
                'raw' => $html,
                'content_classes' => 'wpsn-elementor-seo-preview',
            ]
        );

        $document->end_controls_section();
    }

    /**
     * Persist Elementor controls to post meta.
     *
     * @param mixed $document
     * @param array<string,mixed> $data
     */
    public function saveElementorControls($document, array $data): void
    {
        if (!is_object($document) || !method_exists($document, 'get_main_id') || !method_exists($document, 'get_settings')) {
            return;
        }

        $postId = (int) $document->get_main_id();
        if ($postId <= 0) {
            return;
        }

        if (!current_user_can('edit_post', $postId)) {
            return;
        }

        $settings = $document->get_settings();
        if (!is_array($settings)) {
            return;
        }

        if (array_key_exists('wpsn_seo_title', $settings)) {
            $t = is_scalar($settings['wpsn_seo_title']) ? sanitize_text_field((string) $settings['wpsn_seo_title']) : '';
            if ($t !== '') {
                update_post_meta($postId, MetaKeys::TITLE, $t);
            } else {
                delete_post_meta($postId, MetaKeys::TITLE);
            }
        }

        if (array_key_exists('wpsn_seo_description', $settings)) {
            $d = is_scalar($settings['wpsn_seo_description']) ? sanitize_text_field((string) $settings['wpsn_seo_description']) : '';
            if ($d !== '') {
                update_post_meta($postId, MetaKeys::DESCRIPTION, $d);
            } else {
                delete_post_meta($postId, MetaKeys::DESCRIPTION);
            }
        }
    }
}
