<?php
class SS_Licensing {
    const TRANSIENT_KEY = 'ss_license_status';
    const TTL = 2 * MINUTE_IN_SECONDS;
       
    const REFRESH_EARLY_SEC = 2 * HOUR_IN_SECONDS; // background refresh when <2h left

    public static function init(){
        add_action('update_option_'.SS_Settings::OPT_API_KEY,  [__CLASS__,'invalidate'],10,2);
        add_action('update_option_'.SS_Settings::OPT_DOMAIN,   [__CLASS__,'invalidate'],10,2);
        add_action('update_option_'.SS_Settings::OPT_API_BASE, [__CLASS__,'invalidate'],10,2);

        // background refresh (non-blocking) when cache is getting stale
        add_action('admin_init', [__CLASS__, 'maybe_refresh_async']);
        add_action('ss_license_check', [__CLASS__, 'check_license']); // cron target
        add_action('current_screen', function ($screen) {

        if (!isset($screen->id)) return;

        // Only on SearchShifter admin pages
        if (strpos($screen->id, 'searchshifter') === false) return;

        // If license is cached as free/inactive, refresh once
        $cached = get_transient(SS_Licensing::TRANSIENT_KEY);

        if (is_array($cached) && empty($cached['active'])) {
            SS_Licensing::force_refresh();
        }
    });

add_action('update_option_'.SS_Settings::OPT_API_KEY, function(){
    SS_Licensing::force_refresh();
});

    }

    public static function invalidate(){ delete_transient(self::TRANSIENT_KEY); }

    public static function api_base(){
        $from_opt = rtrim((string) get_option(SS_Settings::OPT_API_BASE, ''), '/');
        if ($from_opt) return $from_opt;
        return rtrim(defined('SEARCHSHIFTER_API_BASE') ? SEARCHSHIFTER_API_BASE : '', '/');
    }

    /** Force a fresh request now (used by the "Re-check license" button) */
    public static function force_refresh(){
        delete_transient(self::TRANSIENT_KEY);
        return self::check_license();
    }

    /** Schedule a background refresh when cache is close to expiring */
    public static function maybe_refresh_async(){
        $timeout = (int) get_option('_transient_timeout_'.self::TRANSIENT_KEY, 0);
        if (!$timeout) return; // no cache yet
        if ( time() + self::REFRESH_EARLY_SEC >= $timeout ){
            if (!wp_next_scheduled('ss_license_check')) {
                wp_schedule_single_event(time()+2, 'ss_license_check');
            }
        }
    }

