<?php

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

final class IComm_SM_License {

	public const CRON_HOOK = 'icomm_sm_license_check';
	public const DEFAULT_ENDPOINT = 'https://license.icomm.systems/wp-json/icomm-lic/v1';
	public const PLUGIN_PRODUCT_SLUG = 'icomm-metrix';
	public const OPTION_KEY = 'icomm_sm_license_settings';
	public const GRACE_DAYS = 14;
	public const TRIAL_DAYS = 7;

	public static function error_message(string $code): string {
		$code = trim((string) $code);
		if ($code === '') {
			return '';
		}
		$map = [
			'domain_mismatch' => __('המפתח משויך לאתר אחר. לא ניתן להפעיל אותו באתר נוסף. אם צריך העברה, שחררו את האתר הישן בשרת הרישיונות או רכשו מפתח חדש.', 'icomm-metrix'),
			'wrong_product' => __('המפתח שייך לתוסף אחר. ודאו שרכשתם icomm metrix.', 'icomm-metrix'),
			'invalid_license' => __('מפתח רישיון לא תקין.', 'icomm-metrix'),
			'invalid_token' => __('טוקן רישיון לא תקין. נסו להפעיל מחדש עם מפתח תקין.', 'icomm-metrix'),
			'license_expired' => __('הרישיון פג תוקף. יש לחדש רישיון.', 'icomm-metrix'),
			'license_inactive' => __('הרישיון לא פעיל. יש להפעיל/לחדש רישיון.', 'icomm-metrix'),
			'activation_failed' => __('הפעלת רישיון נכשלה. בדקו מפתח וחיבור לשרת הרישיונות.', 'icomm-metrix'),
			'check_failed' => __('בדיקת רישיון נכשלה. נסו שוב מאוחר יותר.', 'icomm-metrix'),
			'bad_response' => __('תגובת שרת רישוי לא תקינה. נסו שוב מאוחר יותר.', 'icomm-metrix'),
		];
		if (isset($map[$code])) {
			return (string) $map[$code];
		}
		// Friendly fallback for common HTTP-ish errors.
		if (stripos($code, 'http ') === 0 || strpos($code, '404') !== false) {
			return __('לא ניתן להתחבר לשרת הרישיונות (HTTP). בדקו שהשרת פעיל ושאין חסימה/Firewall.', 'icomm-metrix');
		}
		return $code;
	}

	public static function init(): void {
		add_filter('cron_schedules', [__CLASS__, 'add_daily_schedule'], 10, 1);
		add_action(self::CRON_HOOK, [__CLASS__, 'cron_check']);
		add_action('admin_init', [__CLASS__, 'maybe_ping_license_server']);
	}

	/**
	 * @return array<string, mixed>
	 */
	public static function get_settings(): array {
		$defaults = [
			'license_key' => '',
			'license_token' => '',
			'license_status' => 'inactive',
			'license_expires_at' => 0,
			'license_last_ok' => 0,
			'license_last_error' => '',
		];
		$s = get_option(self::OPTION_KEY, []);
		return is_array($s) ? array_merge($defaults, $s) : $defaults;
	}

	/**
	 * @param array<string, mixed> $settings
	 */
	public static function save_settings(array $settings): void {
		update_option(self::OPTION_KEY, $settings, false);
	}

	public static function endpoint_base(): string {
		return rtrim((string) apply_filters('icomm_sm_license_endpoint', self::DEFAULT_ENDPOINT), '/');
	}

	/**
	 * @param array<string, mixed>|null $settings
	 */
	public static function is_active(?array $settings = null): bool {
		$s = is_array($settings) ? $settings : self::get_settings();
		$key = trim((string) ($s['license_key'] ?? ''));
		$token = trim((string) ($s['license_token'] ?? ''));
		if ($key === '' || $token === '') {
			return false;
		}
		$expires_at = (int) ($s['license_expires_at'] ?? 0);
		$last_ok = (int) ($s['license_last_ok'] ?? 0);
		$now = current_time('timestamp');
		if ($expires_at > 0 && $now <= $expires_at) {
			return true;
		}
		if ($last_ok > 0 && ($now - $last_ok) <= (self::GRACE_DAYS * DAY_IN_SECONDS)) {
			return true;
		}
		return false;
	}

	public static function installed_at(): int {
		$t = get_option('icomm_sm_installed_at', 0);
		return is_numeric($t) ? (int) $t : 0;
	}

