<?php
/**
 * Persistent admin header — renders on every TrustLens admin page.
 *
 * Provides a sticky top bar with: brand mark, primary navigation (all
 * TrustLens submenu pages), live lockdown status pill, notifications
 * dropdown, user menu, and a ⌘K command palette. Renders inside
 * #wpbody-content via the `in_admin_header` hook so it stays below the
 * WordPress admin bar and to the right of the admin menu sidebar.
 *
 * @package TrustLens\Admin
 * @since   1.2.2
 */

defined( 'ABSPATH' ) || exit;

class TrustLens_Admin_Header {

	/**
	 * Register hooks.
	 */
	public function register_hooks(): void {
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
		add_action( 'in_admin_header', array( $this, 'render' ), 100 );
		add_filter( 'admin_body_class', array( $this, 'body_class' ) );
	}

	/**
	 * Page slugs we own (mirror of add_submenu_page registrations in
	 * class-admin-pages.php + class-admin-card-testing-page.php). Any page
	 * not in this list — including Freemius-owned pages like
	 * trustlens-account / -pricing / -contact / -checkout — is skipped so
	 * our nav doesn't collide with Freemius's own chrome.
	 */
	private const OWNED_PAGES = array(
		'trustlens',
		'trustlens-customers',
		'trustlens-notifications',
		'trustlens-automation',
		'trustlens-card-testing',
		'trustlens-chargeback-monitor',
		'trustlens-settings',
	);

	/**
	 * Is the current admin request on a TrustLens plugin page we render chrome for?
	 */
	private function is_plugin_page(): bool {
		if ( ! is_admin() || ! current_user_can( 'manage_woocommerce' ) ) {
			return false;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display-only page check.
		$page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( (string) $_GET['page'] ) ) : '';
		return '' !== $page && in_array( $page, self::OWNED_PAGES, true );
	}

	/**
	 * Add body class so our stylesheet can offset content under the sticky header.
	 */
	public function body_class( string $classes ): string {
		if ( $this->is_plugin_page() ) {
			$classes .= ' wstl-has-header';
		}
		return $classes;
	}

	/**
	 * Enqueue header CSS/JS and localize data.
	 */
	public function enqueue_assets(): void {
		if ( ! $this->is_plugin_page() ) {
			return;
		}

		$css_path = TRUSTLENS_PLUGIN_DIR . 'admin/css/admin-header.css';
		$js_path  = TRUSTLENS_PLUGIN_DIR . 'admin/js/admin-header.js';
		$css_ver  = file_exists( $css_path ) ? (string) filemtime( $css_path ) : TRUSTLENS_VERSION;
		$js_ver   = file_exists( $js_path ) ? (string) filemtime( $js_path ) : TRUSTLENS_VERSION;

		wp_enqueue_style( 'trustlens-admin-header', TRUSTLENS_PLUGIN_URL . 'admin/css/admin-header.css', array(), $css_ver );
		wp_enqueue_script( 'trustlens-admin-header', TRUSTLENS_PLUGIN_URL . 'admin/js/admin-header.js', array(), $js_ver, true );

		wp_localize_script( 'trustlens-admin-header', 'TrustLensHeader', array(
			'commandItems' => $this->get_command_items(),
			'ajaxUrl'      => admin_url( 'admin-ajax.php' ),
			'nonce'        => wp_create_nonce( 'trustlens_admin' ),
			'i18n'         => array(
				'empty'     => __( 'No results', 'trustlens' ),
				'customers' => __( 'Customers', 'trustlens' ),
				'searching' => __( 'Searching customers…', 'trustlens' ),
			),
		) );
	}

