<?php
/**
 * Admin Menu Handler
 *
 * Owns all wp-admin menu registration, page rendering, and the
 * quickstart-redirect guard. Extracted from the Plugin class so that
 * every concern that touches wp-admin pages lives in one place.
 *
 * @package    Agent_Builder
 * @subpackage Includes
 * @since      2.9.115
 *
 * php version 8.1
 */

declare(strict_types=1);

namespace Agentic;

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

/**
 * Registers all Agent Builder wp-admin menu pages and renders their content.
 */
class Admin_Menu_Handler {

	/**
	 * Register all admin menu and submenu pages.
	 *
	 * Hooked to 'admin_menu'.
	 *
	 * @return void
	 */
	public function register(): void {
		add_menu_page(
			__( 'Agent Builder', 'agent-builder' ),
			__( 'Agent Builder', 'agent-builder' ),
			'agentic_view_dashboard',
			'agent-builder',
			fn() => $this->render_page( 'dashboard' ),
			'dashicons-superhero',
			30
		);

		// When no LLM provider is configured, show only "Quick Start" and bail.
		if ( ! $this->any_llm_configured() ) {
			// Remove the auto-generated duplicate top-level submenu entry WordPress adds.
			remove_submenu_page( 'agent-builder', 'agent-builder' );
			add_submenu_page(
				'agent-builder',
				__( 'Agent Builder — Quick Start', 'agent-builder' ),
				__( 'Quick Start', 'agent-builder' ),
				'manage_options',
				'agentic-signup',
				fn() => $this->render_page( 'signup' )
			);
			// Setup wizard — hidden, must be registered so skip link on signup page works.
			add_submenu_page(
				'',
				__( 'Agent Builder — Setup Wizard', 'agent-builder' ),
				__( 'Setup Wizard', 'agent-builder' ),
				'manage_options',
				'agentic-setup',
				fn() => $this->render_page( 'setup' )
			);
			return;
		}

		// Slug used as the parent for "Advanced" surfaces. In Basic mode these
		// pages are registered hidden (parent '') so deep links keep working
		// while the navigation stays uncluttered for non-technical users.
		$agentic_advanced_parent = $this->advanced_parent_slug();

		add_submenu_page(
			'agent-builder',
			__( 'Agent Builder — Dashboard', 'agent-builder' ),
			__( 'Dashboard', 'agent-builder' ),
			'agentic_view_dashboard',
			'agent-builder'
		);

		add_submenu_page(
			'agent-builder',
			__( 'Agent Builder — Chat', 'agent-builder' ),
			__( 'Chat', 'agent-builder' ),
			'agentic_chat_admin_bar',
			'agentic-chat',
			array( $this, 'render_chat_page' )
		);

		$agentic_agents_menu_title = __( 'Agents', 'agent-builder' );
		if ( class_exists( '\Agentic\Agent_Updates' ) ) {
			$agentic_agents_update_count = \Agentic\Agent_Updates::count();
			if ( $agentic_agents_update_count > 0 ) {
				$agentic_agents_menu_title .= sprintf(
					' <span class="update-plugins count-%1$d"><span class="update-count">%1$d</span></span>',
					$agentic_agents_update_count
				);
			}
		}
		add_submenu_page(
			'agent-builder',
			__( 'Agent Builder — Agents', 'agent-builder' ),
			$agentic_agents_menu_title,
			'agentic_manage_agents',
			'agentic-agents',
			fn() => $this->render_page( 'agents' )
		);

		add_submenu_page(
			'agent-builder',
			__( 'Agent Builder — Publish', 'agent-builder' ),
			__( 'Publish', 'agent-builder' ),
			'agentic_manage_agents',
			'agentic-deployment',
			fn() => $this->render_page( 'deployment' )
		);

		// Hidden page — Run (dedicated execution page).
		add_submenu_page(
			'',
			__( 'Agent Builder — Run', 'agent-builder' ),
			__( 'Run', 'agent-builder' ),
			'agentic_run_tasks_manually',
			'agentic-run-task',
			fn() => $this->render_page( 'run-task' )
		);

		// Hidden page — Agent Creation Wizard ("Train an Agent" guided flow).
		add_submenu_page(
			'',
			__( 'Agent Builder — Train an Agent', 'agent-builder' ),
			__( 'Train an Agent', 'agent-builder' ),
			'manage_options',
			'agentic-agent-wizard',
			fn() => $this->render_page( 'agent-wizard' )
		);

		add_submenu_page(
			'agent-builder',
			__( 'Agent Builder — Knowledge', 'agent-builder' ),
			__( 'Knowledge', 'agent-builder' ),
			'agentic_manage_settings',
			'agentic-train-data',
			array( $this, 'render_train_data_page' )
		);

		add_submenu_page(
			'agent-builder',
			__( 'Agent Builder — Tools', 'agent-builder' ),
			__( 'Tools', 'agent-builder' ),
			'agentic_manage_tools',
			'agentic-tools',
			fn() => $this->render_page( 'tools' )
		);

		// Skills — an advanced concept; hidden from nav in Basic mode but still
		// reachable at admin.php?page=agentic-skills.
		add_submenu_page(
			$agentic_advanced_parent,
			__( 'Agent Builder — Skills', 'agent-builder' ),
			__( 'Skills', 'agent-builder' ),
			'agentic_manage_tools',
			'agentic-skills',
			fn() => $this->render_page( 'skills' )
		);

		$agentic_approvals_title = __( 'Approvals', 'agent-builder' );
		if ( class_exists( '\Agentic\Approval_Queue' ) ) {
			$agentic_pending = ( new \Agentic\Approval_Queue() )->get_pending_count();
			if ( $agentic_pending > 0 ) {
				$agentic_approvals_title .= sprintf(
					' <span class="awaiting-mod count-%1$d"><span class="pending-count">%1$d</span></span>',
					$agentic_pending
				);
			}
		}
		add_submenu_page(
			'agent-builder',
			__( 'Agent Builder — Approvals', 'agent-builder' ),
			$agentic_approvals_title,
			'agentic_manage_agents',
			'agentic-approvals',
			fn() => $this->render_page( 'approvals' )
		);

		// Usage / Costs page is registered by Agent Builder Pro.

		add_submenu_page(
			'agent-builder',
			__( 'Agent Builder — Activity', 'agent-builder' ),
			__( 'Activity', 'agent-builder' ),
			'agentic_view_audit_log',
			'agentic-audit-log',
			fn() => $this->render_page( 'logs' )
		);

		add_submenu_page(
			'agent-builder',
			__( 'Agent Builder — Settings', 'agent-builder' ),
			__( 'Settings', 'agent-builder' ),
			'agentic_manage_settings',
			'agentic-settings',
			array( $this, 'render_settings_page' )
		);

		// Setup wizard — hidden from nav, accessible at admin.php?page=agentic-setup.
		add_submenu_page(
			'',
			__( 'Agent Builder — Setup Wizard', 'agent-builder' ),
			__( 'Setup Wizard', 'agent-builder' ),
			'manage_options',
			'agentic-setup',
			fn() => $this->render_page( 'setup' )
		);

		// Sign-up page — hidden page shown once after plugin activation.
		add_submenu_page(
			'',
			__( 'Agent Builder — Get Started', 'agent-builder' ),
			'',
			'manage_options',
			'agentic-signup',
			fn() => $this->render_page( 'signup' )
		);
	}

