<?php
/**
 * PageContext - Central view-model for all admin pages
 *
 * Single source of truth for tier, credits, connection status, and URLs.
 * All admin views should use PageContext::get() instead of reading
 * options/Freemius/PointsEconomy directly.
 *
 * Includes throttled Hub refresh (2 min) so tier changes are picked up
 * quickly after purchase without hammering the API.
 *
 * @package Consolety
 */

namespace Consolety;

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

class PageContext
{
    public bool $isConnected;
    public bool $isPro;
    public string $tierLabel;
    public string $tierSlug;
    public int $credits;
    public int $creditsReserved;
    public int $balanceCap;
    public string $upgradeUrl;
    public string $accountUrl;
    public string $contactUrl;
    public string $oauthUrl;
    public array $metrics;
    public array $siteInfo;

    private static ?self $instance = null;

    /**
     * Get the singleton PageContext for this request.
     * Refreshes tier from Hub if stale (throttled to 2 min).
     */
    public static function get(): self
    {
        if (self::$instance !== null) {
            return self::$instance;
        }

        $ctx = new self();
        $ctx->load();
        self::$instance = $ctx;

        return $ctx;
    }

    /**
     * Force a fresh context (clears singleton cache).
     */
    public static function fresh(): self
    {
        self::$instance = null;
        return self::get();
    }

    private function load(): void
    {
        // Connection status
        $plugin = Plugin::instance();
        $this->isConnected = $plugin->isConnected();

        // Refresh from Hub if stale (2 min throttle)
        if ($this->isConnected) {
            $this->refreshIfNeeded();
        }

        // Tier (uses Freemius + Hub cache fallback)
        $this->isPro = PointsEconomy::isPro();
        $this->tierLabel = PointsEconomy::getTierLabel();
        $this->tierSlug = $this->isPro ? 'pro' : 'free';

        // Credits from cached site info
        $this->siteInfo = get_option('consolety_site_info', []);
        $this->credits = (int) ($this->siteInfo['credits'] ?? 0);
        $this->creditsReserved = (int) ($this->siteInfo['credits_reserved'] ?? 0);
        $this->balanceCap = $this->isPro ? 1000 : 500;

        // Metrics
        $this->metrics = get_option('consolety_metrics', []);

        // OAuth URL
        $api = new Api();
        $this->oauthUrl = $api->getOAuthUrl();

        // Freemius URLs (with safe fallbacks)
        $this->upgradeUrl = 'https://consolety.ai/pricing/';
        $this->accountUrl = 'https://consolety.ai/account/';
        $this->contactUrl = 'mailto:support@consolety.ai';

        if (function_exists('consolety_fs') && consolety_fs()) {
            try {
                // While Freemius is in activation mode it never registers the
                // pricing page, so its upgrade URL 403s. Only trust that URL once
                // the install is registered or anonymous; otherwise keep the
                // consolety.ai fallback so an upgrade CTA always leads somewhere.
                $fs_ready = consolety_fs()->is_registered() || consolety_fs()->is_anonymous();
                $billing = defined('WP_FS__PERIOD_MONTHLY') ? WP_FS__PERIOD_MONTHLY : 'monthly';
                $url = $fs_ready ? consolety_fs()->get_upgrade_url($billing) : '';
                if ($url) {
                    $this->upgradeUrl = $url;
                }
            } catch (\Throwable $e) {
                // Freemius error - use fallback
            }

            try {
                $url = consolety_fs()->get_account_url();
                if ($url) {
                    $this->accountUrl = $url;
                }
            } catch (\Throwable $e) {
                // Freemius error - use fallback
            }

            try {
                $url = consolety_fs()->contact_url();
                if ($url) {
                    $this->contactUrl = $url;
                }
            } catch (\Throwable $e) {
                // Freemius error - use fallback
            }
        }
    }

    /**
     * Refresh tier/credits from Hub API (throttled to once per 2 min).
     */
    private function refreshIfNeeded(): void
    {
        $lastRefresh = get_transient('consolety_status_refresh');
        if ($lastRefresh) {
            return;
        }

        Plugin::instance()->refresh_status();
        set_transient('consolety_status_refresh', time(), 120);
    }

    /**
     * Lazy-loaded, cached preview of the live network for the
     * pre-connection onboarding screen (disconnected state only).
     *
     * Best-effort: returns empty arrays if the Hub is unreachable.
     * Cached in a transient so we never hit the Hub on every page load.
     *
     * @return array{publishers: array, stats: array}
     */
    public function getNetworkPreview(): array
    {
        $cached = get_transient('consolety_network_preview');
        if (is_array($cached)) {
            return $cached;
        }

        $preview = ['publishers' => [], 'stats' => []];

        try {
            $resp = (new Api())->getNetworkShowcase();
            if (!empty($resp['success']) && !empty($resp['data'])) {
                $preview['publishers'] = $resp['data']['publishers'] ?? [];
                $preview['stats'] = $resp['data']['stats'] ?? [];
            }
        } catch (\Throwable $e) {
            // Preview is non-critical; ignore failures.
        }

        // Cache a populated preview for an hour; cache an empty one briefly
        // so a transient Hub hiccup does not suppress the preview for long.
        $ttl = !empty($preview['publishers']) ? HOUR_IN_SECONDS : 5 * MINUTE_IN_SECONDS;
        set_transient('consolety_network_preview', $preview, $ttl);

        return $preview;
    }
}
