<?php
/**
 * Forge Suite Dashboard — bundle upsell CTA banner.
 *
 * F13 phase 5 extraction (2026-04-21). Split from class-forge-dashboard.php
 * so the facade no longer carries the upsell-banner shape + its two
 * "is the user already paying?" probes.
 *
 * Shared across all 4 Forge plugins — first-loaded plugin wins via
 * bulletproof `if (!class_exists)` wrap (PHP-8.3-safe).
 *
 * What it owns:
 * - render_banner($statuses): emit the "Get All 4 Plugins — Save up
 * to 40%" banner, or nothing if the user already has a bundle /
 * fully paid across plugins.
 * - user_has_bundle: true when any active Forge plugin reports a
 * bundle-backed license (plugin_id == 27475 OR parent_license_id set).
 * - all_plugins_pro: true when every Forge plugin reports paying OR
 * trial. Handles the "4 separate licenses, not a bundle" shape so the
 * banner doesn't upsell someone who already paid the full premium
 * price.
 *
 * Called from:
 * - Forge_Suite_Dashboard::render header (credits chip) + main body.
 *
 * @package ForgeSuite
 */

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

if (!class_exists('Forge_Suite_Dashboard_Bundle_CTA')) {

class Forge_Suite_Dashboard_Bundle_CTA {

    /**
 * Freemius product ID for the Forge Suite bundle (SEO + Lang + Form + Field).
 * Kept as a constant so swapping environments (if we ever run a staging
 * Freemius) is a one-line change.
 */
    const BUNDLE_ID = 27475;

    /** Method names on Freemius instances we probe for bundle detection. */
    const FS_FNS = ['sf_freemius', 'langforge_freemius', 'ff_freemius', 'fdf_freemius'];

    /**
 * Emit the "Get All 4 Plugins — Save up to 40%" upsell banner, unless
 * the user already owns the bundle OR all 4 plugins are separately
 * PRO. $statuses is accepted for API parity with the old callsite but
 * isn't used here — the check goes through Freemius directly.
 */
    public static function render_banner($statuses = null) {
        // Hide the upsell banner if the user already owns the bundle, OR
        // if all 4 plugins are already PRO (via separate licenses or HMAC
        // test-site activation). Detecting only the bundle license missed
        // test sites and users who bought plugins individually — in both
        // cases showing "Save 40% by buying the bundle!" is wrong: they've
        // already paid the full premium price.
        if (self::user_has_bundle() || self::all_plugins_pro()) {
            return;
        }

        $bundle_checkout = 'https://checkout.freemius.com/mode/dialog/plugin/' . self::BUNDLE_ID . '/plan/45432/';
        ?>
        <div class="forge-suite-bundle-banner">
            <div class="forge-suite-bundle-inner">
                <div class="forge-suite-bundle-text">
                    <div class="forge-suite-bundle-title">
                        <span class="dashicons dashicons-yes-alt"></span>
                        <?php esc_html_e('Get All 4 Plugins — Save up to 40%', 'rankforge'); ?>
                    </div>
                    <div class="forge-suite-bundle-desc">
                        <?php esc_html_e('Rank Forge + Lang Forge + Form Forge + Field Forge. One license, all features, priority support.', 'rankforge'); ?>
                    </div>
                    <div class="forge-suite-bundle-price">
                        <?php esc_html_e('Starting at $99/year for all 4 plugins', 'rankforge'); ?>
                    </div>
                </div>
                <div class="forge-suite-bundle-action">
                    <a href="<?php echo esc_url($bundle_checkout); ?>" class="forge-suite-bundle-btn" target="_blank">
                        <?php esc_html_e('Get Bundle', 'rankforge'); ?>
                        <span class="dashicons dashicons-external"></span>
                    </a>
                </div>
            </div>
        </div>
        <?php
    }

    /**
 * True if any active Forge plugin reports a bundle-backed license.
 * Mirrors the server-side CreditService.isBundleLicense check.
 *
 * A license is bundle-backed when its plugin_id == BUNDLE_ID OR when
 * it has a parent_license_id pointing at the bundle license.
 */
    public static function user_has_bundle() {
        if (self::has_local_bundle_stub()) {
            return true;
        }

        foreach (self::FS_FNS as $fn) {
            if (!function_exists($fn)) continue;
            $fs = $fn();
            if (!$fs || !method_exists($fs, 'is_registered') || !$fs->is_registered()) continue;
            $license = $fs->_get_license();
            if (!is_object($license)) continue;
            if ((int) ($license->plugin_id ?? 0) === self::BUNDLE_ID) return true;
            if (!empty($license->parent_license_id)) return true;
        }
        return false;
    }

    /**
 * Local PRO test sites and clone QA use HMAC/e2e license_data instead of
 * a Freemius bundle object. Treat an all-plugin shared stub key as bundle
 * state so the suite dashboard and credits header reflect the same paid
 * surface the per-plugin pages already expose.
 */
    private static function has_local_bundle_stub() {
        if (!defined('FORGE_SKIP_LICENSE_REVALIDATION') || !FORGE_SKIP_LICENSE_REVALIDATION) {
            return false;
        }
        if (!in_array(get_option('forge_e2e_plan', ''), ['pro', 'trial'], true)) {
            return false;
        }

        $keys = [];
        foreach (['rankforge', 'langforge', 'formforge', 'fieldforge'] as $slug) {
            $data = get_option($slug . '_license_data', []);
            if (!is_array($data) || empty($data['key'])) {
                return false;
            }
            $keys[] = (string) $data['key'];
        }

        return count(array_unique($keys)) === 1;
    }

    /**
 * True when every Forge plugin reports a paid (or trial) license.
 * The upsell banner is noise for these users whether or not the
 * licenses happen to be a bundle underneath.
 */
    public static function all_plugins_pro() {
        $pro = 0;
        foreach (self::FS_FNS as $fn) {
            if (!function_exists($fn)) continue;
            $fs = $fn();
            if (!$fs) continue;
            if (method_exists($fs, 'is_paying') && $fs->is_paying()) { $pro++; continue; }
            if (method_exists($fs, 'is_trial')  && $fs->is_trial())  { $pro++; continue; }
        }
        return $pro >= 4;
    }
}

} // end: if (!class_exists('Forge_Suite_Dashboard_Bundle_CTA'))