	public static function is_trial_active(): bool {
		if (self::is_active()) {
			return false;
		}
		$installed_at = self::installed_at();
		if ($installed_at <= 0) {
			return false;
		}
		$ends = $installed_at + (self::TRIAL_DAYS * DAY_IN_SECONDS);
		return current_time('timestamp') < $ends;
	}

	public static function trial_days_left(): int {
		if (!self::is_trial_active()) {
			return 0;
		}
		$ends = self::installed_at() + (self::TRIAL_DAYS * DAY_IN_SECONDS);
		return max(0, (int) ceil(($ends - current_time('timestamp')) / DAY_IN_SECONDS));
	}

	/**
	 * @param array<string, array{interval:int, display:string}> $schedules
	 * @return array<string, array{interval:int, display:string}>
	 */
	public static function add_daily_schedule(array $schedules): array {
		if (!isset($schedules['icomm_sm_daily'])) {
			$schedules['icomm_sm_daily'] = [
				'interval' => DAY_IN_SECONDS,
				'display' => 'Once daily (icomm metrix)',
			];
		}
		return $schedules;
	}

	public static function schedule_if_needed(): void {
		if (!wp_next_scheduled(self::CRON_HOOK)) {
			wp_schedule_event(time() + 400, 'icomm_sm_daily', self::CRON_HOOK);
		}
	}

	public static function unschedule(): void {
		$ts = wp_next_scheduled(self::CRON_HOOK);
		while ($ts) {
			wp_unschedule_event($ts, self::CRON_HOOK);
			$ts = wp_next_scheduled(self::CRON_HOOK);
		}
	}

	public static function maybe_ping_license_server(): void {
		if (!is_admin() || !current_user_can('manage_options')) {
			return;
		}
		if (function_exists('icomm_lic_client_bg_http_allowed') && !icomm_lic_client_bg_http_allowed()) {
			return;
		}
		$s = self::get_settings();
		$token = trim((string) ($s['license_token'] ?? ''));
		if ($token === '') {
			return;
		}
		$cur_ver = defined('ICOMM_SM_VERSION') ? (string) ICOMM_SM_VERSION : '';
		$last_reported_ver = (string) get_option('icomm_sm_last_reported_plugin_version', '');
		$version_changed = ($cur_ver !== '' && $cur_ver !== $last_reported_ver);
		$last = (int) get_option('icomm_sm_last_license_ping', 0);
		if (!$version_changed && $last > 0 && (current_time('timestamp') - $last) < (6 * HOUR_IN_SECONDS)) {
			return;
		}
		// Defer to WP-Cron / telemetry, do not wp_remote_post during page render.
		if (function_exists('icomm_lic_client_telemetry_schedule')) {
			icomm_lic_client_telemetry_schedule(self::PLUGIN_PRODUCT_SLUG, 'ping', 2);
		} else {
			if (!wp_next_scheduled(self::CRON_HOOK)) {
				wp_schedule_single_event(time() + 30, self::CRON_HOOK);
			}
		}
		update_option('icomm_sm_last_license_ping', current_time('timestamp'), false);
		if ($cur_ver !== '') {
			update_option('icomm_sm_last_reported_plugin_version', $cur_ver, false);
		}
	}

	public static function cron_check(): void {
		$s = self::get_settings();
		$token = trim((string) ($s['license_token'] ?? ''));
		if ($token === '') {
			return;
		}
		self::apply_check_result($s, self::check_with_server($token));
	}

	/**
	 * @return array{ok:bool, token?:string, expires_at?:int, error?:string}
	 */
	public static function activate_with_server(string $license_key): array {
		$license_key = trim($license_key);
		if ($license_key === '') {
			return ['ok' => false, 'error' => 'empty_key'];
		}
		$res = wp_remote_post(self::endpoint_base() . '/activate', [
			'timeout' => 20,
			'headers' => ['Content-Type' => 'application/json; charset=UTF-8'],
			'body' => wp_json_encode([
				'license_key' => $license_key,
				'site_url' => home_url('/'),
				'plugin' => self::PLUGIN_PRODUCT_SLUG,
				'plugin_version' => defined('ICOMM_SM_VERSION') ? ICOMM_SM_VERSION : '',
				'wp_version' => get_bloginfo('version'),
			]),
		]);
		if (is_wp_error($res)) {
			return ['ok' => false, 'error' => $res->get_error_message()];
		}
		$data = json_decode((string) wp_remote_retrieve_body($res), true);
		if ((int) wp_remote_retrieve_response_code($res) !== 200 || !is_array($data) || empty($data['ok'])) {
			$msg = is_array($data) && !empty($data['error']) ? (string) $data['error'] : 'activation_failed';
			return ['ok' => false, 'error' => $msg];
		}
		$token = trim((string) ($data['token'] ?? ''));
		$exp = (int) ($data['expires_at'] ?? 0);
		if ($token === '' || $exp <= 0) {
			return ['ok' => false, 'error' => 'bad_response'];
		}
		return ['ok' => true, 'token' => $token, 'expires_at' => $exp];
	}

