<script lang="ts">
  import { nostrClient } from '../../services/nostr/nostr-client.js';
  import Icon from '../ui/Icon.svelte';
  import { relayManager } from '../../services/nostr/relay-manager.js';
  import { getEvent, getEventsByKind, getEventsByPubkey } from '../../services/cache/event-cache.js';
  import { cacheEvent } from '../../services/cache/event-cache.js';
  import { nip19 } from 'nostr-tools';
  import { goto } from '$app/navigation';
  import { KIND } from '../../types/kind-lookup.js';
  import type { NostrEvent } from '../../types/nostr.js';

  let searchQuery = $state('');
  let searching = $state(false);
  let searchResults = $state<Array<{ event: NostrEvent; matchType: string }>>([]);
  let showResults = $state(false);
  let searchInput: HTMLInputElement | null = $state(null);
  let searchTimeout: ReturnType<typeof setTimeout> | null = null;

  // Decode bech32 identifiers
  function decodeIdentifier(input: string): { type: 'event' | 'profile' | null; id: string | null; pubkey: string | null } {
    const trimmed = input.trim();
    
    // Check if it's a bech32 encoded format first (before hex)
    if (/^(note|nevent|naddr|npub|nprofile)1[a-z0-9]+$/i.test(trimmed)) {
      try {
        const decoded = nip19.decode(trimmed);
        
        if (decoded.type === 'note') {
          return { type: 'event', id: String(decoded.data), pubkey: null };
        } else if (decoded.type === 'nevent') {
          if (decoded.data && typeof decoded.data === 'object' && 'id' in decoded.data) {
            return { type: 'event', id: String(decoded.data.id), pubkey: null };
          }
        } else if (decoded.type === 'naddr') {
          // naddr requires fetching by kind+pubkey+d, but we can try to find it
          // For now, return null - we'll handle it in search
          return { type: null, id: null, pubkey: null };
        } else if (decoded.type === 'npub') {
          return { type: 'profile', id: null, pubkey: String(decoded.data) };
        } else if (decoded.type === 'nprofile') {
          if (decoded.data && typeof decoded.data === 'object' && 'pubkey' in decoded.data) {
            return { type: 'profile', id: null, pubkey: String(decoded.data.pubkey) };
          }
        }
      } catch (error) {
        console.error('Error decoding bech32:', error);
      }
    }
    
    // Check if it's a hex identifier (64 hex characters)
    // We can't distinguish between event IDs and pubkeys by format alone,
    // so we'll try event ID first, then fall back to pubkey if event not found
    if (/^[0-9a-f]{64}$/i.test(trimmed)) {
      // Default to event ID - if not found, we can try as pubkey in performSearch
      return { type: 'event', id: trimmed.toLowerCase(), pubkey: trimmed.toLowerCase() };
    }
    
    return { type: null, id: null, pubkey: null };
  }

  async function performSearch() {
    if (!searchQuery.trim()) {
      searchResults = [];
      showResults = false;
      return;
    }

    // Ensure nostrClient is initialized
    await nostrClient.initialize();

    searching = true;
    searchResults = [];
    showResults = true;

    try {
      const query = searchQuery.trim();
      
      // First, try to decode as specific identifier
      const decoded = decodeIdentifier(query);
      
      if (decoded.type === 'event' && decoded.id) {
        // Search for specific event ID
        let event: NostrEvent | undefined = await getEvent(decoded.id);
        
        if (!event) {
          // Not in cache, fetch from relays
          const relays = relayManager.getFeedReadRelays();
          const events = await nostrClient.fetchEvents(
            [{ ids: [decoded.id] }],
            relays,
            { useCache: false, cacheResults: true }
          );
          
          if (events.length > 0) {
            event = events[0];
            await cacheEvent(event);
          }
        }
        
        if (event) {
          searchResults = [{ event, matchType: 'Event ID' }];
        } else if (decoded.pubkey) {
          // Event not found, but we have a pubkey - try as profile
          handleProfileClick(decoded.pubkey);
          return;
        }
      } else if (decoded.type === 'profile' && decoded.pubkey) {
        // Search for profile - navigate directly to profile page
        handleProfileClick(decoded.pubkey);
        return;
      } else {
        // Text search in cached events
        const allCached: NostrEvent[] = [];
        
        // Search kind 1 events
        const kind1Events = await getEventsByKind(KIND.SHORT_TEXT_NOTE, 100);
        allCached.push(...kind1Events);
        
        // Search kind 11 events
        const kind11Events = await getEventsByKind(KIND.DISCUSSION_THREAD, 100);
        allCached.push(...kind11Events);
        
        // Filter by search query - search title, summary, and content
        const queryLower = query.toLowerCase();
        const matches = allCached.filter(event => {
          // Search content
          const contentMatch = event.content.toLowerCase().includes(queryLower);
          
          // Search title tag
          const titleTag = event.tags.find(t => t[0] === 'title');
          const titleMatch = titleTag?.[1]?.toLowerCase().includes(queryLower) || false;
          
          // Search summary tag
          const summaryTag = event.tags.find(t => t[0] === 'summary');
          const summaryMatch = summaryTag?.[1]?.toLowerCase().includes(queryLower) || false;
          
          return contentMatch || titleMatch || summaryMatch;
        });
        
        // Sort by relevance (exact matches first, then by created_at)
        const sorted = matches.sort((a, b) => {
          const aExact = a.content.toLowerCase() === queryLower;
          const bExact = b.content.toLowerCase() === queryLower;
          if (aExact && !bExact) return -1;
          if (!aExact && bExact) return 1;
          return b.created_at - a.created_at;
        });
        
        searchResults = sorted.slice(0, 20).map(e => ({ event: e, matchType: 'Content' }));
      }
    } catch (error) {
      console.error('Search error:', error);
    } finally {
      searching = false;
    }
  }

  function handleSearchInput(e: Event) {
    const target = e.target as HTMLInputElement;
    const newValue = target.value;
    searchQuery = newValue;
    
    // Clear existing timeout
    if (searchTimeout) {
      clearTimeout(searchTimeout);
    }
    
    // Debounce search - wait 300ms after user stops typing
    if (newValue.trim()) {
      // Show loading indicator immediately
      searching = true;
      searchTimeout = setTimeout(() => {
        performSearch();
      }, 300);
    } else {
      searchResults = [];
      showResults = false;
      searching = false;
    }
  }

  function handleKeyDown(e: KeyboardEvent) {
    if (e.key === 'Enter') {
      performSearch();
    } else if (e.key === 'Escape') {
      showResults = false;
      searchQuery = '';
    }
  }

  function handleResultClick(event: NostrEvent) {
    showResults = false;
    searchQuery = '';
    goto(`/event/${event.id}`);
  }

  function handleProfileClick(pubkey: string) {
    showResults = false;
    searchQuery = '';
    goto(`/profile/${pubkey}`);
  }

  // Close results when clicking outside
  $effect(() => {
    if (showResults) {
      const handleClickOutside = (e: MouseEvent) => {
        const target = e.target as HTMLElement;
        if (!target.closest('.search-box-container')) {
          showResults = false;
          searchQuery = '';
        }
      };
      
      // Use capture phase to catch clicks before they bubble
      document.addEventListener('click', handleClickOutside, true);
      return () => {
        document.removeEventListener('click', handleClickOutside, true);
      };
    }
  });

  // Cleanup timeout on unmount
  $effect(() => {
    return () => {
      if (searchTimeout) {
        clearTimeout(searchTimeout);
      }
    };
  });
