<?php
if (!defined('ABSPATH')) exit;

class SPG_License {

  const OPT_KEY       = 'spg_license_key';
  const OPT_TOKEN     = 'spg_license_token';
  const OPT_EXPIRES   = 'spg_license_expires';
  const OPT_STATUS    = 'spg_license_status';
  const OPT_LAST_ERR  = 'spg_license_last_error';

  // === CHANGE THESE ===
  const API_BASE = '|:O4mQO*`Z/{}N>BhxWQ)A)Vjt`8N$G_oG*>A/+yNrYJa+~*'; // or https://api.yourdomain.com
  const API_APP_ID = 'spg_crypto_manual';
  const API_SECRET = 'CDQBT6WXC8FJUIEFKTLL'; // shared secret used to HMAC-sign requests

  public static function init(): void {
    add_action('wp_ajax_spg_activate_license', [__CLASS__, 'ajax_activate']);
    add_action('wp_ajax_spg_deactivate_license', [__CLASS__, 'ajax_deactivate']);

    add_action('spg_license_daily_check', [__CLASS__, 'cron_validate']);
    if (!wp_next_scheduled('spg_license_daily_check')) {
      wp_schedule_event(time() + 300, 'daily', 'spg_license_daily_check');
    }
  }

  public static function get_key(): string {
    return (string) get_option(self::OPT_KEY, '');
  }

  public static function set_key(string $key): void {
    update_option(self::OPT_KEY, trim($key));
  }

  public static function is_valid(): bool {
    $status  = (string) get_option(self::OPT_STATUS, 'inactive');
    $expires = (int) get_option(self::OPT_EXPIRES, 0);

    if ($status !== 'active') return false;
    if ($expires <= time()) return false;

    return true;
  }

  public static function needs_refresh(int $buffer_seconds = 24 * 3600): bool {
    $expires = (int) get_option(self::OPT_EXPIRES, 0);
    if ($expires <= 0) return true;
    return ($expires - time()) <= $buffer_seconds;
  }

  private static function site_url(): string {
    return home_url();
  }

  private static function site_hash(): string {
    // stable per-site identifier
    return hash_hmac('sha256', self::site_url(), wp_salt('auth'));
  }

  private static function sign_payload(array $payload): string {
    $json = wp_json_encode($payload);
    return hash_hmac('sha256', $json, self::API_SECRET);
  }

  private static function request(string $path, array $payload): array {
    $payload['app_id']    = self::API_APP_ID;
    $payload['site_url']  = self::site_url();
    $payload['site_hash'] = self::site_hash();
    $payload['wp']        = get_bloginfo('version');
    $payload['plugin']    = defined('SPG_VERSION') ? SPG_VERSION : '0';

    $sig = self::sign_payload($payload);

    $res = wp_remote_post(self::API_BASE . $path, [
      'timeout' => 15,
      'headers' => [
        'Content-Type' => 'application/json',
        'X-SPG-Signature' => $sig,
      ],
      'body' => wp_json_encode($payload),
    ]);

    if (is_wp_error($res)) {
      return ['ok' => false, 'error' => $res->get_error_message()];
    }

    $code = (int) wp_remote_retrieve_response_code($res);
    $body = wp_remote_retrieve_body($res);
    $data = json_decode($body, true);

    if ($code < 200 || $code >= 300 || !is_array($data)) {
      return ['ok' => false, 'error' => 'Bad response', 'code' => $code, 'raw' => $body];
    }

    return ['ok' => true, 'data' => $data];
  }