	/**
	 * Build nav items — live, respects Pro gating.
	 *
	 * @return array<int,array<string,mixed>>
	 */
	private function get_nav_items(): array {
		$items = array(
			array( 'slug' => 'trustlens',               'label' => __( 'Dashboard', 'trustlens' ),            'icon' => 'i-home' ),
			array( 'slug' => 'trustlens-customers',     'label' => __( 'Customers', 'trustlens' ),            'icon' => 'i-users' ),
			array( 'slug' => 'trustlens-notifications', 'label' => __( 'Notifications', 'trustlens' ),        'icon' => 'i-bell' ),
		);

		// Automation page is always registered (admin-pages.php registers it
		// unconditionally; the free build renders a Pro upsell). Show the tab in
		// every build — badged Pro when Pro can't be used — to match the
		// WordPress submenu.
		$items[] = array(
			'slug'  => 'trustlens-automation',
			'label' => __( 'Automation', 'trustlens' ),
			'icon'  => 'i-zap',
			'pro'   => ! wstl_can_use_pro(),
		);

		$items[] = array( 'slug' => 'trustlens-card-testing', 'label' => __( 'Card-Testing Defense', 'trustlens' ), 'icon' => 'i-shield' );

		// Chargeback Monitor submenu is only registered when its class is present.
		if ( wstl_has_chargebacks() ) {
			$items[] = array(
				'slug'  => 'trustlens-chargeback-monitor',
				'label' => __( 'Chargeback Monitor', 'trustlens' ),
				'icon'  => 'i-chart',
				'pro'   => ! wstl_can_use_pro(),
			);
		}

		$items[] = array( 'slug' => 'trustlens-settings', 'label' => __( 'Settings', 'trustlens' ), 'icon' => 'i-settings' );
		return $items;
	}

	/**
	 * Settings sub-tabs (mirror of admin/views/settings.php).
	 *
	 * @return array<string,array<string,mixed>>
	 */
	private function get_settings_subtabs(): array {
		return array(
			'general'          => array( 'label' => __( 'General', 'trustlens' ) ),
			'payment-controls' => array( 'label' => __( 'Payment Controls', 'trustlens' ), 'pro' => ! ( wstl_has_payment_method_controls() && wstl_can_use_pro() ) ),
			'modules'          => array( 'label' => __( 'Modules', 'trustlens' ) ),
			'webhooks'         => array( 'label' => __( 'Webhooks', 'trustlens' ),         'pro' => ! ( wstl_has_webhooks() && wstl_can_use_pro() ) ),
			'reports'          => array( 'label' => __( 'Reports', 'trustlens' ),          'pro' => ! ( wstl_has_scheduled_reports() && wstl_can_use_pro() ) ),
			'store-network'    => array( 'label' => __( 'Store Network', 'trustlens' ),    'pro' => ! ( function_exists( 'wstl_can_use_network' ) && wstl_can_use_network() ) ),
			'api'              => array( 'label' => __( 'API', 'trustlens' ) ),
			'data'             => array( 'label' => __( 'Data', 'trustlens' ) ),
		);
	}

