<script lang="ts">
	import { goto } from '$app/navigation';
	import { page } from '$app/stores';
	import { browser } from '$app/environment';
	import { GLOBAL_NAV } from '$lib/config/shortcuts';
	import { hasAccessTokenInDocument } from '$lib/access-token-cookie-browser';
	import { shortcutStore, activeShortcutsList } from '$lib/stores/shortcut-store';
	import { focusStore, interactionMode } from '$lib/stores/focus-store';
	import { helpStore } from '$lib/stores/help.svelte';
	import ShortcutsHelpModal from './ShortcutsHelpModal.svelte';

	let showHelp = $state(false);
	/** Element to restore focus when closing the F1 shortcuts help modal */
	let helpFocusRestore: HTMLElement | null = null;
	let lastShortcutTime = 0;

	function restoreHelpFocus() {
		const el = helpFocusRestore;
		helpFocusRestore = null;
		if (el && document.contains(el) && typeof el.focus === 'function') {
			try {
				el.focus();
			} catch {
				/* ignore e.g. disconnected nodes */
			}
		}
	}

	// Verificar si el usuario está autenticado
	function isAuthenticated(): boolean {
		if (!browser) return false;
		const currentPath = $page?.url?.pathname || '';
		const isAuthenticatedRoute = currentPath.startsWith('/dashboard');
		const hasAccessToken =
			hasAccessTokenInDocument() || localStorage.getItem('access_token');
		return isAuthenticatedRoute && !!hasAccessToken;
	}

	function isVisibleInMainContent(htmlEl: HTMLElement): boolean {
		if (htmlEl.closest('[data-sidebar="sidebar"]')) return false;
		return !!(htmlEl.offsetWidth || htmlEl.offsetHeight || htmlEl.getClientRects().length);
	}

	function inputIsSearchCandidate(el: HTMLInputElement): boolean {
		const t = (el.type || 'text').toLowerCase();
		return !['hidden', 'checkbox', 'radio', 'file', 'button', 'submit', 'reset'].includes(t);
	}

	/**
	 * Alt+B: focus the current view's primary filter/search when possible.
	 * Order: [data-view-search] → placeholder hints (buscar/search/…) →
	 * first visible text-like input before the main table / catalog scroll → global sr-only fallback.
	 */
	function focusViewSearchOrGlobal() {
		const main =
			document.getElementById('dashboard-main-content') ||
			document.getElementById('main-form-content');

		const tryFocus = (el: HTMLElement | null | undefined): boolean => {
			if (!el || !isVisibleInMainContent(el)) return false;
			if (el.closest('[role="dialog"]')) return false;
			try {
				el.focus();
			} catch {
				return false;
			}
			setTimeout(() => {
				el.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
			}, 50);
			return true;
		};

		if (main) {
			const explicit = main.querySelector<HTMLElement>('[data-view-search]:not([disabled])');
			if (tryFocus(explicit)) return;

			const phPattern = /buscar|search|filtrar|filter|búsqueda|busqueda/i;
			const inputs = Array.from(
				main.querySelectorAll<HTMLInputElement>('input:not([disabled])')
			).filter(inputIsSearchCandidate);

			for (const input of inputs) {
				if (!isVisibleInMainContent(input)) continue;
				if (input.closest('[role="dialog"]')) continue;
				if (phPattern.test(input.placeholder || '')) {
					if (tryFocus(input)) return;
				}
			}

			const boundary = main.querySelector(
				'table, tbody, .catalog-table-scroll, [data-slot="table-container"]'
			);
			if (boundary) {
				for (const input of inputs) {
					if (!isVisibleInMainContent(input)) continue;
					if (input.closest('[role="dialog"]')) continue;
					if (input.compareDocumentPosition(boundary) & Node.DOCUMENT_POSITION_FOLLOWING) {
						if (tryFocus(input)) return;
					}
				}
			}
		}

		document.getElementById('global-search-input')?.focus();
	}

	/** First meaningful control in main area (forms); optional delay for post-navigation paint. */
	function focusMainContentPrimary(options?: { delay?: number }) {
		const delay = options?.delay ?? 350;
		setTimeout(() => {
			const container =
				document.getElementById('main-form-content') ||
				document.getElementById('dashboard-main-content') ||
				document.body;

			const activePanels = container.querySelectorAll('[role="tabpanel"][data-state="active"]');
			const searchableAreas =
				activePanels.length > 0 ? Array.from(activePanels).reverse() : [container];

			for (const area of searchableAreas) {
				const focusables = area.querySelectorAll(
					'input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]):not([role="tab"])'
				);
				const firstVisible = Array.from(focusables).find((el) =>
					isVisibleInMainContent(el as HTMLElement)
				) as HTMLElement | undefined;

				if (firstVisible) {
					firstVisible.focus();
					setTimeout(() => {
						firstVisible.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
					}, 100);
					return;
				}
			}

			const fallbacks = container.querySelectorAll(
				'tr[tabindex="0"], [data-slot="table-row"][tabindex="0"], a[href]:not([tabindex="-1"]), button:not([disabled]):not([role="tab"]):not([tabindex="-1"])'
			);
			const fb = Array.from(fallbacks).find((el) =>
				isVisibleInMainContent(el as HTMLElement)
			) as HTMLElement | undefined;
			if (fb) {
				fb.focus();
				setTimeout(() => {
					fb.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
				}, 100);
			}
		}, delay);
	}

	function focusSidebarNav() {
		window.dispatchEvent(new CustomEvent('app:expand-sidebar-for-nav'));
		setTimeout(() => {
			const nav = document.getElementById('dashboard-sidebar-nav');
			if (!nav) return;
			const candidates = nav.querySelectorAll(
				'a[href]:not([tabindex="-1"]), button:not([disabled]):not([tabindex="-1"])'
			);
			const first = Array.from(candidates).find(
				(el) => !(el as HTMLElement).closest('[data-slot="sidebar-rail"]')
			) as HTMLElement | undefined;
			if (first) {
				first.focus();
				setTimeout(() => {
					first.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
				}, 50);
			}
		}, 350);
	}

	function focusTriggerByDescription(description: string) {
		// Small delay to allow Svelte to update the DOM
		setTimeout(() => {
			// Extract a meaningful keyword from the description (e.g., "Go to DTA")
			const words = description.split(' ');
			// Look for words that are uppercase or the last word
			const keyword =
				words.find((w) => w.length >= 3 && w === w.toUpperCase()) || words[words.length - 1];

			if (!keyword) return;

			// Find buttons or tabs containing that text
			const elements = document.querySelectorAll('button, [role="tab"], a');
			const target = Array.from(elements).find((el) => {
				const text = el.textContent?.trim() || '';
				// Exclude sidebar
				if (el.closest('[data-sidebar="sidebar"]')) return false;

				return text.toLowerCase().includes(keyword.toLowerCase());
			}) as HTMLElement;

			if (target) {
				target.focus();
				target.scrollIntoView({ behavior: 'smooth', block: 'center' });
			}
		}, 100);
	}

	// FOCUS POLICY DICTIONARY
	// Decides what to focus after a shortcut/navigation based on context
	const FOCUS_POLICY: Record<string, 'trigger' | 'first-input'> = {
		// Pedimentos
		'General Tab Navigation': 'trigger',
		'Pedimento Edit Main Tabs': 'first-input',
		'Otros Tab Navigation': 'first-input',
		'Contribuciones Tab Navigation': 'first-input',

		// Dashboard forms with Alt+Digit tab navigation
		'Edit Broker Tabs': 'first-input',
		'Edit Client Provider': 'first-input',
		'Formulario Empresa': 'first-input',
		'Formulario DODA': 'first-input',
		'Invoice Edit': 'first-input',
		'Part Form': 'first-input',
		'Invoice Item Form (Inventory)': 'first-input',
		'Invoice Item Form (Fixed Asset)': 'first-input',
		'Invoice Items Tab': 'first-input',
		'Customs Brokers List': 'trigger',
		'Clients Providers List': 'trigger'
	};

	/** When focus is inside the line-item sheet, only these contexts may handle shortcuts (overrides Invoice Edit). */
	const INVOICE_ITEM_SHEET_CONTEXTS = new Set([
		'Invoice Item Form (Fixed Asset)',
		'Invoice Item Form (Inventory)'
	]);

	const INVOICE_ITEM_SHEET_CONTEXT_BY_ATTR: Record<string, string> = {
		fixed_asset: 'Invoice Item Form (Fixed Asset)',
		inventory: 'Invoice Item Form (Inventory)'
	};

	function filterShortcutsWhenInItemSheet<
		T extends { context: string; key: string; description: string; action: () => void }
	>(pool: T[], eventTarget: EventTarget | null): T[] {
		const el = eventTarget as HTMLElement | null;
		const sheet = el?.closest?.('[data-invoice-item-sheet]') as HTMLElement | null;
		if (!sheet) return pool;
		const kind = sheet.getAttribute('data-invoice-item-sheet') || '';
		const onlyContext = INVOICE_ITEM_SHEET_CONTEXT_BY_ATTR[kind];
		if (onlyContext) return pool.filter((s) => s.context === onlyContext);
		return pool.filter((s) => INVOICE_ITEM_SHEET_CONTEXTS.has(s.context));
	}

	// Listen for remote focus requests (e.g., from mouse navigation)
	$effect(() => {
		if ($focusStore) {
			// If a shortcut was just pressed, ignore remote focus requests for 250ms
			// to allow the shortcut's specific focus strategy to prevail
			if (Date.now() - lastShortcutTime < 250) return;

			if ($focusStore.strategy === 'first-input') {
				focusMainContentPrimary();
			} else if ($focusStore.strategy === 'trigger' && $focusStore.description) {
				focusTriggerByDescription($focusStore.description);
			}
		}
	});

	function handleKeydown(event: KeyboardEvent) {
		// Verificar autenticación al inicio
		const authenticated = isAuthenticated();

		const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
		if (!key) return;
		const lowerKey = key.toLowerCase();

		// Ignore standalone modifiers
		if (['Control', 'Alt', 'Shift', 'Meta'].includes(key)) return;

		// Construct current combo string: "Alt+Shift+K"
		const modifiers = [];
		if (ctrlKey) modifiers.push('Ctrl');
		if (altKey) modifiers.push('Alt');
		if (shiftKey) modifiers.push('Shift');
		if (metaKey) modifiers.push('Meta');

		const combo = [...modifiers, key.toUpperCase()].join('+');

		// Input Guard
		const target = event.target as HTMLElement;
		const isInput =
			target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable;

		// 0. SEARCH TO TABLE FLOW: ArrowDown from search input to first table row
		if (isInput && key === 'ArrowDown') {
			const dialog = target.closest('[role="dialog"]');
			if (dialog) {
				const firstRow = dialog.querySelector(
					'tr[tabindex="0"], [data-slot$="-item"][tabindex="0"]'
				) as HTMLElement;
				if (firstRow) {
					event.preventDefault();
					firstRow.focus();
					return;
				}
			} else {
				// Invoices list (and similar): jump from a filter field to first data row
				const main =
					document.getElementById('dashboard-main-content') ||
					document.getElementById('main-form-content');
				if (main?.contains(target)) {
					const firstDataRow = main.querySelector(
						'[data-invoice-list-table] tbody tr[data-invoice-data-row][tabindex="0"]'
					) as HTMLElement | null;
					if (firstDataRow) {
						event.preventDefault();
						firstDataRow.focus();
						setTimeout(() => {
							firstDataRow.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
						}, 50);
						return;
					}
				}
			}
		}

		// 1. HELP: F1
		if (key === 'F1') {
			// Solo permitir F1 si está autenticado
			if (!isAuthenticated()) {
				return;
			}
			event.preventDefault();
			if (showHelp) {
				showHelp = false;
				restoreHelpFocus();
			} else {
				const active = document.activeElement;
				if (active instanceof HTMLElement) {
					helpFocusRestore = active;
				}
				showHelp = true;
			}
			return;
		}

		// 1.5 HELP DRAWER: F12
		if (key === 'F12') {
			if (!authenticated) {
				return;
			}
			event.preventDefault();
			helpStore.toggle();
			return;
		}

		// 2. ESCAPE
		if (key === 'Escape') {
			if (showHelp) {
				showHelp = false;
				restoreHelpFocus();
				event.preventDefault();
				return;
			}
			// specific search for Escape in REVERSE order (LIFO); sheet partida overrides Invoice Edit
			const escapePool = filterShortcutsWhenInItemSheet(
				[...$activeShortcutsList].reverse(),
				target
			);
			const match = escapePool.find((s) => s.key === 'Escape');
			if (match) {
				event.preventDefault();
				match.action();
				return;
			}
		}

		// 3. PRIORITY: LOCAL SHORTCUTS
		// Solo permitir atajos locales si está autenticado
		if (authenticated) {
			// Match exact combo string against registered shortcuts
			// Search in REVERSE order (LIFO) so recent contexts (modals) override earlier ones (pages)
			const reversedShortcuts = filterShortcutsWhenInItemSheet(
				[...$activeShortcutsList].reverse(),
				target
			);
			let match = reversedShortcuts.find((s) => s.key === combo);

			// Fallback: If no match found by 'key' (e.g. Shift+1 produces 'Alt+Shift+!'),
			// try matching by 'code' (e.g. 'Alt+Shift+Digit1')
			if (!match) {
				const codeCombo = [...modifiers, event.code].join('+');
				match = reversedShortcuts.find((s) => s.key === codeCombo);
			}

			if (match) {
				// Guard: If it's a single key (no modifiers) and we are in input, ignore it
				// Unless the shortcut explicitly says "allowInInput" (not implemented yet, assuming strictly no inputs for single keys)
				if (modifiers.length === 0 && isInput) {
					// allow native typing
					return;
				}

				event.preventDefault();
				event.stopPropagation(); // Stop bubbling
				lastShortcutTime = Date.now();
				match.action();

				// Hybrid focus strategy (skip when shortcut manages focus itself)
				if (combo.includes('Alt+') && match && !match.skipDefaultFocusAfter) {
					const isDigit = combo.includes('Digit') || (event.code && event.code.startsWith('Digit'));
					const strategy = FOCUS_POLICY[match.context] || 'first-input';

					if (isDigit && strategy === 'trigger') {
						// Focus the trigger for specific views (General sub-tabs)
						focusTriggerByDescription(match.description);
					} else {
						// Default: Focus the first input (Main tabs, non-trigger sub-tabs)
						focusMainContentPrimary();
					}
				}
				return;
			}
		} // Fin del bloque authenticated

		// 4. GLOBAL NAV: Alt + Key (Legacy/Default behavior for global nav)
		// Solo permitir si está autenticado
		if (authenticated && altKey && modifiers.length === 1) {
			// Exactly Alt + Key (no shift/ctrl)
			// Special: Alt+B -> Focus view search / filters or global fallback
			if (lowerKey === 'b') {
				event.preventDefault();
				lastShortcutTime = Date.now();
				focusViewSearchOrGlobal();
				return;
			}

			if (lowerKey === 'n') {
				event.preventDefault();
				lastShortcutTime = Date.now();
				focusSidebarNav();
				return;
			}

			if (lowerKey === 'j') {
				event.preventDefault();
				lastShortcutTime = Date.now();
				focusMainContentPrimary({ delay: 0 });
				return;
			}

			const route = GLOBAL_NAV[lowerKey as keyof typeof GLOBAL_NAV];
			if (
				route &&
				route !== 'SEARCH_FOCUS' &&
				route !== 'SIDEBAR_FOCUS' &&
				route !== 'MAIN_CONTENT_FOCUS'
			) {
				event.preventDefault();
				lastShortcutTime = Date.now();
				void goto(route).then(() => {
					focusMainContentPrimary();
				});
				return;
			}
		}

		// 5. GLOBAL TABLE & SELECT NAVIGATION: Arrows / Enter / Tab
		const isRowOrItem =
			target.tagName === 'TR' ||
			target.getAttribute('data-slot') === 'table-row' ||
			target.getAttribute('data-slot') === 'select-item' ||
			target.closest('[data-slot="table-row"]') ||
			target.closest('[data-slot="select-item"]');

		if (isRowOrItem) {
			const element = (
				target.getAttribute('data-slot')?.includes('-item') || target.tagName === 'TR'
					? target
					: target.closest('[data-slot$="-row"], [data-slot$="-item"]')
			) as HTMLElement;

			if (!element) return;

			const inInvoiceListDataBody =
				element.tagName === 'TR' &&
				element.hasAttribute('data-invoice-data-row') &&
				!!element.closest('[data-invoice-list-table] tbody');

			const inInvoiceItemsDataBody =
				element.tagName === 'TR' &&
				element.hasAttribute('data-item-line-row') &&
				!!element.closest('[data-invoice-items-table] tbody');

			// Logic for UP/DOWN arrows
			if (key === 'ArrowDown') {
				if (inInvoiceItemsDataBody) {
					let next = element.nextElementSibling as HTMLElement | null;
					while (next) {
						if (next.hasAttribute('data-item-line-row')) {
							event.preventDefault();
							next.focus();
							setTimeout(() => {
								next.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
							}, 50);
							return;
						}
						next = next.nextElementSibling as HTMLElement | null;
					}
					return;
				}
				if (inInvoiceListDataBody) {
					let next = element.nextElementSibling as HTMLElement | null;
					while (next) {
						if (next.hasAttribute('data-invoice-data-row')) {
							event.preventDefault();
							next.focus();
							setTimeout(() => {
								next.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
							}, 50);
							return;
						}
						next = next.nextElementSibling as HTMLElement | null;
					}
					return;
				}
				const next = element.nextElementSibling as HTMLElement;
				if (next) {
					event.preventDefault();
					next.focus();
				}
			} else if (key === 'ArrowUp') {
				if (inInvoiceItemsDataBody) {
					let prev = element.previousElementSibling as HTMLElement | null;
					while (prev) {
						if (prev.hasAttribute('data-item-line-row')) {
							event.preventDefault();
							prev.focus();
							setTimeout(() => {
								prev.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
							}, 50);
							return;
						}
						prev = prev.previousElementSibling as HTMLElement | null;
					}
					return;
				}
				if (inInvoiceListDataBody) {
					let prev = element.previousElementSibling as HTMLElement | null;
					while (prev) {
						if (prev.hasAttribute('data-invoice-data-row')) {
							event.preventDefault();
							prev.focus();
							setTimeout(() => {
								prev.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
							}, 50);
							return;
						}
						prev = prev.previousElementSibling as HTMLElement | null;
					}
					return;
				}
				const prev = element.previousElementSibling as HTMLElement;
				if (prev) {
					event.preventDefault();
					prev.focus();
				}
			} else if (key === 'Enter' || key === ' ') {
				if (target.tagName !== 'INPUT' && target.tagName !== 'TEXTAREA') {
					event.preventDefault();
					if (element.hasAttribute('data-item-line-row')) {
						const editBtn = element.querySelector('button') as HTMLButtonElement | null;
						editBtn?.click();
					} else {
						element.click();
					}
				}
			} else if (key === 'Tab') {
				// Only hijack Tab inside dialogs (selection lists). In main content, preserve natural tab order.
				if (!element.closest('[role="dialog"]')) {
					return;
				}
				const siblings = Array.from(element.parentElement?.children || []);
				const index = siblings.indexOf(element);

				if (shiftKey) {
					if (index > 0) {
						event.preventDefault();
						(siblings[index - 1] as HTMLElement).focus();
					}
				} else {
					if (index < siblings.length - 1) {
						event.preventDefault();
						(siblings[index + 1] as HTMLElement).focus();
					}
				}
			}
		}
	}

	function handleFocusIn(event: FocusEvent) {
		const target = event.target as HTMLElement;
		if (!target) return;

		// Exclude sidebar from any magic scrolling
		if (target.closest('[data-sidebar="sidebar"]')) return;

		// Exclude checkboxes inside tables (e.g. row selection) - prevents unwanted scroll when selecting
		if (
			target.tagName === 'INPUT' &&
			(target as HTMLInputElement).type === 'checkbox' &&
			target.closest('table')
		) {
			return;
		}

		// Exclude table rows (TR) - they have tabindex for keyboard nav but clicking to select shouldn't scroll
		if (target.tagName === 'TR' && target.closest('table')) {
			return;
		}

		// Check if it's an interactive element we care about
		const isInteractive =
			['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'A'].includes(target.tagName) ||
			target.role === 'tab';

		if (isInteractive) {
			// Force scroll to center after a delay to override browser default behavior
			setTimeout(() => {
				target.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
			}, 100);
		}
	}
	// --- DYNAMIC INTERACTIVE OBSERVER ---
	// Automatically make any clickable row or item focusable
	$effect(() => {
		const observer = new MutationObserver((mutations) => {
			mutations.forEach((mutation) => {
				mutation.addedNodes.forEach((node) => {
					if (node instanceof HTMLElement) {
						// Find TRs that look like they are clickable/interactive
						const trs = node.tagName === 'TR' ? [node] : Array.from(node.querySelectorAll('tr'));
						trs.forEach((tr) => {
							// If it has a cursor-pointer class or an onclick handler (complex to detect in Svelte,
							// so we use a broad heuristic: any TR inside a dialog's scroll area)
							const isInSelectionDialog =
								!!tr.closest('[role="dialog"]') &&
								!!tr.closest('.overflow-y-auto, .overflow-auto');
							if (isInSelectionDialog && !tr.hasAttribute('tabindex')) {
								tr.setAttribute('tabindex', '0');
								// Add focus styles if it's a native TR
								if (!tr.getAttribute('data-slot')) {
									tr.classList.add(
										'focus-visible:outline-none',
										'focus-visible:bg-accent',
										'focus-visible:ring-1',
										'focus-visible:ring-ring'
									);
								}
							}
						});
					}
				});
			});
		});

		observer.observe(document.body, { childList: true, subtree: true });
		return () => observer.disconnect();
	});
</script>

<svelte:window
	onkeydown={(e) => {
		interactionMode.set('keyboard');
		handleKeydown(e);
	}}
	onmousedown={() => interactionMode.set('mouse')}
	onfocusin={handleFocusIn}
/>

{#if showHelp}
	<ShortcutsHelpModal
		open={true}
		onClose={() => {
			showHelp = false;
			restoreHelpFocus();
		}}
	/>
{/if}