    /** Main check — returns a rich array, but still includes ['active','message'] for back-compat */
    public static function check_license(){
        $cached = get_transient(self::TRANSIENT_KEY);
        if (is_array($cached)) return $cached;

        $apiKey = trim((string) get_option(SS_Settings::OPT_API_KEY, ''));
        $domain = trim((string) get_option(SS_Settings::OPT_DOMAIN, parse_url(get_site_url(), PHP_URL_HOST)));
        $base   = self::api_base();

        $baseRes = [
            'active'      => false,
            'read_only'   => true,
            'status'      => 'inactive',
            'plan'        => null,
            'expires_at'  => null,
            'expires'     => null, // <— alias for UI
            'reason'      => null,
            'message'     => '',
            'checked_at'  => time(),
        ];

        // if (!$apiKey || !$domain || !$base){
        //     $res = $baseRes;
        //     $res['message'] = 'Missing API base, key or domain';
        //     set_transient(self::TRANSIENT_KEY, $res, self::TTL);
        //     return $res;
        // }

        // ✅ FREE MODE — no API key is EXPECTED
// ✅ NO API KEY YET — allow paid users to enter it
if (!$apiKey) {

    // If we already KNOW this site is paid, do NOT fallback to free
    $knownPlan = get_option('ss_plan_type', 'free');

if ($knownPlan !== 'free') {
    $res['active']    = false;   // 🔴 IMPORTANT
    $res['read_only'] = true;    // 🔴 IMPORTANT
    $res['status']    = 'pending_key';
    $res['plan']      = $knownPlan;
    $res['message']   = 'Enter your API key to activate your plan.';
}


    // Otherwise truly Free
    $res = $baseRes;
    $res['active']     = true;
    $res['read_only']  = false;
    $res['status']     = 'free';
    $res['plan']       = 'free';
    $res['message']    = 'Free plan active';

    set_transient(self::TRANSIENT_KEY, $res, self::TTL);
    update_option('ss_plan_type', 'free');

    return $res;
}


        $resp = \SS\Core\Http::postJson('license.validate', '/license/validate', [
            'domain'         => $domain,
            'plugin_version' => defined('SEARCHSHIFTER_VERSION') ? SEARCHSHIFTER_VERSION : 'unknown',
        ], ['timeout'=>12]);

if (empty($resp['ok'])) {

    // 🔥 HARD RESET LOCAL STATE
    delete_transient(self::TRANSIENT_KEY);
    update_option('ss_plan_type', 'free');

    $res = $baseRes;
    $res['status']  = 'inactive';
    $res['plan']    = 'free';
    $res['message'] = !empty($resp['error'])
        ? $resp['error']
        : 'License not found';

    set_transient(self::TRANSIENT_KEY, $res, self::TTL);
    return $res;
}

        
        $domainFromWp = parse_url(get_site_url(), PHP_URL_HOST);

        // Extract the returned domain if your Laravel API sends it
        if (!empty($resp['json']['data']['registered_domain'])) {
            $registeredDomain = strtolower($resp['json']['data']['registered_domain']);
            $currentDomain = strtolower($domainFromWp);

            if ($registeredDomain !== $currentDomain) {
                $res = $baseRes;
                $res['message'] = 'License mismatch — this key is registered for ' . $registeredDomain;
                set_transient(self::TRANSIENT_KEY, $res, self::TTL);
                return $res;
            }
        }
        $json = is_array($resp['json'] ?? null) ? $resp['json'] : [];
        $data = is_array($json['data'] ?? null) ? $json['data'] : [];

        $status    = strtolower((string)($data['status'] ?? 'inactive'));
        $readOnly  = (bool) ($data['readOnly'] ?? true);
        // $plan      = isset($data['plan']) ? (string)$data['plan'] : null;
        // $expiresAt = isset($data['expiresAt']) ? (string)$data['expiresAt'] : null;
        // $reason    = isset($data['reason']) ? (string)$data['reason'] : null;

        $plan      = isset($data['plan']) ? (string)$data['plan'] : 'free';
        $expiresAt = isset($data['expiresAt']) ? (string)$data['expiresAt'] : null;
        $reason    = isset($data['reason']) ? (string)$data['reason'] : null;
        $features  = isset($data['features']) && is_array($data['features'])
                        ? $data['features']
                        : [];

        $active = in_array($status, ['active','trialing'], true) && !$readOnly;

        $res = $baseRes;
        $res['active']     = $active;
        $res['read_only']  = $readOnly;
        $res['status']     = $status;
        $res['plan']       = $plan;
        $res['expires_at'] = $expiresAt ?: null;
        $res['expires']    = $expiresAt ?: null; // <— alias used by UI
        $res['reason']     = $reason ?: null;

        if ($active) {
            $res['message'] = 'Valid';
        } elseif ($status === 'active' && $readOnly) {
            $res['message'] = 'Read-only mode';
        } elseif ($status === 'expired') {
            $res['message'] = 'License expired';
        } elseif ($reason) {
            $res['message'] = $reason;
        } else {
            $res['message'] = 'Inactive';
        }
       $res['features'] = $features;

// ✅ Cache for 12 hours
set_transient(self::TRANSIENT_KEY, $res, self::TTL);

// ✅ Normalize and sync plan type to wp_options
$normalizedPlan = strtolower(trim($res['plan'] ?? 'free'));
if (!in_array($normalizedPlan, ['free','pro','authority','elite'], true)) {
    $normalizedPlan = 'free';
}

// If license is inactive or expired → force fallback to free
if ($res['status'] === 'expired') {
    $normalizedPlan = 'free';
}

// Save to wp_options for frontend + dashboard access
update_option('ss_plan_type', $normalizedPlan);

// Optional debug log
// error_log('[SS Licensing] Synced plan: ' . $normalizedPlan . ' | Status: ' . $res['status']);

return $res;

    }


    
    public static function is_active(){
        $st = self::check_license();
        return !empty($st['active']);
    }
    public static function get_cached_status(){ return self::check_license(); }

