<?php
/**
 * Private update metadata from icomm license server (slug: icomm-metrix).
 */
if (!defined('ABSPATH')) {
	exit;
}

final class IComm_SM_Updater {

	private const SLUG = 'icomm-metrix';
	private const CACHE_KEY = 'icomm_sm_update_meta_v1';

	public static function init(): void {
		add_filter('site_transient_update_plugins', [__CLASS__, 'inject_update'], 10, 1);
		add_filter('plugins_api', [__CLASS__, 'plugins_api'], 10, 3);
		add_filter('plugin_action_links_' . plugin_basename(ICOMM_SM_PLUGIN_FILE), [__CLASS__, 'action_links'], 10, 1);
		add_filter('plugin_row_meta', [__CLASS__, 'row_meta_links'], 20, 2);
		add_filter('plugin_auto_update_setting_html', [__CLASS__, 'filter_auto_update_setting_html'], 10, 3);
		add_action('admin_notices', [__CLASS__, 'maybe_show_update_check_notice']);
		add_filter('http_request_args', [__CLASS__, 'http_request_args_for_license_host'], 10, 2);
		add_filter('allowed_redirect_hosts', [__CLASS__, 'allowed_redirect_hosts'], 10, 2);
		add_filter('upgrader_pre_download', [__CLASS__, 'upgrader_pre_download_with_retry'], 10, 4);
	}

	public static function bust_cache(): void {
		delete_site_transient(self::CACHE_KEY);
	}

	public static function endpoint_url(): string {
		$base = (string) apply_filters('icomm_sm_updates_endpoint_base', 'https://license.icomm.systems/wp-json/icomm-updates/v1');
		return rtrim($base, '/') . '/' . self::SLUG;
	}

	/**
	 * @param string[] $hosts
	 * @param string|false $location
	 * @return string[]
	 */
	public static function allowed_redirect_hosts($hosts, $location) {
		unset($location);
		$hosts = is_array($hosts) ? $hosts : [];
		$hosts[] = 'license.icomm.systems';
		$hosts[] = 'icomm.systems';
		$hosts[] = 'icomm.market';
		return $hosts;
	}

	private static function normalize_package_url(string $url): string {
		$url = trim($url);
		if ($url === '') {
			return '';
		}
		$parts = wp_parse_url($url);
		if (!is_array($parts) || empty($parts['path'])) {
			return $url;
		}
		$path = $parts['path'];
		$file = basename($path);
		if ($file === '' || $file === '.' || $file === '..') {
			return $url;
		}
		if (!preg_match('/^icomm-metrix\.zip$/i', $file)) {
			return $url;
		}
		$dir = dirname($path);
		$new_file = 'icomm-metrix.zip';
		if ($dir === '/' || $dir === '\\' || $dir === '.') {
			$new_path = '/' . $new_file;
		} else {
			$new_path = str_replace('\\', '/', $dir) . '/' . $new_file;
		}
		$scheme = isset($parts['scheme']) ? $parts['scheme'] . '://' : '';
		$auth = '';
		if (!empty($parts['user'])) {
			$auth = $parts['user'];
			if (isset($parts['pass'])) {
				$auth .= ':' . $parts['pass'];
			}
			$auth .= '@';
		}
		$host = $parts['host'] ?? '';
		$port = isset($parts['port']) ? ':' . (int) $parts['port'] : '';
		$query = isset($parts['query']) ? '?' . $parts['query'] : '';
		$fragment = isset($parts['fragment']) ? '#' . $parts['fragment'] : '';
		return $scheme . $auth . $host . $port . $new_path . $query . $fragment;
	}

	/**
	 * @param array<string, mixed> $args
	 * @return array<string, mixed>
	 */
	public static function http_request_args_for_license_host(array $args, string $url): array {
		if (!self::is_icomm_sm_http_url($url)) {
			return $args;
		}
		// API / telemetry / update-meta must stay fail-fast (2s). Only ZIP packages need a long wait.
		$path = (string) (wp_parse_url($url, PHP_URL_PATH) ?? '');
		$is_zip = (bool) preg_match('#\.zip($|\?)#i', $url);
		$is_package_path = (bool) preg_match('#/(download|package|packages|files)/#i', $path);
		if (!$is_zip && !$is_package_path) {
			return $args;
		}
		$prev = isset($args['timeout']) ? (int) $args['timeout'] : 5;
		$args['timeout'] = max($prev, 120);
		$args['redirection'] = isset($args['redirection']) ? max((int) $args['redirection'], 5) : 5;
		if (!isset($args['headers']) || !is_array($args['headers'])) {
			$args['headers'] = [];
		}
		$args['headers']['Accept'] = '*/*';
		$args['headers']['Accept-Encoding'] = 'identity';
		return $args;
	}