	/**
	 * Whether the admin UI is in "Advanced" mode.
	 *
	 * Stored as a site-wide option so the navigation can hide advanced
	 * concepts from non-technical users by default. Both this plugin and
	 * Agent Builder Pro read the same option to gate advanced surfaces.
	 *
	 * @return bool
	 */
	public static function is_advanced_mode(): bool {
		return 'advanced' === get_option( 'agentic_ui_mode', 'basic' );
	}

	/**
	 * Parent slug to register an advanced page under.
	 *
	 * Returns the real parent in Advanced mode so the page appears in the
	 * navigation; returns '' in Basic mode so the page is still registered
	 * (and therefore directly accessible by URL) but hidden from the menu.
	 *
	 * @return string
	 */
	private function advanced_parent_slug(): string {
		return self::is_advanced_mode() ? 'agent-builder' : '';
	}

	/**
	 * Handle the Basic/Advanced UI mode toggle (admin-post).
	 *
	 * @return void
	 */
	public function handle_set_ui_mode(): void {
		if ( ! current_user_can( 'agentic_manage_settings' ) && ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have permission to change the interface mode.', 'agent-builder' ) );
		}
		check_admin_referer( 'agentic_set_ui_mode' );

		$mode = isset( $_POST['agentic_ui_mode'] ) ? sanitize_key( wp_unslash( $_POST['agentic_ui_mode'] ) ) : 'basic';
		if ( ! in_array( $mode, array( 'basic', 'advanced' ), true ) ) {
			$mode = 'basic';
		}
		update_option( 'agentic_ui_mode', $mode, false );

		$redirect = wp_get_referer();
		if ( ! $redirect ) {
			$redirect = admin_url( 'admin.php?page=agent-builder' );
		}
		wp_safe_redirect( $redirect );
		exit;
	}