	/**
	 * Compute live lockdown + chargeback status for the header chip.
	 *
	 * @param \TrustLens_Lockdown_State|null $lockdown Shared instance (optional) to avoid
	 *                                                 re-instantiating + re-reading transients.
	 * @return array{level:string,label:string,detail:string,fps:array<int,array<string,string>>,expires:?int}
	 */
	private function get_status( $lockdown = null ): array {
		$out = array( 'level' => 'good', 'label' => __( 'All clear', 'trustlens' ), 'detail' => '', 'fps' => array(), 'expires' => null );

		// Card-testing lockdown takes precedence.
		if ( null === $lockdown && class_exists( 'TrustLens_Lockdown_State' ) ) {
			$lockdown = new TrustLens_Lockdown_State();
		}
		if ( $lockdown ) {
			if ( $lockdown->is_panic_active() ) {
				$out['level']   = 'danger';
				$out['label']   = __( 'Panic Freeze', 'trustlens' );
				$out['detail']  = __( 'All new card attempts are being denied.', 'trustlens' );
				$out['expires'] = $lockdown->panic_expires_at();
				return $out;
			}
			$targeted = $lockdown->currently_targeted();
			if ( ! empty( $targeted ) ) {
				$out['level']  = 'warn';
				$out['label']  = sprintf(
					/* translators: %d: fingerprint count */
					_n( 'Targeted · %d FP', 'Targeted · %d FPs', count( $targeted ), 'trustlens' ),
					count( $targeted )
				);
				$out['detail'] = __( 'Card-testing attack in progress. Clean sessions unaffected.', 'trustlens' );
				foreach ( $targeted as $fp => $expires_at ) {
					$out['fps'][] = array(
						'hash' => (string) $fp,
						'ttl'  => date_i18n( 'H:i', (int) $expires_at ),
					);
				}
				return $out;
			}
		}

		// Chargeback threshold breach (non-panic fallback signal).
		if ( wstl_has_chargebacks() && class_exists( 'TrustLens_Chargeback_Monitor' ) ) {
			$monitor = new TrustLens_Chargeback_Monitor();
			$ratios  = $monitor->get_ratios();
			$warn    = (int) get_option( 'trustlens_chargeback_alert_threshold_pct', 70 );
			$status  = TrustLens_Chargeback_Monitor::get_threshold_status( $ratios['calendar_month'], $warn );
			foreach ( $status as $row ) {
				if ( 'danger' === ( $row['status'] ?? '' ) ) {
					$out['level']  = 'danger';
					$out['label']  = __( 'Chargeback over line', 'trustlens' );
					$out['detail'] = sprintf(
						/* translators: %s: program label */
						__( 'Over %s threshold. Respond to open disputes.', 'trustlens' ),
						(string) $row['label']
					);
					return $out;
				}
			}
		}

		return $out;
	}

	/**
	 * Notifications — derived from live state. Small, honest, no backend table.
	 *
	 * @param \TrustLens_Lockdown_State|null $lockdown Shared instance (optional).
	 * @return array<int,array<string,mixed>>
	 */
	private function get_notifications( $lockdown = null ): array {
		$items = array();

		if ( null === $lockdown && class_exists( 'TrustLens_Lockdown_State' ) ) {
			$lockdown = new TrustLens_Lockdown_State();
		}
		if ( $lockdown ) {
			if ( $lockdown->is_panic_active() ) {
				$items[] = array(
					'level'  => 'danger',
					'icon'   => 'i-shield',
					'title'  => __( 'Panic freeze active', 'trustlens' ),
					'detail' => __( 'All new card attempts are being denied site-wide.', 'trustlens' ),
					'href'   => admin_url( 'admin.php?page=trustlens-card-testing' ),
				);
			} else {
				$targeted = $lockdown->currently_targeted();
				if ( ! empty( $targeted ) ) {
					$items[] = array(
						'level'  => 'warn',
						'icon'   => 'i-shield',
						'title'  => __( 'Card-testing attack detected', 'trustlens' ),
						'detail' => sprintf(
							/* translators: %d: count */
							_n( '%d fingerprint held at the gate', '%d fingerprints held at the gate', count( $targeted ), 'trustlens' ),
							count( $targeted )
						),
						'href'   => admin_url( 'admin.php?page=trustlens-card-testing' ),
					);
				}
			}
		}

		if ( wstl_has_chargebacks() && class_exists( 'TrustLens_Chargeback_Monitor' ) ) {
			$monitor = new TrustLens_Chargeback_Monitor();
			$ratios  = $monitor->get_ratios();
			$warn    = (int) get_option( 'trustlens_chargeback_alert_threshold_pct', 70 );
			$status  = TrustLens_Chargeback_Monitor::get_threshold_status( $ratios['calendar_month'], $warn );
			foreach ( $status as $row ) {
				if ( 'danger' === ( $row['status'] ?? '' ) ) {
					$items[] = array(
						'level'  => 'danger',
						'icon'   => 'i-chart',
						'title'  => __( 'Chargeback ratio over line', 'trustlens' ),
						'detail' => (string) ( $row['label'] ?? '' ),
						'href'   => admin_url( 'admin.php?page=trustlens-chargeback-monitor' ),
					);
					break;
				}
			}
		}

		// High-risk customers. Count is cached for 60s so every plugin admin
		// page load doesn't re-query trustlens_customers.
		if ( class_exists( 'TrustLens_Customer_Repository' ) ) {
			$count = get_transient( 'trustlens_hdr_highrisk_count' );
			if ( false === $count ) {
				global $wpdb;
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Result is cached in a 60s transient (above); table name from $wpdb->prefix.
				$count = (int) $wpdb->get_var(
					"SELECT COUNT(*) FROM {$wpdb->prefix}trustlens_customers WHERE segment IN ('risk','critical')"
				);
				set_transient( 'trustlens_hdr_highrisk_count', $count, MINUTE_IN_SECONDS );
			}
			$count = (int) $count;
			if ( $count > 0 ) {
				$items[] = array(
					'level'  => 'info',
					'icon'   => 'i-users',
					'title'  => sprintf(
						/* translators: %d: count */
						_n( '%d high-risk customer needs review', '%d high-risk customers need review', $count, 'trustlens' ),
						$count
					),
					'detail' => __( 'Segmented as risk or critical', 'trustlens' ),
					'href'   => admin_url( 'admin.php?page=trustlens-customers&segment=critical' ),
				);
			}
		}

		return $items;
	}