  public static function activate(string $license_key): array {
    $license_key = trim($license_key);
    if ($license_key === '') return ['ok' => false, 'error' => 'Empty license key'];

    $resp = self::request('/activate', [
      'license_key' => $license_key,
    ]);

    if (!$resp['ok']) {
      update_option(self::OPT_STATUS, 'inactive');
      update_option(self::OPT_LAST_ERR, $resp['error'] ?? 'Activate failed');
      return ['ok' => false, 'error' => $resp['error'] ?? 'Activate failed'];
    }

    $d = $resp['data'];

    // Expecting: status, expires_at (unix), token, token_sig
    if (empty($d['token']) || empty($d['expires_at']) || empty($d['status'])) {
      update_option(self::OPT_STATUS, 'inactive');
      update_option(self::OPT_LAST_ERR, 'Invalid activate payload');
      return ['ok' => false, 'error' => 'Invalid activate payload'];
    }

    // Verify server signature over token+expires+status
    if (!self::verify_server_sig($d)) {
      update_option(self::OPT_STATUS, 'inactive');
      update_option(self::OPT_LAST_ERR, 'Signature check failed');
      return ['ok' => false, 'error' => 'Signature check failed'];
    }

    self::set_key($license_key);
    update_option(self::OPT_TOKEN, (string) $d['token']);
    update_option(self::OPT_EXPIRES, (int) $d['expires_at']);
    update_option(self::OPT_STATUS, (string) $d['status']);
    update_option(self::OPT_LAST_ERR, '');

    return ['ok' => true, 'status' => $d['status'], 'expires_at' => (int)$d['expires_at']];
  }

  public static function deactivate(): array {
    $key = self::get_key();
    if ($key === '') return ['ok' => true];

    $resp = self::request('/deactivate', [
      'license_key' => $key,
      'token'       => (string) get_option(self::OPT_TOKEN, ''),
    ]);

    // Regardless of remote result, disable locally
    update_option(self::OPT_STATUS, 'inactive');
    update_option(self::OPT_TOKEN, '');
    update_option(self::OPT_EXPIRES, 0);

    return ['ok' => (bool)($resp['ok'] ?? false)];
  }

  public static function validate_remote(): bool {
    $key = self::get_key();
    $token = (string) get_option(self::OPT_TOKEN, '');

    if ($key === '' || $token === '') return false;

    $resp = self::request('/validate', [
      'license_key' => $key,
      'token'       => $token,
    ]);

    if (!$resp['ok']) {
      update_option(self::OPT_LAST_ERR, $resp['error'] ?? 'Validate failed');
      return false;
    }

    $d = $resp['data'];
    if (!self::verify_server_sig($d)) {
      update_option(self::OPT_LAST_ERR, 'Signature check failed');
      return false;
    }

    update_option(self::OPT_STATUS, (string)($d['status'] ?? 'inactive'));
    update_option(self::OPT_EXPIRES, (int)($d['expires_at'] ?? 0));

    // Token rotation supported
    if (!empty($d['token'])) {
      update_option(self::OPT_TOKEN, (string)$d['token']);
    }

    update_option(self::OPT_LAST_ERR, '');
    return self::is_valid();
  }

  public static function cron_validate(): void {
    if (!self::get_key()) return;
    if (!self::needs_refresh()) return;
    self::validate_remote();
  }

  private static function verify_server_sig(array $d): bool {
    // server signs: token|expires_at|status|site_hash|app_id
    $token     = (string)($d['token'] ?? '');
    $expires   = (string)($d['expires_at'] ?? '');
    $status    = (string)($d['status'] ?? '');
    $site_hash = (string)($d['site_hash'] ?? '');
    $app_id    = (string)($d['app_id'] ?? '');

    $sig = (string)($d['token_sig'] ?? '');
    if ($sig === '' || $token === '' || $expires === '' || $status === '') return false;

    $base = $token . '|' . $expires . '|' . $status . '|' . $site_hash . '|' . $app_id;
    $calc = hash_hmac('sha256', $base, self::API_SECRET);

    return hash_equals($calc, $sig);
  }

  // ==== AJAX handlers ====

  public static function ajax_activate(): void {
    if (!current_user_can('manage_woocommerce')) wp_send_json_error(['message' => 'Forbidden'], 403);
    check_ajax_referer('spg_license_nonce');

    $key = isset($_POST['license_key']) ? sanitize_text_field(wp_unslash($_POST['license_key'])) : '';
    $r = self::activate($key);

    if (!$r['ok']) wp_send_json_error(['message' => $r['error'] ?? 'Activate failed']);
    wp_send_json_success(['status' => $r['status'], 'expires_at' => $r['expires_at']]);
  }

  public static function ajax_deactivate(): void {
    if (!current_user_can('manage_woocommerce')) wp_send_json_error(['message' => 'Forbidden'], 403);
    check_ajax_referer('spg_license_nonce');

    self::deactivate();
    wp_send_json_success(['status' => 'inactive']);
  }
}