	/**
	 * Handle the Automatic Agent Updates opt-in/opt-out toggle (admin-post).
	 *
	 * @return void
	 */
	public function handle_set_agent_updates(): void {
		if ( ! current_user_can( 'agentic_manage_settings' ) && ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have permission to change update settings.', 'agent-builder' ) );
		}
		check_admin_referer( 'agentic_set_agent_updates' );

		$enabled = isset( $_POST['agentic_agent_updates'] ) && 'yes' === sanitize_key( wp_unslash( $_POST['agentic_agent_updates'] ) );
		if ( class_exists( '\Agentic\Agent_Updates' ) ) {
			update_option( \Agentic\Agent_Updates::OPT_IN_OPTION, $enabled ? 'yes' : 'no' );
		}

		$redirect = wp_get_referer();
		if ( ! $redirect ) {
			$redirect = admin_url( 'admin.php?page=agent-builder' );
		}
		wp_safe_redirect( $redirect );
		exit;
	}

	/**
	 * Redirect any Agentic admin page to the Quick Start (signup) page when
	 * no LLM provider is configured yet.
	 *
	 * Runs on admin_init. Exits early on the signup/setup pages themselves
	 * so the user is never trapped in a redirect loop.
	 *
	 * @return void
	 */
	public function maybe_redirect_to_quickstart(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		if ( $this->any_llm_configured() ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only page identification.
		$page = isset( $_GET['page'] ) ? sanitize_key( $_GET['page'] ) : '';

		// Not an Agentic page — nothing to do.
		if ( 'agent-builder' !== $page && ! str_starts_with( $page, 'agentic-' ) ) {
			return;
		}

		// Already on an allowed page — don't redirect.
		if ( in_array( $page, array( 'agentic-signup', 'agentic-setup' ), true ) ) {
			return;
		}

		// No usable provider — revert onboarding so the setup wizard reappears
		// (a plugin with zero configured providers is non-functional).
		update_option( 'agentic_onboarding_complete', false );

		wp_safe_redirect( admin_url( 'admin.php?page=agentic-signup' ) );
		exit;
	}

	/**
	 * Replace WordPress's bare "Sorry, you are not allowed to access this page."
	 * with a branded, actionable notice when a logged-in user without the
	 * required permissions lands on an Agent Builder admin page.
	 *
	 * Hooked to 'admin_page_access_denied', which WordPress fires immediately
	 * before it wp_die()s in wp-admin/admin.php. We only take over for our own
	 * pages, so denials for other plugins are left untouched.
	 *
	 * @return void
	 */
	public function maybe_show_access_notice(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only page identification.
		$page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '';

		// Only intervene for Agent Builder pages; leave every other denial alone.
		if ( 'agent-builder' !== $page && ! str_starts_with( $page, 'agentic-' ) ) {
			return;
		}

		$admin_email = get_option( 'admin_email', '' );

		$parts   = array();
		$parts[] = '<h1>' . esc_html__( 'Administrator access required', 'agent-builder' ) . '</h1>';
		$parts[] = '<p>' . esc_html__( 'Agent Builder can only be set up and managed by a site administrator. Your account does not have the required permissions, so we cannot continue here.', 'agent-builder' ) . '</p>';
		$parts[] = '<p>' . esc_html__( 'Please sign in with an administrator account, or ask a user with administrator access to complete the setup.', 'agent-builder' ) . '</p>';
		if ( is_email( $admin_email ) ) {
			$parts[] = '<p>' . sprintf(
				/* translators: %s: site administrator email address, rendered as a mailto link. */
				esc_html__( 'Need help? Contact your site administrator at %s.', 'agent-builder' ),
				'<a href="mailto:' . esc_attr( $admin_email ) . '">' . esc_html( $admin_email ) . '</a>'
			) . '</p>';
		}
		$parts[] = '<p><a href="' . esc_url( admin_url() ) . '">' . esc_html__( 'Back to the WordPress dashboard', 'agent-builder' ) . '</a></p>';

		wp_die(
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- each $parts fragment is individually escaped (esc_html__/esc_attr/esc_url) above.
			implode( '', $parts ),
			esc_html__( 'Administrator access required', 'agent-builder' ),
			array( 'response' => 403 )
		);
	}

	/**
	 * Inject contextual help bar (after h1) and footer legal links (end of .wrap)
	 * on all Agentic admin pages via JavaScript.
	 *
	 * Runs on admin_footer so the full page DOM is already in place.
	 *
	 * @return void
	 */
	public function render_admin_page_links(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only, page identification only.
		$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';

		// Only on Agentic admin pages.
		if ( 'agent-builder' !== $page && ! str_starts_with( $page, 'agentic-' ) ) {
			return;
		}

		// Skip the setup wizard — it renders a full-page custom overlay.
		if ( 'agentic-setup' === $page ) {
			return;
		}

		// Resolve active tab — settings/deployment use ?tab=, tools uses ?section=.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only.
		$tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : '';
		if ( ! $tab ) {
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only.
			$tab = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '';
		}

		$doc_url     = $this->get_page_doc_url( $page, $tab );
		$support_url = 'https://agentic-plugin.com/support/';

		$footer_html = '<div class="agentic-page-footer">'
			. '<span class="agentic-page-footer-left">'
			. esc_html__( 'Need help?', 'agent-builder' ) . ' '
			. '<a href="' . esc_url( $support_url ) . '" target="_blank" rel="noopener">' . esc_html__( 'Visit our Support Center', 'agent-builder' ) . '</a>'
			. ' | '
			. '<a href="' . esc_url( $doc_url ) . '" target="_blank" rel="noopener">' . esc_html__( 'Documentation', 'agent-builder' ) . '</a>'
			. '</span>'
			. '<span class="agentic-page-footer-right">'
			. '<a href="https://agentic-plugin.com/terms-of-service/" target="_blank" rel="noopener">' . esc_html__( 'Terms of Service', 'agent-builder' ) . '</a>'
			. ' | '
			. '<a href="https://agentic-plugin.com/privacy-policy/" target="_blank" rel="noopener">' . esc_html__( 'Privacy Policy', 'agent-builder' ) . '</a>'
			. ' | '
			. '<a href="https://agentic-plugin.com/gdpr-policy/" target="_blank" rel="noopener">' . esc_html__( 'GDPR Policy', 'agent-builder' ) . '</a>'
			. '</span>'
			. '</div>';
		?>
		<script>
		(function() {
			var wrap = document.querySelector( '.wrap' );
			if ( ! wrap ) return;

			// Append footer bar at end of .wrap.
			var footerDiv = document.createElement( 'div' );
			footerDiv.innerHTML = <?php echo wp_json_encode( $footer_html ); ?>;
			wrap.appendChild( footerDiv.firstChild );
		})();
		</script>
		<?php
	}

	/**
	 * Include a simple admin page template.
	 *
	 * @param string $file Template filename (without .php extension) inside admin/.
	 * @return void
	 */
	public function render_page( string $file ): void {
		include AGENT_BUILDER_DIR . "admin/{$file}.php";
	}

	/**
	 * Render Agent Chat page.
	 *
	 * @return void
	 */
	public function render_chat_page(): void {
		wp_enqueue_style(
			'agentic-chat',
			AGENT_BUILDER_URL . 'assets/css/chat.css',
			array(),
			AGENT_BUILDER_VERSION
		);
		\Agentic\Chat_Assets::maybe_add_chat_theme_overrides();

		wp_enqueue_script(
			'agentic-chat',
			AGENT_BUILDER_URL . 'assets/js/chat.js',
			array( 'agentic-ui' ),
			AGENT_BUILDER_VERSION,
			true
		);

		// Resolve agent slug (same priority as chat-interface.php: URL → cookie → first).
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$agentic_chat_slug = isset( $_GET['agent'] ) ? sanitize_key( $_GET['agent'] ) : '';
		if ( ! $agentic_chat_slug && isset( $_COOKIE['agentic_last_agent'] ) ) {
			$agentic_chat_slug = sanitize_key( $_COOKIE['agentic_last_agent'] );
		}
		$agentic_chat_features = agentic_get_effective_chat_features( $agentic_chat_slug );

		wp_localize_script(
			'agentic-chat',
			'agenticChat',
			array(
				'restUrl'        => rest_url( 'agentic/v1/' ),
				'nonce'          => wp_create_nonce( 'wp_rest' ),
				'userId'         => get_current_user_id(),
				'userName'       => wp_get_current_user()->display_name,
				'audio'          => $agentic_chat_features['audio'],
				'vision'         => $agentic_chat_features['vision'],
				'costs'          => $agentic_chat_features['costs'],
				'tts'            => $agentic_chat_features['tts'],
				'ttsVoice'       => get_option( 'agentic_tts_voice', 'journey-f' ),
				'consentEnabled' => get_option( 'agentic_chat_consent_enabled', false ) ? '1' : '0',
				'consentText'    => \Agentic\GDPR::get_consent_text(),
				'isAdmin'        => current_user_can( 'manage_options' ) ? '1' : '0',
				'adminUrl'       => admin_url(),
				'adminAgentsUrl' => admin_url( 'admin.php?page=agentic-agents' ),
				// Agent-to-agent handoff context (set when arriving via a delegate
				// button). Without these the admin chat drops the handoff silently.
				// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only display params from a same-site delegate link.
				'initialMessage' => isset( $_GET['initial_message'] ) ? sanitize_textarea_field( wp_unslash( $_GET['initial_message'] ) ) : '',
				// phpcs:ignore WordPress.Security.NonceVerification.Recommended
				'handoffFrom'    => isset( $_GET['handoff_from'] ) ? sanitize_key( wp_unslash( $_GET['handoff_from'] ) ) : '',
				// phpcs:ignore WordPress.Security.NonceVerification.Recommended
				'handoffContext' => isset( $_GET['handoff_context'] ) ? sanitize_textarea_field( wp_unslash( $_GET['handoff_context'] ) ) : '',
				'slashCommands'  => \Agentic\Chat_Assets::get_slash_commands_for_js(),
				'i18n'           => agentic_chat_i18n(),
			)
		);

		echo '<div class="wrap">';
		echo '<h1>' . esc_html__( 'Agent Chat', 'agent-builder' ) . ' <span class="agentic-status" style="font-size: 14px; font-weight: normal; vertical-align: middle;"><span class="agentic-status-dot"></span>' . esc_html__( 'Online', 'agent-builder' ) . '</span></h1>';
		include AGENT_BUILDER_DIR . 'templates/chat-interface.php';
		echo '<p style="margin-top:12px;"><a href="' . esc_url( admin_url( 'admin.php?page=agentic-deployment' ) ) . '">' . esc_html__( 'Manage Agent Deployments', 'agent-builder' ) . '</a></p>';
		echo '</div>';
	}

	/**
	 * Render Settings page.
	 *
	 * @return void
	 */
	public function render_settings_page(): void {
		wp_enqueue_script(
			'agentic-settings',
			AGENT_BUILDER_URL . 'assets/js/settings.js',
			array( 'agentic-ui' ),
			AGENT_BUILDER_VERSION,
			true
		);

		// Build per-provider key map from the DB-backed provider registry.
		$agentic_s_provider_keys = array();
		foreach ( \Agentic\Provider_Registry::get_all() as $agentic_s_p ) {
			if ( ! empty( $agentic_s_p['api_key'] ) ) {
				$agentic_s_provider_keys[ $agentic_s_p['slug'] ] = $agentic_s_p['api_key'];
			}
		}

		wp_localize_script(
			'agentic-settings',
			'agenticSettings',
			array(
				'restUrl'              => rest_url( 'agentic/v1/' ),
				'nonce'                => wp_create_nonce( 'wp_rest' ),
				'settingsNonce'        => wp_create_nonce( 'agentic_settings_nonce' ),
				'providerKeys'         => array_map( 'strval', $agentic_s_provider_keys ),
				'providerModels'       => array_map( 'strval', (array) get_option( 'agentic_model_preferences', array() ) ),
				'providerVisionModels' => ( function () {
					$all    = \Agentic\Provider_Registry::get_all();
					$result = array();
					foreach ( $all as $p ) {
						if ( ! empty( $p['vision_model'] ) ) {
							$result[ $p['slug'] ] = (string) $p['vision_model'];
						}
					}
					return $result;
				} )(),
				'agentOverrides'       => ( function () {
					$agentic_ov_map = array();
					foreach ( array_keys( \Agentic_Agent_Registry::get_instance()->get_installed_agents() ) as $agentic_ov_s ) {
						$agentic_ov_entry = array(
							'provider'     => \Agentic\Agent_Settings::get( $agentic_ov_s, 'override_provider' ),
							'model'        => \Agentic\Agent_Settings::get( $agentic_ov_s, 'override_model' ),
							'vision_model' => \Agentic\Agent_Settings::get( $agentic_ov_s, 'override_vision_model' ),
							'mode'         => \Agentic\Agent_Settings::get( $agentic_ov_s, 'override_mode' ),
							'audio'        => \Agentic\Agent_Settings::get( $agentic_ov_s, 'override_audio' ),
							'tts'          => \Agentic\Agent_Settings::get( $agentic_ov_s, 'override_tts' ),
							'vision'       => \Agentic\Agent_Settings::get( $agentic_ov_s, 'override_vision' ),
							'costs'        => \Agentic\Agent_Settings::get( $agentic_ov_s, 'override_costs' ),
							'cache'        => \Agentic\Agent_Settings::get( $agentic_ov_s, 'override_cache' ),
						);
						if ( array_filter( $agentic_ov_entry ) ) {
							$agentic_ov_map[ $agentic_ov_s ] = $agentic_ov_entry;
						}
					}
					return $agentic_ov_map;
				} )(),
				'globalDefault'        => get_option( 'agentic_llm_provider', 'agentic' ),
			)
		);

		include AGENT_BUILDER_DIR . 'admin/settings.php';
	}

	/**
	 * Render Train on Data page.
	 *
	 * @return void
	 */
	public function render_train_data_page(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only tab params.
		$active_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'wiki';
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$vector_tab = isset( $_GET['vtab'] ) ? sanitize_key( wp_unslash( $_GET['vtab'] ) ) : 'scan';

		$is_pro = class_exists( '\Agentic\License_Client' ) && License_Client::get_instance()->is_pro();

		// Free Knowledge Wiki UI.
		wp_enqueue_script(
			'agentic-okf-knowledge',
			AGENT_BUILDER_URL . 'assets/js/okf-knowledge.js',
			array( 'jquery' ),
			AGENT_BUILDER_VERSION,
			true
		);

		// Hosted Vector Store UI only when Pro is active (train-data.js talks to RAG API).
		if ( $is_pro && 'vector' === $active_tab ) {
			wp_enqueue_script(
				'agentic-train-data',
				AGENT_BUILDER_URL . 'assets/js/train-data.js',
				array( 'jquery', 'agentic-ui' ),
				AGENT_BUILDER_VERSION,
				true
			);
			wp_localize_script(
				'agentic-train-data',
				'agenticTrainData',
				array(
					'ajaxUrl'   => admin_url( 'admin-ajax.php' ),
					'nonce'     => wp_create_nonce( 'agentic_train_data' ),
					'activeTab' => $vector_tab,
					'siteUrl'   => site_url(),
				)
			);
		}

		include AGENT_BUILDER_DIR . 'admin/train-data.php';
	}

	/**
	 * Check if at least one LLM provider has a usable API key (or no-key endpoint).
	 *
	 * Used to gate the full admin menu: when nothing is configured the user is
	 * funnelled to the Quick Start / signup page.
	 *
	 * @return bool
	 */
	private function any_llm_configured(): bool {
		return \Agentic\Provider_Registry::has_usable_provider();
	}

	/**
	 * Get the documentation URL for a given Agentic admin page slug and optional tab.
	 *
	 * The full map lives in admin/doc-map.php — edit that file to add
	 * or update entries without touching this class.
	 *
	 * @param string $page The admin page slug (value of ?page= query var).
	 * @param string $tab  The active tab/section (value of ?tab= or ?section= query var).
	 * @return string Absolute URL to the relevant documentation page.
	 */
	private function get_page_doc_url( string $page, string $tab = '' ): string {
		$map = require AGENT_BUILDER_DIR . 'admin/doc-map.php';

		$key = $tab ? "{$page}:{$tab}" : '';
		if ( $key && isset( $map['tabs'][ $key ] ) ) {
			return $map['tabs'][ $key ];
		}

		return $map['pages'][ $page ] ?? 'https://agentic-plugin.com/documentation/';
	}
}
