<?php
/**
 * Forge Suite — docs link helper (FC-36).
 *
 * Landing URLs live in constants so we can point at different domains
 * without touching plugin PHP. While we're on Hostinger temp domains the
 * defaults use those; when custom domains land, override via wp-config.php:
 *
 * define('FORGE_DOCS_URL_LANGFORGE', 'https://langforgewp.com');
 *
 * Inline tooltip markup is rendered via Forge_Docs_Link::tooltip next
 * to feature labels. Client-side behaviour: hover shows short description,
 * click opens the docs page in a new tab.
 */

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

// Default landing URLs (production domains). A host's definition takes
// precedence — override via wp-config.php / MU plugin if needed. Defined as
// explicit literals (not a loop over a variable) so Plugin Check can verify
// each constant name carries the Forge prefix.
if (!defined('FORGE_DOCS_URL_LANGFORGE'))  define('FORGE_DOCS_URL_LANGFORGE', 'https://langforgewp.com');
if (!defined('FORGE_DOCS_URL_SEOFORGE'))   define('FORGE_DOCS_URL_SEOFORGE', 'https://seoforgewp.com');
if (!defined('FORGE_DOCS_URL_FORMFORGE'))  define('FORGE_DOCS_URL_FORMFORGE', 'https://formforgewp.com');
if (!defined('FORGE_DOCS_URL_FIELDFORGE')) define('FORGE_DOCS_URL_FIELDFORGE', 'https://fieldforgewp.com');
if (!defined('FORGE_DOCS_URL_AVAKODE'))    define('FORGE_DOCS_URL_AVAKODE', 'https://avakode.com');

