<script>
  import { createEventDispatcher, onDestroy, onMount, tick } from 'svelte'
  import { t } from './i18n'
  import { expandKeyboardVariants } from './util/keyboardLayout'

  export let wailsCall = async () => []
  export let typeLabel = (type) => type || ''

  const dispatch = createEventDispatcher()

  let query = ''
  let results = []
  let open = false
  let loading = false
  let selectedIndex = 0
  let inputEl
  let searchTimer

  function clean(value) {
    return String(value || '').trim()
  }

  function resultPath(result) {
    return clean(result.path)
  }

  function resultMeta(result) {
    const parts = []
    const type = typeLabel(result.type)
    const path = resultPath(result)
    if (type) parts.push(type)
    if (path) parts.push(path)
    return parts.join(' · ')
  }

  async function runSearch() {
    const q = clean(query)
    if (q.length < 2) {
      results = []
      open = false
      loading = false
      return
    }
    loading = true
    try {
      // Build query variants: original + keyboard-swapped + lowercased
      const variants = expandKeyboardVariants(q)
      // Deduplicate preserving order
      const seenVariants = new Set()
      const queries = []
      for (const v of variants) {
        if (!seenVariants.has(v)) {
          seenVariants.add(v)
          queries.push(v)
        }
      }
      // Execute all variant queries in parallel, collect results
      const allResults = await Promise.all(
        queries.map(v => wailsCall('Search', v).catch(() => []))
      )
      // Merge and deduplicate by node ID (or type+title for links/actions)
      const merged = new Map()
      // First pass: results from the original query get priority
      for (let qi = 0; qi < allResults.length; qi++) {
        const arr = allResults[qi] || []
        for (const r of arr) {
          const key = r.type + ':' + r.nodeId + ':' + (r.targetId || '') + ':' + r.title
          if (!merged.has(key)) {
            merged.set(key, r)
          }
        }
      }
      results = Array.from(merged.values())
      selectedIndex = 0
      open = results.length > 0
    } catch (e) {
      results = []
      open = false
    } finally {
      loading = false
    }
  }

  function scheduleSearch() {
    clearTimeout(searchTimer)
    searchTimer = setTimeout(runSearch, 180)
  }

  function closeResults() {
    open = false
    selectedIndex = 0
  }

  function clearSearch() {
    query = ''
    results = []
    closeResults()
  }

  function openResult(result) {
    if (!result) return
    dispatch('open', result)
    clearSearch()
    inputEl?.blur()
  }

  function handleInput() {
    scheduleSearch()
  }

  function handleKeydown(e) {
    if (e.key === 'Escape') {
      e.preventDefault()
      clearSearch()
      inputEl?.blur()
      return
    }
    if (!open || results.length === 0) return
    if (e.key === 'ArrowDown') {
      e.preventDefault()
      selectedIndex = Math.min(results.length - 1, selectedIndex + 1)
    } else if (e.key === 'ArrowUp') {
      e.preventDefault()
      selectedIndex = Math.max(0, selectedIndex - 1)
    } else if (e.key === 'Enter') {
      e.preventDefault()
      openResult(results[selectedIndex])
    }
  }

  async function focusSearch() {
    await tick()
    inputEl?.focus()
    inputEl?.select()
  }

  function handleWindowKeydown(e) {
    if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k') {
      e.preventDefault()
      focusSearch()
      return
    }
    if (e.key === '/' && !isEditableTarget(e.target)) {
      e.preventDefault()
      focusSearch()
    }
  }

  function isEditableTarget(target) {
    if (!target || !(target instanceof Element)) return false
    return !!target.closest('input, textarea, select, [contenteditable="true"], [contenteditable=""]')
  }

  onMount(() => {
    window.addEventListener('keydown', handleWindowKeydown)
  })

  onDestroy(() => {
    window.removeEventListener('keydown', handleWindowKeydown)
    clearTimeout(searchTimer)
  })
</script>

<div class="global-search">
  <input
    class="global-search-input"
    bind:this={inputEl}
    bind:value={query}
    type="search"
    placeholder={t('search.placeholder')}
    aria-label={t('search.placeholder')}
    autocomplete="off"
    on:input={handleInput}
    on:focus={() => { if (results.length > 0) open = true }}
    on:keydown={handleKeydown}
    on:blur={() => setTimeout(closeResults, 160)}
  />
  {#if open}
    <div class="global-search-results">
      {#if loading}
        <div class="global-search-empty">{t('common.loading')}</div>
      {:else if results.length === 0}
        <div class="global-search-empty">{t('search.noResults')}</div>
      {:else}
        {#each results as result, index}
          <button
            class="global-search-result"
            class:selected={index === selectedIndex}
            on:mousedown|preventDefault={() => openResult(result)}
          >
            <span class="global-search-title">{result.title}</span>
            {#if resultMeta(result)}
              <span class="global-search-meta">{resultMeta(result)}</span>
            {/if}
            {#if result.snippet}
              <span class="global-search-snippet">{result.snippet}</span>
            {/if}
          </button>
        {/each}
      {/if}
    </div>
  {/if}
</div>

<style>
  .global-search { position: relative; flex: 1 1 360px; min-width: 180px; max-width: 520px; }
  .global-search-input { width: 100%; height: 32px; padding: 0 12px; border: 1px solid #2a2a3c; border-radius: 6px; background: #10101a; color: #e4e4ef; font: inherit; font-size: 13px; }
  .global-search-input:focus { outline: none; border-color: #6366f1; box-shadow: 0 0 0 2px rgba(99,102,241,0.18); }
  .global-search-results { position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 160; max-height: min(360px, calc(100vh - 88px)); overflow-y: auto; background: #1a1a28; border: 1px solid #2a2a3c; border-radius: 8px; box-shadow: 0 14px 36px rgba(0,0,0,0.38); padding: 4px; }
  .global-search-result { display: flex; flex-direction: column; gap: 2px; width: 100%; border: 0; background: transparent; color: #e4e4ef; text-align: left; padding: 8px 10px; border-radius: 6px; cursor: pointer; font: inherit; }
  .global-search-result:hover, .global-search-result.selected { background: #252545; }
  .global-search-title { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .global-search-meta { font-size: 11px; color: #a0a0bc; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .global-search-snippet { font-size: 12px; color: #767690; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .global-search-empty { padding: 10px 12px; color: #8888a0; font-size: 12px; }
</style>