	/**
	 * Command palette items — organized by capability ("feature-first"), not
	 * by page. Each item has optional `keywords` — comma-separated synonyms
	 * used by the JS filter for fuzzy matching without cluttering the label.
	 *
	 * @return array<int,array<string,string>>
	 */
	private function get_command_items(): array {
		$licensed = wstl_can_use_pro();
		$needs_upgrade = ! $licensed; // true → render a "PRO" pill next to label
		$ct       = admin_url( 'admin.php?page=trustlens-card-testing' );
		$cust     = admin_url( 'admin.php?page=trustlens-customers' );
		$settings = admin_url( 'admin.php?page=trustlens-settings' );
		$notif    = admin_url( 'admin.php?page=trustlens-notifications' );
		$cb_url   = admin_url( 'admin.php?page=trustlens-chargeback-monitor' );
		$auto_url = admin_url( 'admin.php?page=trustlens-automation' );

		$items = array();

		// ---- Card-testing defense (Free base + Pro extras) ----------------
		$grp = __( 'Card-testing', 'trustlens' );
		$items[] = array( 'group' => $grp, 'icon' => 'i-shield',   'label' => __( 'Engage panic freeze', 'trustlens' ),        'href' => $ct . '#panic',    'keywords' => 'panic freeze block stop attack emergency' );
		$items[] = array( 'group' => $grp, 'icon' => 'i-settings', 'label' => __( 'Adjust detection thresholds', 'trustlens' ),'href' => $ct . '#settings', 'keywords' => 'threshold velocity declines submissions sensitivity' );
		// Pro-tier card-testing extras — gated on CODE presence (the alert
		// dispatcher / history query classes). If absent, the anchors don't
		// resolve to anything useful; if present but unlicensed, the target
		// sections render an upsell, so we show the item with a PRO badge.
		if ( class_exists( 'TrustLens_Card_Testing_History_Query' ) ) {
			$items[] = array( 'group' => $grp, 'icon' => 'i-key',   'label' => __( 'Manage allowlists (fingerprints & IPs)', 'trustlens' ), 'href' => $ct . '#allowlists',   'keywords' => 'allowlist whitelist exception bypass cidr ip fingerprint', 'pro' => $needs_upgrade );
			$items[] = array( 'group' => $grp, 'icon' => 'i-chart', 'label' => __( 'View 24h attack intelligence', 'trustlens' ),          'href' => $ct . '#intelligence', 'keywords' => 'history timeline decline codes top attackers report', 'pro' => $needs_upgrade );
			if ( $licensed ) {
				// CSV export only exposed to licensed users — the nonce-protected
				// admin-post endpoint would 403 for them anyway.
				$items[] = array( 'group' => $grp, 'icon' => 'i-csv', 'label' => __( 'Export 24h attack CSV', 'trustlens' ), 'href' => wp_nonce_url( admin_url( 'admin-post.php?action=trustlens_ct_history_csv&hours=24' ), 'trustlens_card_testing_csv' ), 'keywords' => 'export download csv report attack declines' );
			}
		}

		// ---- Customers (Free) ---------------------------------------------
		$grp = __( 'Customers', 'trustlens' );
		$items[] = array( 'group' => $grp, 'icon' => 'i-users', 'label' => __( 'Browse all customers', 'trustlens' ),           'href' => $cust,                       'keywords' => 'list search profile trust score' );
		$items[] = array( 'group' => $grp, 'icon' => 'i-users', 'label' => __( 'Filter critical-risk customers', 'trustlens' ), 'href' => $cust . '&segment=critical', 'keywords' => 'risk review fraud flagged' );
		$items[] = array( 'group' => $grp, 'icon' => 'i-users', 'label' => __( 'Filter high-risk customers', 'trustlens' ),     'href' => $cust . '&segment=risk',     'keywords' => 'caution review flagged' );
		$items[] = array( 'group' => $grp, 'icon' => 'i-users', 'label' => __( 'Filter VIP customers', 'trustlens' ),           'href' => $cust . '&segment=vip',      'keywords' => 'top loyal trusted best' );
		$items[] = array( 'group' => $grp, 'icon' => 'i-zap',   'label' => __( 'Run historical sync', 'trustlens' ),            'href' => admin_url( 'admin.php?page=trustlens' ), 'keywords' => 'import orders backfill initial load' );

		// ---- Chargebacks (Pro) — only show if code is present -------------
		if ( wstl_has_chargebacks() ) {
			$grp = __( 'Chargebacks', 'trustlens' );
			$items[] = array( 'group' => $grp, 'icon' => 'i-chart',    'label' => __( 'View chargeback ratio', 'trustlens' ),           'href' => $cb_url,                        'keywords' => 'dispute ratio visa mastercard threshold', 'pro' => $needs_upgrade );
			$items[] = array( 'group' => $grp, 'icon' => 'i-settings', 'label' => __( 'Configure chargeback thresholds', 'trustlens' ), 'href' => $cb_url . '#wstl-cb-threshold', 'keywords' => 'dispute alert threshold warn danger',     'pro' => $needs_upgrade );
		}

		// ---- Automation (Pro) — only show if code is present --------------
		if ( wstl_has_automation() ) {
			$items[] = array( 'group' => __( 'Automation', 'trustlens' ), 'icon' => 'i-zap', 'label' => __( 'Configure automation rules', 'trustlens' ), 'href' => $auto_url, 'keywords' => 'auto block rules trigger flow if then', 'pro' => $needs_upgrade );
		}

		// ---- Alerts (Free + Pro dispatch) ---------------------------------
		$grp = __( 'Alerts', 'trustlens' );
		$items[] = array( 'group' => $grp, 'icon' => 'i-bell', 'label' => __( 'Configure notifications', 'trustlens' ), 'href' => $notif, 'keywords' => 'notify alert ping warning admin email' );
		if ( class_exists( 'TrustLens_Alert_Dispatcher' ) ) {
			$items[] = array( 'group' => $grp, 'icon' => 'i-bell', 'label' => __( 'Set up Slack / email alerts', 'trustlens' ), 'href' => $notif, 'keywords' => 'slack email webhook channel dispatch attack', 'pro' => $needs_upgrade );
		}

		// ---- Settings by capability ---------------------------------------
		$grp = __( 'Settings', 'trustlens' );
		$items[] = array( 'group' => $grp, 'icon' => 'i-settings', 'label' => __( 'General settings', 'trustlens' ), 'href' => $settings . '&tab=general', 'keywords' => 'retention trust score segments' );
		if ( wstl_has_payment_method_controls() ) {
			$items[] = array( 'group' => $grp, 'icon' => 'i-shield', 'label' => __( 'Configure payment method blocks', 'trustlens' ), 'href' => $settings . '&tab=payment-controls', 'keywords' => 'payment gateway allow deny card bank transfer', 'pro' => $needs_upgrade );
		}
		$items[] = array( 'group' => $grp, 'icon' => 'i-settings', 'label' => __( 'Enable or disable modules', 'trustlens' ), 'href' => $settings . '&tab=modules', 'keywords' => 'toggle feature coupon refund return chargeback card-testing' );
		if ( wstl_has_webhooks() ) {
			$items[] = array( 'group' => $grp, 'icon' => 'i-zap', 'label' => __( 'Set up webhooks', 'trustlens' ), 'href' => $settings . '&tab=webhooks', 'keywords' => 'webhook post http integration slack zapier', 'pro' => $needs_upgrade );
		}
		if ( wstl_has_scheduled_reports() ) {
			$items[] = array( 'group' => $grp, 'icon' => 'i-csv', 'label' => __( 'Schedule email reports', 'trustlens' ), 'href' => $settings . '&tab=reports', 'keywords' => 'report email schedule daily weekly monthly roi summary', 'pro' => $needs_upgrade );
		}
		$items[] = array( 'group' => $grp, 'icon' => 'i-key', 'label' => __( 'Get API key', 'trustlens' ),        'href' => $settings . '&tab=api',  'keywords' => 'api token rest access external integration' );
		$items[] = array( 'group' => $grp, 'icon' => 'i-csv', 'label' => __( 'Export plugin data', 'trustlens' ), 'href' => $settings . '&tab=data', 'keywords' => 'export download backup json csv' );
		$items[] = array( 'group' => $grp, 'icon' => 'i-csv', 'label' => __( 'Import plugin data', 'trustlens' ), 'href' => $settings . '&tab=data', 'keywords' => 'import restore upload json' );

		// ---- Help / license -----------------------------------------------
		$grp = __( 'Help', 'trustlens' );
		$items[] = array( 'group' => $grp, 'icon' => 'i-book', 'label' => __( 'Open documentation', 'trustlens' ), 'href' => wstl_get_docs_url(), 'keywords' => 'docs help guide how to' );
		if ( $needs_upgrade && function_exists( 'wstl_get_upgrade_or_fallback_url' ) ) {
			$items[] = array( 'group' => $grp, 'icon' => 'i-key', 'label' => __( 'Upgrade to Pro', 'trustlens' ), 'href' => wstl_get_upgrade_or_fallback_url(), 'keywords' => 'pro license upgrade paid features' );
		}

		return $items;
	}

