import type { Component, Setter } from 'solid-js'
import type { ExtraSearchResult } from '../../data/search'
import type { LocNav } from '../../ui/utils-ui'
import { A } from '@solidjs/router'
import { Logger } from 'besonders-logger'
import { startCase } from 'lodash-es'
import { createEffect, For, Match, on, onCleanup, Show, Switch } from 'solid-js'
import { Dynamic } from 'solid-js/web'
import { useSearchContext } from '../../data/search'
import { useFocus } from '../../ui/reactive'
import { focusViewOnBlock, makeNote3Url, replaceUriParts, useLocationNavigate } from '../../ui/utils-ui'
import { Iconify, ShortID } from '../mini-components'

const { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO) // eslint-disable-line unused-imports/no-unused-vars

export const HeaderSearchBar: Component<{
	open: boolean
	setOpen: Setter<boolean>
	// onEnterPressed: () => void
	firstResult: any
}> = (props) => {
	// let setOpenInternal
	// if (open === undefined) {
	// 	;[open, setOpenInternal] = createSignal(false)
	// 	const setOpenOriginal = setOpen
	// 	setOpen = (state: boolean) => {
	// 		setOpenInternal(state)
	// 		setOpen(state)
	// 	}
	// }
	const { locnav, location, navigate } = useLocationNavigate()
	const [search, setSearch] = useSearchContext()
	const focus = useFocus()

	createEffect(on(() => search(), (search) => {
		if (search && !props.open) {
			props.setOpen(true)
			inputRef?.focus()
		}
	}))

	// Auto-navigate for search results (except block-not-found which is feedback-only)
	createEffect(on(() => props.firstResult, (firstResult) => {
		if (!firstResult || !search()) return
		if (firstResult.type !== 'block-not-found') {
			close()
			openExtraSearchResult(firstResult, { location, navigate })
			setSearch(null)
		}
	}))

	const close = () => {
		props.setOpen(false)
	}

	// Global keylistener
	function onEnterPressed() {
		const firstResult = props.firstResult
		if (firstResult) {
			close()
			openExtraSearchResult(firstResult, { location, navigate })
			// setSearch(null)
		}
	}
	const handleKeyDown = (event: KeyboardEvent) => {
		DEBUG(`[handleKeyDown]`, event)
		if (event.ctrlKey && event.code === 'Slash') { // HACK: code=='Slash' so that Shift+/ will still match...
			if (props.open) {
				if (event.shiftKey) {
					// Ctrl+Shift+/ when search is open
					if (location.pathname.startsWith('/block/')) {
						// Navigate to global view while preserving search params
						navigate(replaceUriParts(location, { pathname: '/timeline' }))
					} else {
						// Already in global view, close search
						close()
					}
				} else {
					// Ctrl+/ when search is open: close search
					close()
				}
			} else {
				if (location.pathname.startsWith('settings')) {
					focusViewOnBlock({ id: null }, locnav)
				} else if (event.shiftKey && focus()) {
					focusViewOnBlock({ id: null }, locnav)
				}
				props.setOpen(true)
				inputRef?.focus() // TODO: when header button click?
			}
		} else if (props.open) {
			if (event.key === 'Escape') {
				close()
			}
		}
	}
	document.addEventListener('keydown', handleKeyDown, true)
	onCleanup(() => {
		document.removeEventListener('keydown', handleKeyDown, true)
	})

	let inputRef // , resultsContainerRef
	// const handleArrowKeys = (event: KeyboardEvent) => {
	// 	DEBUG(`[handleArrowKeys]`, event)
	// 	if (['ArrowUp', 'ArrowDown'].includes(event.key)) {
	// 		let target = event.target as HTMLElement
	// 		if (target.getRootNode() instanceof ShadowRoot) {
	// 			// Get the host element of the shadow root
	// 			target = (target.getRootNode() as ShadowRoot).host as HTMLElement
	// 		}
	// 		const current = target.closest('sl-input, div[data-block-id]') as HTMLElement
	// 		DEBUG(`[handleArrowKeys] current`, current)
	// 		if (!current) return
	// 		let newTarget = (event.key === 'ArrowUp' ? current.previousElementSibling : current.nextElementSibling) as HTMLElement
	// 		if (!newTarget && current.parentElement == resultsContainerRef && event.key === 'ArrowUp') {
	// 			newTarget = inputRef
	// 		}
	// 		if (newTarget == resultsContainerRef) {
	// 			newTarget = newTarget.firstElementChild as HTMLElement
	// 		}
	// 		DEBUG(`[handleArrowKeys] newTarget`, newTarget)
	// 		if (newTarget) {
	// 			newTarget.focus()
	// 			event.preventDefault()
	// 		}
	// 	}
	// }

	// const currentDS = useCurrentThread()
	// const [results] = createResource(() => ({ search: search(), currentDS }), performSearch)

	// createEffect(() => {
	// 	if (open()) {
	// 		DEBUG(`Focussing search field:`, inputRef)
	// 		inputRef?.focus()
	// 	}
	// })
	// const openResult = (result: Result) => {
	// 	close()
	// 	if (result.type === 'block') zoomToBlock({ id: result.id }, location, navigate)
	// 	else if (result.type === 'preview') navigate(makeNote3Url({ pub: result.id, block: result.focus, previewPub: true, relative: true }))
	// 	else navigate(`/settings/${result.type}s/${result.id}`)
	// }

	return (
		<sl-input
			class='header-search-input'
			w-full
			ref={inputRef}
			placeholder='Search'
			value={search() || ''}
			onInput={e => setSearch(e.target.value)}
			onsl-clear={close}
			border='2 solid white'
			clearable={true}
			type='search'
			autocomplete='nope' // FIXME https://stackoverflow.com/a/30873633/1633985 & https://stackoverflow.com/questions/25823448/ng-form-and-autocomplete-off/39689037#39689037
			rounded
			tabindex='0'
			onKeyDown={({ key }) => key === 'Enter' && onEnterPressed()}
		>
			<Iconify slot='clear-icon' name='x-bold' size={6} color='white' />
		</sl-input>
	)
}

