<script lang="ts">
  import Fuse from 'fuse.js'
  import BlogCard from './BlogCard.svelte'
  import { cn } from '@/lib/utils'

  interface BlogEntry {
    id: string
    collection: string
    data: {
      title: string
      description: string
      tags?: string[]
    }
  }

  interface Props {
    searchList: BlogEntry[]
    initialPosts: BlogEntry[]
  }

  let { searchList, initialPosts }: Props = $props()

  let query = $state('')
  let filteredPosts = $state(initialPosts)

  const options = {
    keys: ['data.title', 'data.description', 'data.tags'],
    includeMatches: true,
    minMatchCharLength: 3,
    threshold: 0.3,
    distance: 100,
    sortFn: (a: { score: number }, b: { score: number }) => a.score - b.score,
  }

  const processedSearchList = $derived(
    searchList.map((item) => ({
      ...item,
      data: {
        ...item.data,
        title: String(item.data.title || '').toLowerCase(),
        description: String(item.data.description || '').toLowerCase(),
        tags: Array.isArray(item.data.tags)
          ? item.data.tags.map((tag) => String(tag).toLowerCase())
          : [],
      },
    }))
  )

  const fuse = $derived(new Fuse(processedSearchList, options))

  let debounceTimer: ReturnType<typeof setTimeout>

  function handleSearch(searchQuery: string) {
    clearTimeout(debounceTimer)
    debounceTimer = setTimeout(() => {
      if (searchQuery.length > 2) {
        const results = fuse
          .search(searchQuery.toLowerCase())
          .map((result) => result.item)
        // Map back to original items to preserve original casing
        filteredPosts = results.map(result =>
          searchList.find(item => item.id === result.id) || result
        ) as BlogEntry[]
      } else {
        filteredPosts = initialPosts
      }
    }, 100)
  }

  function handleInputChange(event: Event) {
    const target = event.target as HTMLInputElement
    query = target.value
    handleSearch(query)
  }
</script>

<div>
  <div>
    <label
      for="search"
      class="text-foreground mb-2 block text-sm font-medium dark:text-white"
    >
      Search
    </label>
    <input
      type="text"
      value={query}
      oninput={handleInputChange}
      name="search"
      id="search"
      autocomplete="off"
      autocorrect="off"
      placeholder="Search posts"
      class="border-input file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] dark:bg-neutral-900 dark:text-white"
    />
  </div>

  <hr class="my-6 border-neutral-200 dark:border-neutral-700" />

  <div class={cn('flex items-center justify-between', 'mb-4', !query && 'hidden')}>
    <h2 class="text-lg font-semibold text-neutral-900 dark:text-white">
      {filteredPosts.length} posts found
    </h2>
    <p class="text-sm text-neutral-500 dark:text-neutral-400">
      Search results for: <strong>{query}</strong>
    </p>
  </div>

  <div class="mt-6">
    <ul class="flex flex-col gap-4">
      {#each filteredPosts.slice(0, 50) as post, index (post.id || index)}
        <li>
          <BlogCard entry={post} />
        </li>
      {/each}
    </ul>

    {#if filteredPosts.length === 0}
      <div class="mt-12 text-center">
        <p class="text-neutral-600 dark:text-neutral-400">
          No posts found matching your search criteria.
        </p>
      </div>
    {/if}
  </div>
</div>