</script>

<div class="search-box-container">
  <div class="search-input-wrapper">
    <Icon name="search" size={18} class="search-icon" />
    <input
      bind:this={searchInput}
      type="text"
      placeholder="Search events, profiles, or enter event ID (hex, note, nevent, npub, nprofile)..."
      value={searchQuery}
      oninput={handleSearchInput}
      onkeydown={handleKeyDown}
      class="search-input"
      aria-label="Search"
    />
    {#if searching}
      <span class="search-loading">⟳</span>
    {/if}
  </div>
  
  {#if showResults && searchResults.length > 0}
    <div class="search-results">
      {#each searchResults as { event, matchType }}
        <button
          onclick={() => {
            if (event.kind === KIND.METADATA) {
              handleProfileClick(event.pubkey);
            } else {
              handleResultClick(event);
            }
          }}
          class="search-result-item"
        >
          <div class="search-result-header">
            <span class="search-result-type">{matchType}</span>
            <span class="search-result-id">{event.id.substring(0, 16)}...</span>
          </div>
          <div class="search-result-content">
            {event.content.substring(0, 100)}{event.content.length > 100 ? '...' : ''}
          </div>
          <div class="search-result-meta">
            Kind {event.kind} • {new Date(event.created_at * 1000).toLocaleDateString()}
          </div>
        </button>
      {/each}
    </div>
  {:else if showResults && !searching && searchQuery.trim()}
    <div class="search-results">
      <div class="search-no-results">No results found</div>
    </div>
  {/if}
</div>

<style>
  .search-box-container {
    position: relative;
    width: 100%;
    max-width: 600px;
  }

  .search-input-wrapper {
    position: relative;
    display: flex;
    align-items: center;
  }
  
  .search-icon {
    position: absolute;
    left: 0.75rem;
    color: var(--fog-text-light, #9ca3af);
    pointer-events: none;
    z-index: 1;
  }
  
  :global(.dark) .search-icon {
    color: var(--fog-dark-text-light, #6b7280);
  }

  .search-input {
    width: 100%;
    padding: 0.75rem 1rem 0.75rem 2.5rem;
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.375rem;
    background: var(--fog-post, #ffffff);
    color: var(--fog-text, #1f2937);
    font-size: 0.875rem;
    transition: all 0.2s;
  }

  .search-input:focus {
    outline: none;
    border-color: var(--fog-accent, #64748b);
    box-shadow: 0 0 0 3px rgba(100, 116, 139, 0.1);
  }

  :global(.dark) .search-input {
    background: var(--fog-dark-post, #1f2937);
    border-color: var(--fog-dark-border, #374151);
    color: var(--fog-dark-text, #f9fafb);
  }

  :global(.dark) .search-input:focus {
    border-color: var(--fog-dark-accent, #94a3b8);
    box-shadow: 0 0 0 3px rgba(148, 163, 184, 0.1);
  }

  .search-loading {
    position: absolute;
    right: 1rem;
    color: var(--fog-text-light, #9ca3af);
    animation: spin 1s linear infinite;
  }

  @keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
  }

  .search-results {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    margin-top: 0.25rem;
    background: var(--fog-post, #ffffff);
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.375rem;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    max-height: 400px;
    overflow-y: auto;
    z-index: 1000;
  }

  :global(.dark) .search-results {
    background: var(--fog-dark-post, #1f2937);
    border-color: var(--fog-dark-border, #374151);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  }

  .search-result-item {
    width: 100%;
    padding: 0.75rem;
    border: none;
    background: transparent;
    text-align: left;
    cursor: pointer;
    transition: background 0.2s;
    border-bottom: 1px solid var(--fog-border, #e5e7eb);
  }

  .search-result-item:last-child {
    border-bottom: none;
  }

  .search-result-item:hover {
    background: var(--fog-highlight, #f3f4f6);
  }

  :global(.dark) .search-result-item {
    border-bottom-color: var(--fog-dark-border, #374151);
  }

  :global(.dark) .search-result-item:hover {
    background: var(--fog-dark-highlight, #374151);
  }

  .search-result-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.25rem;
  }

  .search-result-type {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--fog-accent, #64748b);
    text-transform: uppercase;
  }

  :global(.dark) .search-result-type {
    color: var(--fog-dark-accent, #94a3b8);
  }

  .search-result-id {
    font-size: 0.75rem;
    font-family: monospace;
    color: var(--fog-text-light, #9ca3af);
  }

  :global(.dark) .search-result-id {
    color: var(--fog-dark-text-light, #6b7280);
  }

  .search-result-content {
    font-size: 0.875rem;
    color: var(--fog-text, #1f2937);
    margin-bottom: 0.25rem;
    line-height: 1.4;
  }

  :global(.dark) .search-result-content {
    color: var(--fog-dark-text, #f9fafb);
  }

  .search-result-meta {
    font-size: 0.75rem;
    color: var(--fog-text-light, #9ca3af);
  }

  :global(.dark) .search-result-meta {
    color: var(--fog-dark-text-light, #6b7280);
  }

  .search-no-results {
    padding: 1rem;
    text-align: center;
    color: var(--fog-text-light, #9ca3af);
    font-size: 0.875rem;
  }

  :global(.dark) .search-no-results {
    color: var(--fog-dark-text-light, #6b7280);
  }
</style>