	private static function is_icomm_sm_http_url(string $url): bool {
		if (stripos($url, 'icomm.systems') !== false || stripos($url, 'icomm.market') !== false) {
			return true;
		}
		return stripos($url, 'icomm-metrix') !== false;
	}

	/**
	 * @param bool|\WP_Error $reply
	 * @param array<string, mixed> $hook_extra
	 * @return bool|\WP_Error|string
	 */
	public static function upgrader_pre_download_with_retry($reply, string $package, $upgrader, $hook_extra) {
		unset($upgrader);
		if (false !== $reply) {
			return $reply;
		}
		$hook_extra = is_array($hook_extra) ? $hook_extra : [];
		if (!preg_match('!^https?://!i', $package)) {
			return false;
		}
		$our = plugin_basename(ICOMM_SM_PLUGIN_FILE);
		$plugin = isset($hook_extra['plugin']) ? (string) $hook_extra['plugin'] : '';
		if ($plugin !== '' && $plugin !== $our) {
			return false;
		}
		if ($plugin === '' && !self::is_icomm_sm_http_url($package)) {
			return false;
		}

		if (!function_exists('download_url')) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
		}

		$attempts = 3;
		$last = null;
		for ($i = 1; $i <= $attempts; $i++) {
			if ($i > 1) {
				sleep(3);
			}
			$tmp = download_url($package, 300, false);
			if (!is_wp_error($tmp) && is_string($tmp) && is_readable($tmp)) {
				return $tmp;
			}
			$last = $tmp;
			if (!is_wp_error($tmp)) {
				break;
			}
			$msg = $tmp->get_error_message();
			if (!self::download_error_is_retryable($msg) || $i === $attempts) {
				return $tmp;
			}
		}
		return is_wp_error($last) ? $last : false;
	}

	private static function download_error_is_retryable(string $msg): bool {
		$m = strtolower($msg);
		foreach (['503', '502', '504', '500', 'service unavailable', 'bad gateway', 'gateway timeout', 'timed out', 'timeout', 'connection reset', 'could not resolve', 'empty reply'] as $needle) {
			if (strpos($m, $needle) !== false) {
				return true;
			}
		}
		return false;
	}

	private static function can_see_license_ui(): bool {
		return current_user_can('manage_options');
	}

	/**
	 * @param string[] $links
	 * @return string[]
	 */
	public static function action_links(array $links): array {
		if (!self::can_see_license_ui()) {
			return $links;
		}
		$settings_url = admin_url('admin.php?page=icomm-metrix-settings');
		$license_url = admin_url('admin.php?page=icomm-metrix-settings#icomm-sm-license');
		$s = IComm_SM_License::get_settings();
		$key = isset($s['license_key']) ? trim((string) $s['license_key']) : '';
		$token = isset($s['license_token']) ? trim((string) $s['license_token']) : '';
		$days_left = IComm_SM_License::trial_days_left();
		$is_trial = ($key === '' || $token === '') && $days_left > 0;
		$is_licensed = $key !== '' && $token !== '';
		$is_active = IComm_SM_License::is_active($s);

		if ($is_trial) {
			$license_label = sprintf(__('ניסיון: נותרו %d ימים', 'icomm-metrix'), $days_left);
			$license_style = 'color:#2271b1;font-weight:600;';
		} elseif ($is_licensed && $is_active) {
			$license_label = __('רישיון פעיל', 'icomm-metrix');
			$license_style = 'color:#00a32a;font-weight:600;';
		} elseif ($is_active) {
			$license_label = __('פעיל', 'icomm-metrix');
			$license_style = 'color:#00a32a;font-weight:600;';
		} else {
			$license_label = __('הפעלת רישיון', 'icomm-metrix');
			$license_style = 'color:#d63638;font-weight:500;';
		}

		$new = [
			'<a href="' . esc_url(admin_url('admin.php?page=icomm-metrix')) . '">' . esc_html__('דשבורד', 'icomm-metrix') . '</a>',
			'<a href="' . esc_url($settings_url) . '">' . esc_html__('הגדרות', 'icomm-metrix') . '</a>',
			'<a href="' . esc_url($license_url) . '" style="' . esc_attr($license_style) . '">' . esc_html($license_label) . '</a>',
		];
		return array_merge($new, $links);
	}

	/**
	 * @param string[] $links
	 * @return string[]
	 */
	public static function row_meta_links(array $links, string $file): array {
		$plugin_file = plugin_basename(ICOMM_SM_PLUGIN_FILE);
		if ($file !== $plugin_file) {
			return $links;
		}

		// Remove WP core "View details" (empty modal) + any prior "הצגת פרטים" so we add exactly one.
		$links = array_values(array_filter($links, static function ($link) {
			$link = (string) $link;
			if ($link === '') {
				return false;
			}
			if (strpos($link, 'plugin-install.php') !== false) {
				return false;
			}
			if (strpos($link, 'tab=plugin-information') !== false) {
				return false;
			}
			if (strpos($link, 'open-plugin-details-modal') !== false) {
				return false;
			}
			if (preg_match('/הצגת פרטים|View details/i', wp_strip_all_tags($link))) {
				return false;
			}
			return true;
		}));

		if (self::can_see_license_ui()) {
			$check_url = wp_nonce_url(
				add_query_arg(['icomm_sm_action' => 'check_updates'], admin_url('plugins.php')),
				'icomm_sm_check_updates'
			);
			$links[] = '<a href="' . esc_url($check_url) . '">' . esc_html__('בדוק עדכונים', 'icomm-metrix') . '</a>';
		}

		if (current_user_can('activate_plugins') && defined('ICOMM_SM_PLUGIN_ABOUT_SLUG')) {
			$details_url = add_query_arg(
				[
					'page' => (string) ICOMM_SM_PLUGIN_ABOUT_SLUG,
					'TB_iframe' => 'true',
					'width' => '880',
					'height' => '800',
				],
				admin_url('admin.php')
			);
			$links[] = '<a href="' . esc_url($details_url) . '" class="thickbox">' . esc_html__('הצגת פרטים', 'icomm-metrix') . '</a>';
		}

		return $links;
	}

	/**
	 * @param string $html
	 * @param array<string, mixed> $plugin_data
	 */
	public static function filter_auto_update_setting_html(string $html, string $plugin_file, array $plugin_data): string {
		$our = plugin_basename(ICOMM_SM_PLUGIN_FILE);
		if ($plugin_file !== $our) {
			return $html;
		}
		if (trim(wp_strip_all_tags($html)) !== '') {
			return $html;
		}
		if (!current_user_can('update_plugins')) {
			return $html;
		}

		$auto_updates = (array) get_site_option('auto_update_plugins', []);
		$enabled = in_array($plugin_file, array_map('strval', $auto_updates), true);
		$action = $enabled ? 'disable' : 'enable';
		$text = $enabled ? __('Disable auto-updates') : __('Enable auto-updates');

		$page = isset($_REQUEST['paged']) ? max(1, absint($_REQUEST['paged'])) : 1;
		$status = isset($_REQUEST['plugin_status']) ? sanitize_key((string) wp_unslash($_REQUEST['plugin_status'])) : 'all';
		$url = add_query_arg(
			[
				'action' => $action . '-auto-update',
				'plugin' => $plugin_file,
				'paged' => $page,
				'plugin_status' => $status,
			],
			'plugins.php'
		);
		$url = wp_nonce_url($url, 'updates');

		$out = '<a class="toggle-auto-update" href="' . esc_url($url) . '" data-wp-action="' . esc_attr($action) . '">'
			. '<span class="dashicons dashicons-update hidden" aria-hidden="true"></span>'
			. '<span class="label">' . esc_html($text) . '</span>'
			. '</a>';

		if (!empty($plugin_data['update']) && function_exists('wp_get_auto_update_message')) {
			$out .= '<div class="auto-update-time hidden">' . wp_kses_post(wp_get_auto_update_message()) . '</div>';
		}

		return $out;
	}

	public static function maybe_show_update_check_notice(): void {
		if (!is_admin() || !self::can_see_license_ui()) {
			return;
		}
		if (!isset($_GET['icomm_sm_updates_checked']) || (string) $_GET['icomm_sm_updates_checked'] !== '1') {
			return;
		}
		$screen = function_exists('get_current_screen') ? get_current_screen() : null;
		if (!is_object($screen) || ($screen->id ?? '') !== 'plugins') {
			return;
		}
		$has = isset($_GET['icomm_sm_has_update']) && (string) $_GET['icomm_sm_has_update'] === '1';
		if ($has) {
			echo '<div class="notice notice-warning is-dismissible" dir="rtl" lang="he" style="direction:rtl;text-align:right;"><p>'
				. esc_html__('בוצעה בדיקת עדכונים, יש עדכון זמין ל־icomm metrix.', 'icomm-metrix')
				. '</p></div>';
		} else {
			echo '<div class="notice notice-success is-dismissible" dir="rtl" lang="he" style="direction:rtl;text-align:right;"><p>'
				. esc_html__('בוצעה בדיקת עדכונים, אין עדכון זמין כרגע.', 'icomm-metrix')
				. '</p></div>';
		}
	}

	/**
	 * @param object|mixed $transient
	 * @return object|mixed
	 */
	public static function inject_update($transient) {
		if (!is_object($transient)) {
			return $transient;
		}
		if (!isset($transient->response) || !is_array($transient->response)) {
			$transient->response = [];
		}

		$plugin_file = plugin_basename(ICOMM_SM_PLUGIN_FILE);
		$current = defined('ICOMM_SM_VERSION') ? (string) ICOMM_SM_VERSION : '';
		$meta = self::fetch_meta();
		if (!$meta || empty($meta['version'])) {
			return $transient;
		}
		$remote_ver = (string) $meta['version'];
		if ($current === '' || version_compare($remote_ver, $current, '<=')) {
			unset($transient->response[$plugin_file]);
			if (!isset($transient->no_update) || !is_array($transient->no_update)) {
				$transient->no_update = [];
			}
			$transient->no_update[$plugin_file] = (object) [
				'slug' => self::SLUG,
				'plugin' => $plugin_file,
				'new_version' => $current !== '' ? $current : $remote_ver,
				'url' => 'https://icomm.market',
				'package' => '',
			];
			return $transient;
		}

		$package = isset($meta['download_url']) ? (string) $meta['download_url'] : '';
		if ($package === '' && !empty($meta['package'])) {
			$package = (string) $meta['package'];
		}
		$package = self::normalize_package_url($package);

		$transient->response[$plugin_file] = (object) [
			'slug' => self::SLUG,
			'plugin' => $plugin_file,
			'new_version' => $remote_ver,
			'url' => isset($meta['homepage']) ? (string) $meta['homepage'] : 'https://icomm.market',
			'package' => $package,
			'tested' => isset($meta['tested']) ? (string) $meta['tested'] : '',
			'requires' => isset($meta['requires']) ? (string) $meta['requires'] : '',
			'requires_php' => isset($meta['requires_php']) ? (string) $meta['requires_php'] : '',
		];
		return $transient;
	}

	/**
	 * @param mixed $result
	 * @return mixed
	 */
	public static function plugins_api($result, string $action, $args) {
		if ($action !== 'plugin_information' || !is_object($args) || empty($args->slug) || (string) $args->slug !== self::SLUG) {
			return $result;
		}
		$meta = self::fetch_meta();
		if (!$meta) {
			return $result;
		}

		$sections = isset($meta['sections']) && is_array($meta['sections']) ? $meta['sections'] : [];
		$dl = isset($meta['download_url']) ? self::normalize_package_url((string) $meta['download_url']) : '';
		if ($dl === '' && !empty($meta['package'])) {
			$dl = self::normalize_package_url((string) $meta['package']);
		}

		return (object) [
			'name' => 'icomm metrix',
			'slug' => self::SLUG,
			'version' => isset($meta['version']) ? (string) $meta['version'] : '',
			'author' => 'icomm systems',
			'homepage' => isset($meta['homepage']) ? (string) $meta['homepage'] : 'https://icomm.market',
			'requires' => isset($meta['requires']) ? (string) $meta['requires'] : '',
			'tested' => isset($meta['tested']) ? (string) $meta['tested'] : '',
			'requires_php' => isset($meta['requires_php']) ? (string) $meta['requires_php'] : '',
			'sections' => $sections,
			'download_link' => $dl,
			'last_updated' => isset($meta['last_updated']) ? (string) $meta['last_updated'] : '',
		];
	}

	/**
	 * @return array<string, mixed>|null
	 */
	private static function fetch_meta(): ?array {
		$cached = get_site_transient(self::CACHE_KEY);
		if (is_array($cached) && !empty($cached['version'])) {
			return $cached;
		}

		if (function_exists('icomm_lic_client_bg_http_allowed') && !icomm_lic_client_bg_http_allowed()) {
			return null;
		}

		$res = wp_remote_get(self::endpoint_url(), [
			'timeout' => 2,
			'redirection' => 0,
		]);
		if (is_wp_error($res)) {
			return null;
		}
		if ((int) wp_remote_retrieve_response_code($res) !== 200) {
			return null;
		}
		$data = json_decode((string) wp_remote_retrieve_body($res), true);
		if (!is_array($data) || empty($data['version'])) {
			return null;
		}
		if (!empty($data['download_url']) && is_string($data['download_url'])) {
			$data['download_url'] = self::normalize_package_url($data['download_url']);
		}
		if (!empty($data['package']) && is_string($data['package'])) {
			$data['package'] = self::normalize_package_url($data['package']);
		}
		set_site_transient(self::CACHE_KEY, $data, 15 * MINUTE_IN_SECONDS);
		return $data;
	}
}