	/**
	 * @return array{ok:bool, expires_at?:int, error?:string}
	 */
	public static function check_with_server(string $token): array {
		$token = trim($token);
		if ($token === '') {
			return ['ok' => false, 'error' => 'empty_token'];
		}
		$res = wp_remote_post(self::endpoint_base() . '/check', [
			'timeout' => 2,
			'headers' => ['Content-Type' => 'application/json; charset=UTF-8'],
			'body' => wp_json_encode([
				'token' => $token,
				'site_url' => home_url('/'),
				'plugin' => self::PLUGIN_PRODUCT_SLUG,
				'plugin_version' => defined('ICOMM_SM_VERSION') ? ICOMM_SM_VERSION : '',
				'wp_version' => get_bloginfo('version'),
			]),
		]);
		if (is_wp_error($res)) {
			return ['ok' => false, 'error' => $res->get_error_message()];
		}
		$data = json_decode((string) wp_remote_retrieve_body($res), true);
		if ((int) wp_remote_retrieve_response_code($res) !== 200 || !is_array($data) || empty($data['ok'])) {
			$msg = is_array($data) && !empty($data['error']) ? (string) $data['error'] : 'check_failed';
			return ['ok' => false, 'error' => $msg];
		}
		$exp = (int) ($data['expires_at'] ?? 0);
		if ($exp <= 0) {
			return ['ok' => false, 'error' => 'bad_response'];
		}
		return ['ok' => true, 'expires_at' => $exp];
	}

	/**
	 * @param array<string, mixed> $s
	 * @param array{ok?:bool, expires_at?:int, error?:string} $result
	 */
	private static function apply_check_result(array $s, array $result): void {
		if (!empty($result['ok']) && !empty($result['expires_at'])) {
			$s['license_status'] = 'active';
			$s['license_expires_at'] = (int) $result['expires_at'];
			$s['license_last_ok'] = current_time('timestamp');
			$s['license_last_error'] = '';
			self::save_settings($s);
			return;
		}
		if (empty($result['error'])) {
			return;
		}
		$s['license_last_error'] = (string) $result['error'];
		$fatal = ['license_inactive', 'license_expired', 'invalid_token', 'invalid_license', 'domain_mismatch', 'wrong_product'];
		if (in_array((string) $result['error'], $fatal, true)) {
			$s['license_status'] = 'inactive';
			$s['license_token'] = '';
			$s['license_expires_at'] = 0;
		}
		self::save_settings($s);
	}
}

add_action('plugins_loaded', static function (): void {
	if (!defined('ICOMM_SM_PLUGIN_FILE') || !defined('ICOMM_SM_VERSION')) {
		return;
	}
	$dir = dirname(ICOMM_SM_PLUGIN_FILE) . '/includes/';
	$tel = $dir . 'icomm-lic-client-telemetry.php';
	if (!function_exists('icomm_lic_client_telemetry_bootstrap') && is_readable($tel)) {
		require_once $tel;
	}
	$ui = $dir . 'icomm-lic-client-ui.php';
	if (is_readable($ui)) {
		require_once $ui;
	}
	if (!function_exists('icomm_lic_client_telemetry_bootstrap')) {
		return;
	}
	icomm_lic_client_telemetry_bootstrap([
		'plugin' => IComm_SM_License::PLUGIN_PRODUCT_SLUG,
		'version' => (string) ICOMM_SM_VERSION,
		'file' => (string) ICOMM_SM_PLUGIN_FILE,
		'license_state' => static function (): string {
			$s = IComm_SM_License::get_settings();
			$key = trim((string) ($s['license_key'] ?? ''));
			$token = trim((string) ($s['license_token'] ?? ''));
			if ($key !== '' && $token !== '' && IComm_SM_License::is_active($s)) {
				return 'licensed';
			}
			if (IComm_SM_License::is_trial_active()) {
				return 'trial';
			}
			return $key === '' ? 'no_license' : 'expired';
		},
	]);
}, 25);