// export const OverlaySearchBar: Component<{
// 	open: Accessor<boolean>
// 	setOpen: Setter<boolean>
// }> = (
// 	{ open, setOpen },
// ) => {
// 	const location = useLocation()
// 	const navigate = useNavigate()
// 	// let setOpenInternal
// 	// if (open === undefined) {
// 	// 	;[open, setOpenInternal] = createSignal(false)
// 	// 	const setOpenOriginal = setOpen
// 	// 	setOpen = (state: boolean) => {
// 	// 		setOpenInternal(state)
// 	// 		setOpen(state)
// 	// 	}
// 	// }
// 	const [search, setSearch] = useSearch()

// 	const close = () => {
// 		setOpen(false)
// 		setTimeout(() => setSearch(''), 300) // prevent glitch during fadeout
// 	}

// 	const handleKeyDown = (event: KeyboardEvent) => {
// 		DEBUG(`[handleKeyDown]`, event)
// 		if (event.ctrlKey && event.key === '/') {
// 			if (open()) close()
// 			else setOpen(true)
// 		} else if (open()) {
// 			if (event.key === 'Escape') {
// 				close()
// 			}
// 		}
// 	}
// 	document.addEventListener('keydown', handleKeyDown, true)
// 	onCleanup(() => {
// 		document.removeEventListener('keydown', handleKeyDown, true)
// 	})

// 	const handleClickToClose = (event: MouseEvent) => {
// 		DEBUG(`[handleClickToClose]`, event)
// 		// FIXME: if I drag from the input to outside, this is triggered
// 		if ((event.target as HTMLElement).dataset.clickaway !== undefined) {
// 			close()
// 		}
// 	}
// 	let inputRef, resultsContainerRef
// 	const handleArrowKeys = (event: KeyboardEvent) => {
// 		DEBUG(`[handleArrowKeys]`, event)
// 		if (['ArrowUp', 'ArrowDown'].includes(event.key)) {
// 			let target = event.target as HTMLElement
// 			if (target.getRootNode() instanceof ShadowRoot) {
// 				// Get the host element of the shadow root
// 				target = (target.getRootNode() as ShadowRoot).host as HTMLElement
// 			}
// 			const current = target.closest('sl-input, div[data-block-id]') as HTMLElement
// 			DEBUG(`[handleArrowKeys] current`, current)
// 			if (!current) return
// 			let newTarget = (event.key === 'ArrowUp' ? current.previousElementSibling : current.nextElementSibling) as HTMLElement
// 			if (!newTarget && current.parentElement == resultsContainerRef && event.key === 'ArrowUp') {
// 				newTarget = inputRef
// 			}
// 			if (newTarget == resultsContainerRef) {
// 				newTarget = newTarget.firstElementChild as HTMLElement
// 			}
// 			DEBUG(`[handleArrowKeys] newTarget`, newTarget)
// 			if (newTarget) {
// 				newTarget.focus()
// 				event.preventDefault()
// 			}
// 		}
// 	}

// 	const currentDS = useCurrentDS()
// 	const [results] = createResource(() => ({ search: search(), currentDS }), useExtraSearchResults)