// Shared class — class_exists guard so the first plugin to load wins.
if (!class_exists('Forge_Docs_Link')) {

class Forge_Docs_Link {

    /** @var bool Emit styles only once per page load. */
    private static $styles_printed = false;

    /**
 * Full URL to a docs page on the product landing.
 *
 * @param string $plugin One of langforge|seoforge|formforge|fieldforge|avakode
 * @param string $page Optional docs section slug. Empty = /docs/ index.
 * By default slugs resolve under /docs/user-guide/.
 * Known developer-only slugs resolve under /docs/developer-guide/.
 * @param array $args Optional ?a=b query args.
 */
    public static function url($plugin, $page = '', $args = []) {
        $map = [
            'langforge'  => defined('FORGE_DOCS_URL_LANGFORGE')  ? FORGE_DOCS_URL_LANGFORGE  : '',
            'seoforge'   => defined('FORGE_DOCS_URL_SEOFORGE')   ? FORGE_DOCS_URL_SEOFORGE   : '',
            'formforge'  => defined('FORGE_DOCS_URL_FORMFORGE')  ? FORGE_DOCS_URL_FORMFORGE  : '',
            'fieldforge' => defined('FORGE_DOCS_URL_FIELDFORGE') ? FORGE_DOCS_URL_FIELDFORGE : '',
            'avakode'    => defined('FORGE_DOCS_URL_AVAKODE')    ? FORGE_DOCS_URL_AVAKODE    : '',
        ];
        $base = rtrim($map[$plugin] ?? '', '/');
        if (!$base) return '';

        $path = self::docs_path($plugin, $page);

        $url = $base . $path;
        if (!empty($args)) {
            $url = add_query_arg($args, $url);
        }
        return $url;
    }

    private static function docs_path($plugin, $page = '') {
        $page = trim((string) $page, '/');
        if ($page === '') {
            return '/docs/';
        }

        if (strpos($page, '/') !== false) {
            return '/docs/' . $page . '/';
        }

        $developer_pages = [
            'langforge' => [
                '19-migration-from-wpml' => true,
                '20-glossary-api' => true,
                '21-translation-hooks' => true,
            ],
            'seoforge' => [
                '46-migration-from-yoast' => true,
                '47-migration-from-rank-math' => true,
                '48-migration-from-aioseo' => true,
            ],
            'formforge' => [
                '26-stripe-setup' => true,
                '30-maps-integration' => true,
                '31-mailchimp-integration' => true,
                '32-google-sheets-integration' => true,
                '33-google-calendar-integration' => true,
                '34-hubspot-integration' => true,
            ],
            'fieldforge' => [
                '33-typescript-generation' => true,
                '34-graphql-integration' => true,
            ],
        ];

        $section = !empty($developer_pages[$plugin][$page]) ? 'developer-guide' : 'user-guide';
        return '/docs/' . $section . '/' . $page . '/';
    }

    /**
 * Inline tooltip pill: question-mark icon with hover description + click
 * through to the docs page on the product landing.
 *
 * @param string $plugin langforge|seoforge|formforge|fieldforge|avakode
 * @param string $page docs slug
 * @param string $title feature title (shown in tooltip heading)
 * @param string $summary one-line description
 */
    public static function tooltip($plugin, $page, $title, $summary = '') {
        $url = self::url($plugin, $page);
        if (!$url) return '';
        $aria = $summary ? $title . ' — ' . $summary : $title;
        return sprintf(
            '<a href="%s" target="_blank" rel="noopener" class="forge-tip" aria-label="%s" data-tip-title="%s" data-tip-summary="%s">'
                . '<span class="forge-tip__icon" aria-hidden="true">?</span>'
                . '<span class="forge-tip__panel" role="tooltip">'
                    . '<strong class="forge-tip__title">%s</strong>'
                    . ($summary ? '<span class="forge-tip__summary">%s</span>' : '%s')
                    . '<span class="forge-tip__cta">%s &rarr;</span>'
                . '</span>'
            . '</a>',
            esc_url($url),
            esc_attr($aria),
            esc_attr($title),
            esc_attr($summary),
            esc_html($title),
            esc_html($summary ?: ''),
            esc_html__('Read the docs', 'formforge')
        );
    }

    /** Echo-variant of tooltip for render methods. */
    public static function render($plugin, $page, $title, $summary = '') {
        echo self::tooltip($plugin, $page, $title, $summary); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted pre-built markup (values escaped inside tooltip)
    }

    /**
 * Hook print_styles to admin_head so the <style>/<script> block always
 * emits at the top of the page outside any caller's HTML context.
 * Without this, tooltip called inline from inside <h1> (admin page
 * headings frequently render a docs-link pill there) leaked the entire
 * <style> block INTO the <h1> — invalid HTML, screen readers tried to
 * announce CSS as the heading text.
 */
    public static function init() {
        add_action('admin_head', [self::class, 'print_styles']);
    }

    public static function print_styles() {
        if (self::$styles_printed) return;
        self::$styles_printed = true;
        ?>
        <style id="forge-tip-css">
            .forge-tip {
                position: relative;
                display: inline-flex;
                align-items: center;
                justify-content: center;
                width: 18px;
                height: 18px;
                margin-left: 6px;
                border-radius: 50%;
                background: #e5e7eb;
                color: #374151 !important;
                text-decoration: none !important;
                box-shadow: none !important;
                vertical-align: middle;
                transition: background .15s ease, color .15s ease;
            }
            .forge-tip:hover,
            .forge-tip:focus {
                background: #1f2937;
                color: #fff !important;
                outline: none;
            }
            .forge-tip__icon {
                font-size: 14px;
                font-weight: 700;
                line-height: 1;
                font-family: inherit;
            }
            /* Panel is position:fixed so it escapes overflow:hidden/auto
 * ancestors (metabox form groups frequently clip). JS below
 * places it with getBoundingClientRect on mouseenter/focus. */
            .forge-tip__panel {
                position: fixed;
                z-index: 100000;
                top: 0;
                left: 0;
                min-width: 220px;
                max-width: 280px;
                padding: 12px 14px;
                background: #0f172a;
                color: #f9fafb !important;
                border-radius: 10px;
                box-shadow: 0 12px 32px rgba(0,0,0,.25);
                font-size: 14px;
                font-weight: 400;
                line-height: 1.55;
                letter-spacing: 0 !important;
                text-transform: none !important;
                opacity: 0;
                visibility: hidden;
                pointer-events: none;
                transition: opacity .12s ease;
                text-align: left;
                display: flex;
                flex-direction: column;
                gap: 6px;
            }
            .forge-tip__panel * { text-transform: none !important; letter-spacing: 0 !important; }
            /* Arrow points DOWN when panel is above the trigger (default).
 * --tip-arrow-x is set by JS to keep the arrow under the trigger
 * even when the panel has been clamped inside the viewport. */
            .forge-tip__panel::after {
                content: '';
                position: absolute;
                bottom: -6px;
                left: var(--tip-arrow-x, 50%);
                transform: translateX(-50%);
                border: 6px solid transparent;
                border-top-color: #0f172a;
                border-bottom: 0;
            }
            /* Arrow points UP when panel is placed below the trigger (fallback). */
            .forge-tip.is-below .forge-tip__panel::after {
                bottom: auto;
                top: -6px;
                border-top: 0;
                border-bottom: 6px solid #0f172a;
            }
            .forge-tip.is-open .forge-tip__panel {
                opacity: 1;
                visibility: visible;
                pointer-events: auto;
            }
            /* Invisible bridge covers the 10px gap between trigger and panel
 * so the mouse can travel from `?` into the panel without firing
 * mouseout through empty space. Width matches panel width. */
            .forge-tip.is-open .forge-tip__panel::before {
                content: '';
                position: absolute;
                left: 0;
                right: 0;
                height: 10px;
                bottom: -10px;
            }
            .forge-tip.is-open.is-below .forge-tip__panel::before {
                bottom: auto;
                top: -10px;
            }
            /* High-specificity selectors so metabox-scoped rules like
 * `.seoforge-metabox .sf-field-header strong { color:#1e293b!important }`
 * don't leak into the panel. */
            .forge-tip .forge-tip__panel .forge-tip__title,
            strong.forge-tip__title {
                font-size: 14px !important;
                font-weight: 700 !important;
                color: #ffffff !important;
                letter-spacing: .01em !important;
            }
            .forge-tip .forge-tip__panel .forge-tip__summary,
            span.forge-tip__summary {
                color: #e5e7eb !important;
                font-size: 12.5px !important;
                line-height: 1.5 !important;
                font-weight: 400 !important;
            }
            .forge-tip .forge-tip__panel .forge-tip__cta,
            span.forge-tip__cta {
                color: #93c5fd !important;
                font-weight: 600 !important;
                margin-top: 4px !important;
                font-size: 14px !important;
                letter-spacing: .02em !important;
            }
        </style>
        <script>
        (function(){
            if (window.__forgeTipsBound) return;
            window.__forgeTipsBound = true;
            var activeTip = null;
            var closeTimer = null;
            var CLOSE_DELAY = 180;

            function position(tip) {
                var panel = tip.querySelector('.forge-tip__panel');
                if (!panel) return;
                var r = tip.getBoundingClientRect();
                var pw = panel.offsetWidth, ph = panel.offsetHeight;
                var vw = window.innerWidth;
                // Center horizontally over the tip icon, clamped to viewport.
                var left = r.left + r.width / 2 - pw / 2;
                if (left < 8) left = 8;
                if (left + pw > vw - 8) left = vw - pw - 8;
                var top = r.top - ph - 10;
                // If no room above, place below and flip arrow direction.
                if (top < 8) {
                    top = r.bottom + 10;
                    tip.classList.add('is-below');
                } else {
                    tip.classList.remove('is-below');
                }
                // Arrow sits at the CENTER of the tip horizontally — if the
                // panel shifted to stay in-viewport, move the arrow too.
                var arrowX = r.left + r.width / 2 - left;
                panel.style.setProperty('--tip-arrow-x', Math.round(arrowX) + 'px');
                panel.style.left = Math.round(left) + 'px';
                panel.style.top  = Math.round(top)  + 'px';
            }

            function cancelClose() {
                if (closeTimer) { clearTimeout(closeTimer); closeTimer = null; }
            }
            function open(tip) {
                cancelClose();
                if (activeTip && activeTip !== tip) activeTip.classList.remove('is-open');
                activeTip = tip;
                tip.classList.add('is-open');
                position(tip);
            }
            function scheduleClose(tip) {
                cancelClose();
                closeTimer = setTimeout(function(){
                    tip.classList.remove('is-open');
                    if (activeTip === tip) activeTip = null;
                    closeTimer = null;
                }, CLOSE_DELAY);
            }

            document.addEventListener('mouseover', function(e){
                var t = e.target.closest && e.target.closest('.forge-tip');
                if (t) open(t);
            });
            document.addEventListener('mouseout', function(e){
                var t = e.target.closest && e.target.closest('.forge-tip');
                if (!t) return;
                // If mouse went to another element inside the same tip
                // (icon -> panel -> link), keep it open.
                if (e.relatedTarget && t.contains(e.relatedTarget)) return;
                // Otherwise close after a short grace — gives time to cross
                // the 10px arrow gap without the panel disappearing.
                scheduleClose(t);
            });
            document.addEventListener('focusin', function(e){
                var t = e.target.closest && e.target.closest('.forge-tip');
                if (t) open(t);
            });
            document.addEventListener('focusout', function(e){
                var t = e.target.closest && e.target.closest('.forge-tip');
                if (t) scheduleClose(t);
            });
            window.addEventListener('scroll', function(){
                if (activeTip) position(activeTip);
            }, true);
            window.addEventListener('resize', function(){
                if (activeTip) position(activeTip);
            });
        })();
        </script>
        <?php
    }
}

Forge_Docs_Link::init();

} // class_exists guard