	/**
	 * Current user summary for the avatar menu.
	 *
	 * @return array<string,string>
	 */
	private function get_user_info(): array {
		$user = wp_get_current_user();
		$name = $user && $user->display_name ? (string) $user->display_name : __( 'Admin', 'trustlens' );
		$ch   = function_exists( 'mb_substr' ) ? mb_substr( $name, 0, 1 ) : substr( $name, 0, 1 );
		$init = function_exists( 'mb_strtoupper' ) ? mb_strtoupper( $ch ) : strtoupper( $ch );
		return array(
			'name'    => $name,
			'email'   => $user ? (string) $user->user_email : '',
			'initial' => (string) $init,
		);
	}

	/**
	 * Render the header markup via in_admin_header.
	 */
	public function render(): void {
		if ( ! $this->is_plugin_page() ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display-only page check.
		$current = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( (string) $_GET['page'] ) ) : 'trustlens';
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display-only tab check.
		$current_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( (string) $_GET['tab'] ) ) : 'general';

		// Single Lockdown_State instance reused across status + notifications
		// to avoid duplicate transient reads.
		$lockdown      = class_exists( 'TrustLens_Lockdown_State' ) ? new TrustLens_Lockdown_State() : null;
		$nav           = $this->get_nav_items();
		$subtabs       = $this->get_settings_subtabs();
		$status        = $this->get_status( $lockdown );
		$notifications = $this->get_notifications( $lockdown );
		$user          = $this->get_user_info();
		$is_pro        = wstl_can_use_pro();
		$docs_url      = wstl_get_docs_url( $current, $current_tab );

		include TRUSTLENS_PLUGIN_DIR . 'admin/views/admin-header.php';
	}
}
