<script lang="ts">
	import { onMount } from 'svelte';
	import '../app.css';
	import { theme, appConfig, activeNote, activeNotePath, installType, platformIsMobile, checkForUpdate, checkForUpdateMobile, isManagedInstall } from '$lib/stores/app';
	import { openFile, openUrl, readNote, getInstallType, isMobilePlatform } from '$lib/api';
	import { get } from 'svelte/store';
	import ResizeHandles from '$lib/components/ResizeHandles.svelte';

	let { children } = $props();

	const isMobile = /android|iphone|ipad|ipod/i.test(navigator.userAgent);

	// Reactively apply theme class to <html> whenever $theme changes
	$effect(() => {
		applyTheme($theme);
	});

	function applyTheme(t: string) {
		const darkThemes = ['dark', 'solarized-dark', 'catppuccin', 'nord', 'tokyo-night', 'github-dark', 'dracula', 'blueberry', 'forest-green', 'gruvbox', 'midnight-tide', 'cherry-blossom', 'synthwave', 'ember', 'moonlit'];
		const namedThemes = ['solarized-light', 'solarized-dark', 'catppuccin', 'nord', 'tokyo-night', 'github-light', 'github-dark', 'dracula', 'blueberry', 'forest-green', 'gruvbox', 'midnight-tide', 'cherry-blossom', 'synthwave', 'ember', 'moonlit'];
		const root = document.documentElement;
		root.classList.remove('dark');
		root.removeAttribute('data-theme');
		if (namedThemes.includes(t)) {
			root.setAttribute('data-theme', t);
			if (darkThemes.includes(t)) root.classList.add('dark');
		} else if (t === 'dark' || (t === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
			root.classList.add('dark');
		}
	}

	function normalizePath(p: string): string {
		const parts = p.split('/');
		const resolved: string[] = [];
		for (const seg of parts) {
			if (seg === '..') resolved.pop();
			else if (seg !== '.') resolved.push(seg);
		}
		return resolved.join('/');
	}

	const isAndroid = /android/i.test(navigator.userAgent);

	function openLocalFile(path: string) {
		if (isAndroid) {
			const bridge = (window as any).Android;
			if (bridge && typeof bridge.openFile === 'function') {
				bridge.openFile(path);
			}
		} else {
			openFile(path).catch((err) => console.error('Failed to open file:', err));
		}
	}

	function resolveAndHandleLink(href: string) {
		if (href.startsWith('http://') || href.startsWith('https://') || href.startsWith('mailto:') || href.startsWith('tel:') || href.startsWith('sms:')) {
			openUrl(href).catch((err) => console.error('Failed to open URL:', err));
		} else if (!href.startsWith('#')) {
			const decoded = decodeURIComponent(href);
			const config = get(appConfig);
			const vaultRoot = config?.active_vault;
			let absPath = decoded;
			if (!decoded.startsWith('/') && vaultRoot) {
				// .helixnotes/ paths are always relative to vault root, not the note's directory
				if (decoded.startsWith('.helixnotes/')) {
					absPath = normalizePath(`${vaultRoot}/${decoded}`);
				} else {
					const notePath = get(activeNotePath);
					if (notePath) {
						const noteDir = notePath.substring(0, notePath.lastIndexOf('/'));
						absPath = normalizePath(`${noteDir}/${decoded}`);
					} else {
						absPath = normalizePath(`${vaultRoot}/${decoded}`);
					}
				}
			}
			// Internal .md note link - navigate within the app
			if (absPath.endsWith('.md')) {
				readNote(absPath).then((content) => {
					activeNote.set({ ...content, content: content.content });
					activeNotePath.set(absPath);
				}).catch((err) => console.error('Failed to navigate to note:', err));
			} else {
				openLocalFile(absPath);
			}
		}
	}

	// Detect install type and check for updates on startup
	onMount(() => {
		// Authoritative platform from the backend (compile-time), overriding the UA guess. (#63)
		isMobilePlatform().then((m) => platformIsMobile.set(m)).catch(() => {});
		if (isMobile) {
			installType.set('android');
			checkForUpdateMobile();
		} else {
			getInstallType().then(t => {
				installType.set(t);
				if (!isManagedInstall(t)) checkForUpdate();
			}).catch(() => {});
		}
	});

	// Intercept all link clicks in capture phase to prevent webview navigation
	onMount(() => {
		function handleLinkClick(e: MouseEvent) {
			const el = e.target as HTMLElement;
			// PDF/attachment embeds: check for data-open-file on target or ancestors
			const fileTarget = el?.closest('[data-open-file]') as HTMLElement | null;
			if (fileTarget) {
				e.preventDefault();
				e.stopPropagation();
				e.stopImmediatePropagation();
				openLocalFile(fileTarget.getAttribute('data-open-file')!);
				return;
			}
			const target = el?.closest('a');
			if (!target) return;
			const href = target.getAttribute('href');
			if (!href) return;
			e.preventDefault();
			e.stopPropagation();
			e.stopImmediatePropagation();
			resolveAndHandleLink(href);
		}

		document.addEventListener('click', handleLinkClick, true);

		// On Android WebView, tapping a link can trigger native navigation before
		// the JS click event fires (causing 404s for relative .md links).
		// We intercept touchend: if it's a tap (not a scroll) on an <a>, we
		// preventDefault to block the native navigation and handle it ourselves.
		let touchStartY = 0;
		function handleTouchStart(e: TouchEvent) {
			touchStartY = e.touches[0]?.clientY ?? 0;
		}
		function handleTouchEnd(e: TouchEvent) {
			const touch = e.changedTouches[0];
			if (!touch) return;
			const endY = touch.clientY;
			// If the finger moved > 10px, it's a scroll, not a tap
			if (Math.abs(endY - touchStartY) > 10) return;
			// Android WebView may report e.target as the editor root for elements
			// inside contenteditable="false" blocks; use elementFromPoint instead
			const el = (document.elementFromPoint(touch.clientX, touch.clientY) ?? e.target) as HTMLElement;
			// PDF/attachment embeds: check for data-open-file on target or ancestors
			const fileTarget = el?.closest('[data-open-file]') as HTMLElement | null;
			if (fileTarget) {
				e.preventDefault();
				openLocalFile(fileTarget.getAttribute('data-open-file')!);
				return;
			}
			const target = el?.closest('a');
			if (!target) return;
			const href = target.getAttribute('href');
			if (!href) return;
			e.preventDefault();
			resolveAndHandleLink(href);
		}

		if (isMobile) {
			document.addEventListener('touchstart', handleTouchStart, { capture: true, passive: true });
			document.addEventListener('touchend', handleTouchEnd, true);
		}

		return () => {
			document.removeEventListener('click', handleLinkClick, true);
			if (isMobile) {
				document.removeEventListener('touchstart', handleTouchStart, true);
				document.removeEventListener('touchend', handleTouchEnd, true);
			}
		};
	});

	// On Windows the native OS drag-drop handler is disabled (dragDropEnabled:false
	// in tauri.windows.conf.json) so HTML5 drag-and-drop works for reordering. With it
	// off, a file dropped outside a drop zone would make the webview navigate to / open
	// that file, replacing the app. Swallow any drag that bubbles up unhandled. Real drop
	// zones (editor, sidebar reordering) call preventDefault in their own handlers first;
	// these bubble-phase listeners only act as a fallback. On macOS/Linux OS file drops are
	// intercepted natively and never surface as HTML5 events, so this is a harmless no-op there.
	onMount(() => {
		function preventNavigate(e: DragEvent) {
			e.preventDefault();
		}
		window.addEventListener('dragover', preventNavigate);
		window.addEventListener('drop', preventNavigate);
		return () => {
			window.removeEventListener('dragover', preventNavigate);
			window.removeEventListener('drop', preventNavigate);
		};
	});
</script>

<svelte:document oncontextmenu={(e) => { if (!isMobile) e.preventDefault(); }} />

<svelte:head>
	<title>HelixNotes</title>
</svelte:head>

{@render children()}

<ResizeHandles />