    /** Normalize for UI badges */
    // includes/licensing.php
    // public static function ui_state() {
    //     $st   = self::get_cached_status(); // includes plan/expires/expires_at/message
    //     $msg  = isset($st['message']) ? (string)$st['message'] : '';

    //     $badge = ['class' => 'err', 'text' => 'Inactive'];
    //     if (!empty($st['active'])) {
    //         $badge = ['class' => 'ok', 'text' => 'Active'];
    //     } else {
    //         if (stripos($msg, 'expired') !== false) {
    //             $badge = ['class' => 'warn', 'text' => 'Expired'];
    //         } elseif (stripos($msg, 'read-only') !== false || stripos($msg, 'readonly') !== false) {
    //             $badge = ['class' => 'warn', 'text' => 'Read-only'];
    //         } elseif (stripos($msg, 'domain') !== false) {
    //             $badge = ['class' => 'err', 'text' => 'Domain mismatch'];
    //         }
    //     }

    //     return [
    //         'badge'   => $badge,
    //         'message' => $msg,
    //         'plan'    => $st['plan']    ?? null,
    //         'expires' => $st['expires'] ?? ($st['expires_at'] ?? null),
    //     ];
    // }

    
    public static function ui_state() {
$st  = self::get_cached_status();
$msg = (string) ($st['message'] ?? '');
        if (($st['status'] ?? '') === 'pending_key') {
    return [
        'badge' => [
            'class' => 'warn',
            'text'  => ucfirst($st['plan']) . ' (Pending API Key)',
        ],
        'message' => 'Enter your API key to activate SearchShifter.',
        'plan'    => $st['plan'],
        'expires' => null,
        'mode'    => 'paid',
    ];
}


  
    // ✅ FREE MODE (no API key, intentional state)
    if (($st['status'] ?? '') === 'free') {
        return [
            'badge' => [
                'class' => 'ok',
                'text'  => 'Free (Active)',
            ],
            'message' => 'Running in Free mode with limited features.',
            'plan'    => 'free',
            'expires' => null,
            'mode'    => 'free', // 🔑 REQUIRED FOR UI
        ];
    }

    // Default
    $badge = ['class' => 'err', 'text' => 'Inactive'];

    if (!empty($st['active'])) {
        $badge = ['class' => 'ok', 'text' => 'Active'];
    } else {
        if (stripos($msg, 'expired') !== false) {
            $badge = ['class' => 'warn', 'text' => 'Expired'];
        } elseif (stripos($msg, 'read-only') !== false || stripos($msg, 'readonly') !== false) {
            $badge = ['class' => 'warn', 'text' => 'Read-only'];
        } elseif (stripos($msg, 'domain') !== false) {
            $badge = ['class' => 'err', 'text' => 'Domain mismatch'];
        }
    }

    return [
        'badge'   => $badge,
        'message' => $msg,
        'plan'    => $st['plan']    ?? null,
        'expires' => $st['expires'] ?? ($st['expires_at'] ?? null),
        'mode'    => 'paid',
    ];
}

    public static function plan() {
    $st = self::get_cached_status();
    return $st['plan'] ?? 'free';
}

public static function has_feature($feature) {
    $st = self::get_cached_status();

    // Normalize features array
    $features = [];
    if (!empty($st['features'])) {
        if (is_array($st['features'])) {
            $features = $st['features'];
        } elseif (is_string($st['features'])) {
            $features = explode(',', $st['features']);
        }
    }

    // Return true if license is active AND feature exists
    if (!empty($st['active']) && in_array($feature, $features, true)) {
        return true;
    }

    return false;
}

public static function sync_plan_option() {
    // Get current plan from license data
    $plan = self::plan();

    // Normalize
    $allowed = ['free', 'pro', 'authority', 'elite'];
    if (!in_array($plan, $allowed, true)) {
        $plan = 'free';
    }

    // Update wp_options
    update_option('ss_plan_type', $plan);

    // Optional debug log
    // error_log("[SS Licensing] Plan synced: $plan");

    return $plan;
}


}