// 	createEffect(() => {
// 		if (open()) {
// 			DEBUG(`Focussing search field:`, inputRef)
// 			inputRef?.focus()
// 		}
// 	})

// 	// const openResult = (result: ExtraSearchResult) => {
// 	// 	close()
// 	// 	if (result.type === 'block') zoomToBlock({ id: result.id }, location, navigate)
// 	// 	else if (result.type === 'preview') navigate(makeNote3Url({ pub: result.id, block: result.focus, previewPub: true, relative: true }))
// 	// 	else navigate(`/settings/${result.type}s/${result.id}`)
// 	// }

// 	return (
// 		// <Show when={open()}>
// 		<div
// 			class={open() ? 'opacity-100' : 'opacity-0 pointer-events-none'}
// 			transition-300
// 			transition-property-opacity
// 			absolute
// 			flex='~ col items-center'
// 			bg='black opacity-60'
// 			inset-0
// 			h-100vh
// 			z-300
// 			box-border
// 			p-2
// 			data-clickaway
// 			onClick={handleClickToClose}
// 			backdrop='filter blur-3'
// 		>
// 			<div
// 				flex='shrink-1 ~ col items-stretch justify-start'
// 				h-full
// 				w-full
// 				max-w-4xl
// 				color-white
// 				gap-4
// 				data-clickaway
// 				onKeyDown={handleArrowKeys}
// 			>
// 				<sl-input
// 					ref={inputRef}
// 					placeholder='Search'
// 					value={search()}
// 					onInput={e => setSearch(e.target.value)}
// 					border='2 solid white'
// 					rounded
// 					tabindex='0'
// 					onKeyDown={({ key }) => key === 'Enter' && openResult(results()?.[0])}
// 				/>
// 				<div ref={resultsContainerRef} flex='shrink-1 ~ col items-stretch justify-start' w-full gap-2 overflow-y-auto>
// 					<Suspense fallback={<Spinner size='2rem' />}>
// 					</Suspense>
// 				</div>
// 			</div>
// 		</div>
// 		// </Show>
// 	)
// }

export const ExtraSearchResults: Component<{
	results: readonly ExtraSearchResult[]
	close: () => void
}> = (props) => {
	VERBOSE(`<ExtraSearchResults>.created`, props)
	const { locnav, location, navigate } = useLocationNavigate()

	const openResult = (result: ExtraSearchResult) => {
		props.close()
		openExtraSearchResult(result, locnav)
	}

	return (
		<Show when={props.results.length}>
			<div w-full flex='~ col items-stretch'>
				{/* <pre>{JSON.stringify(props.results,undefined,4)}</pre> */}
				<For each={props.results}>
					{(result, _index) => (
						<Dynamic
							component={result.link ? A : 'div'}
							href={result.link ?? null}
							data-block-id={result.type === 'block' ? result.id : undefined}
							onKeyDown={({ key }) => key === 'Enter' && openResult(result)}
							onclick={() => openResult(result)}
							class='block cursor-pointer rounded p-2 text-xs'
							tabindex='0'
							bg='gray-900 hover:bluegray-700 focus:bluegray-800'
							flex='1'
							border='1 solid white focus:blue'
						>
							{/* <pre>{JSON.stringify(applog,undefined,4)}</pre> */}
							<Switch>
								<Match when={result.type === 'block'}>
									<strong>Block:</strong>
									&nbsp;
									{/* @ts-expect-error TS inference doesn't fully work in solid */}
									{contentVlToPlaintext(result.content)}
									{/* TODO proper block rendering postponed because of search re-think ideas */}
								</Match>
								<Match when={result.type === 'block-not-found'}>
									<strong>Block:</strong>
									&nbsp;
									<ShortID id={result.id} />
									<br />
									<span style={{ 'color': '#ff9800', 'font-size': '0.85em' }}>⚠ {result.message}</span>
								</Match>
								<Match when={true}>
									{startCase(result.type)}
									:
									<ShortID id={result.id} />
								</Match>
							</Switch>
						</Dynamic>
					)}
				</For>
			</div>
		</Show>
	)
}
export function openExtraSearchResult(result: ExtraSearchResult, { location, navigate }: LocNav) {
	if (result.type === 'block') {
		focusViewOnBlock({ id: result.id }, { location, navigate })
	} else if (result.type === 'preview') {
		navigate(makeNote3Url({ pub: result.id, block: result.focus, previewPub: true, relative: true }))
	} else if (result.type === 'block-not-found') {
		// Block not found - don't navigate, just close search

	} else {
		navigate(`/settings/${result.type}s/${result.id}`)
	}
}
