<script lang="ts">
  import ProfileBadge from '../../components/layout/ProfileBadge.svelte';
  import MarkdownRenderer from '../../components/content/MarkdownRenderer.svelte';
  import EventMenu from '../../components/EventMenu.svelte';
  import { nostrClient } from '../../services/nostr/nostr-client.js';
  import { relayManager } from '../../services/nostr/relay-manager.js';
  import { onMount } from 'svelte';
  import type { NostrEvent } from '../../types/nostr.js';
  import { getKindInfo, KIND } from '../../types/kind-lookup.js';
  import { getHighlightsForEvent } from '../../services/nostr/highlight-service.js';
  import { isBookmarked } from '../../services/user-actions.js';
  import { sessionManager } from '../../services/auth/session-manager.js';

  interface Props {
    highlight: NostrEvent; // The highlight event (kind 9802)
    onOpenEvent?: (event: NostrEvent) => void; // Callback to open event in drawer
  }

  let { highlight, onOpenEvent }: Props = $props();

  let sourceEvent = $state<NostrEvent | null>(null);
  let loadingSource = $state(false);
  
  // Check if this event is bookmarked (async, so we use state)
  // Only check if user is logged in
  let bookmarked = $state(false);
  const isLoggedIn = $derived(sessionManager.isLoggedIn());
  
  $effect(() => {
    if (isLoggedIn) {
      isBookmarked(highlight.id).then(b => {
        bookmarked = b;
      });
    } else {
      bookmarked = false;
    }
  });

  // Extract source event ID from e-tag or a-tag
  function getSourceEventId(): string | null {
    const eTag = highlight.tags.find(t => t[0] === 'e' && t[1]);
    if (eTag && eTag[1]) {
      return eTag[1];
    }
    return null;
  }

  // Extract source address from a-tag
  function getSourceAddress(): string | null {
    const aTag = highlight.tags.find(t => t[0] === 'a' && t[1]);
    if (aTag && aTag[1]) {
      return aTag[1];
    }
    return null;
  }

  // Parse a-tag to extract kind, pubkey, and d-tag
  function parseATag(): { kind: number; pubkey: string; dTag: string } | null {
    const aTagValue = getSourceAddress();
    if (!aTagValue) return null;
    
    const parts = aTagValue.split(':');
    if (parts.length !== 3) return null;
    
    const kind = parseInt(parts[0], 10);
    const pubkey = parts[1];
    const dTag = parts[2];
    
    if (isNaN(kind) || !pubkey || !dTag) return null;
    
    return { kind, pubkey, dTag };
  }

  // Extract author pubkey from p-tag
  function getAuthorPubkey(): string | null {
    const pTag = highlight.tags.find(t => t[0] === 'p' && t[1]);
    return pTag?.[1] || null;
  }

  // Get source event URL (handles both e-tag and a-tag)
  function getSourceEventUrl(): string | null {
    if (sourceEvent) {
      return `/event/${sourceEvent.id}`;
    }
    
    const sourceEventId = getSourceEventId();
    if (sourceEventId) {
      return `/event/${sourceEventId}`;
    }
    
    const aTagData = parseATag();
    if (aTagData) {
      // Use the d-tag for the replaceable route
      return `/replaceable/${aTagData.dTag}`;
    }
    
    return null;
  }

  // Extract context tag value
  function getContext(): string | null {
    const contextTag = highlight.tags.find(t => t[0] === 'context' && t[1]);
    return contextTag?.[1] || null;
  }

  // Extract URL from url or r tag
  function getUrl(): string | null {
    const urlTag = highlight.tags.find(t => (t[0] === 'url' || t[0] === 'r') && t[1]);
    return urlTag?.[1] || null;
  }

  // Normalize text for matching (remove extra whitespace, normalize line breaks)
  function normalizeText(text: string): string {
    return text.replace(/\s+/g, ' ').trim();
  }

  // Escape HTML to prevent XSS
  function escapeHtml(text: string): string {
    return text
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#39;');
  }

  // Find content within context and highlight it
  function getHighlightedContext(): string {
    const context = getContext();
    const content = highlight.content?.trim();
    
    // If no context or no content, just return the content
    if (!context || !content) {
      return escapeHtml(content || '');
    }
    
    // Escape the context for safety
    const escapedContext = escapeHtml(context);
    const escapedContent = escapeHtml(content);
    
    // Normalize whitespace for matching (but preserve original for display)
    const normalizeForMatch = (text: string) => text.replace(/\s+/g, ' ').trim();
    const normalizedContext = normalizeForMatch(context);
    const normalizedContent = normalizeForMatch(content);
    
    // Try to find the normalized content within the normalized context
    const normalizedIndex = normalizedContext.toLowerCase().indexOf(normalizedContent.toLowerCase());
    
    if (normalizedIndex === -1) {
      // Content not found in context, just return context
      return escapedContext;
    }
    
    // Find the actual position in the original context
    // We need to map from normalized position back to original position
    // This is approximate - we'll search for the content in the original context
    // using a flexible regex that handles whitespace variations
    
    // Create a regex pattern from the content that allows flexible whitespace
    const contentWords = content.trim().split(/\s+/);
    const flexiblePattern = contentWords.map(word => 
      word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
    ).join('\\s+');
    
    const regex = new RegExp(`(${flexiblePattern})`, 'i');
    const match = context.match(regex);
    
    if (!match) {
      // Fallback: just return context without highlighting
      return escapedContext;
    }
    
    // Found match, highlight it
    const matchIndex = match.index!;
    const matchText = match[1];
    const before = escapeHtml(context.substring(0, matchIndex));
    const highlighted = '<mark class="highlight-text">' + escapeHtml(matchText) + '</mark>';
    const after = escapeHtml(context.substring(matchIndex + matchText.length));
    
    return before + highlighted + after;
  }

  // Check if we should show context with highlight
  let shouldShowContext = $derived(getContext() !== null && highlight.content?.trim() !== '');

  onMount(async () => {
    await loadSourceEvent();
  });

  async function loadSourceEvent() {
    if (loadingSource) return;

    loadingSource = true;
    try {
      const relays = relayManager.getFeedReadRelays();
      
      // Try e-tag first
      const sourceEventId = getSourceEventId();
      if (sourceEventId) {
        const events = await nostrClient.fetchEvents(
          [{ ids: [sourceEventId], limit: 1 }],
          relays,
          { useCache: true, cacheResults: true }
        );
        
        if (events.length > 0) {
          sourceEvent = events[0];
          loadingSource = false;
          return;
        }
      }
      
      // Try a-tag (replaceable event)
      const aTagData = parseATag();
      if (aTagData) {
        const events = await nostrClient.fetchEvents(
          [{ kinds: [aTagData.kind], authors: [aTagData.pubkey], '#d': [aTagData.dTag], limit: 1 }],
          relays,
          { useCache: true, cacheResults: true }
        );
        
        // For replaceable events, get the most recent one
        if (events.length > 0) {
          const sorted = events.sort((a, b) => b.created_at - a.created_at);
          sourceEvent = sorted[0];
        }
      }
    } catch (error) {
      console.error('Error loading source event:', error);
    } finally {
      loadingSource = false;
    }
  }

  function getRelativeTime(): string {
    const now = Math.floor(Date.now() / 1000);
    const diff = now - highlight.created_at;
    const hours = Math.floor(diff / 3600);
    const days = Math.floor(diff / 86400);
    const minutes = Math.floor(diff / 60);

    if (days > 0) return `${days}d ago`;
    if (hours > 0) return `${hours}h ago`;
    if (minutes > 0) return `${minutes}m ago`;
    return 'just now';
  }

  function getClientName(): string | null {
    const clientTag = highlight.tags.find((t) => t[0] === 'client');
    return clientTag?.[1] || null;
  }

  function handleCardClick(e: MouseEvent) {
    // Don't open drawer if clicking on interactive elements
    const target = e.target as HTMLElement;
    if (
      target.tagName === 'BUTTON' ||
      target.tagName === 'A' ||
      target.closest('button') ||
      target.closest('a') ||
      target.closest('.post-actions')
    ) {
      return;
    }
    
    // Open source event if available
    const sourceUrl = getSourceEventUrl();
    if (onOpenEvent && sourceEvent) {
      onOpenEvent(sourceEvent);
    } else if (sourceUrl) {
      window.location.href = sourceUrl;
    }
  }

  function handleCardKeydown(e: KeyboardEvent) {
    if (e.key !== 'Enter' && e.key !== ' ') {
      return;
    }
    
    const target = e.target as HTMLElement;
    if (
      target.tagName === 'BUTTON' ||
      target.tagName === 'A' ||
      target.closest('button') ||
      target.closest('a') ||
      target.closest('.post-actions')
    ) {
      return;
    }
    
    e.preventDefault();
    
    const sourceUrl = getSourceEventUrl();
    if (onOpenEvent && sourceEvent) {
      onOpenEvent(sourceEvent);
    } else if (sourceUrl) {
      window.location.href = sourceUrl;
    }
  }
</script>

<article 
  class="highlight-card" 
  data-highlight-id={highlight.id} 
  id="highlight-{highlight.id}"
  onclick={handleCardClick}
  onkeydown={handleCardKeydown}
  class:cursor-pointer={!!(sourceEvent || parseATag())}
  {...((sourceEvent || parseATag()) ? { role: "button", tabindex: 0 } : {})}
>
  <div class="highlight-header">
    <div class="highlight-meta">
      <ProfileBadge pubkey={highlight.pubkey} />
      {#if getAuthorPubkey() && getAuthorPubkey() !== highlight.pubkey}
        <span class="text-xs text-fog-text-light dark:text-fog-dark-text-light">highlighting</span>
        <ProfileBadge pubkey={getAuthorPubkey()!} />
      {/if}
      <span class="text-xs text-fog-text-light dark:text-fog-dark-text-light flex-shrink-0">{getRelativeTime()}</span>
      {#if getClientName()}
        <span class="text-xs text-fog-text-light dark:text-fog-dark-text-light flex-shrink-0">via {getClientName()}</span>
      {/if}
      <div class="ml-auto flex items-center gap-2">
        {#if isLoggedIn && bookmarked}
          <span class="bookmark-indicator bookmarked" title="Bookmarked">🔖</span>
        {/if}
        <EventMenu event={highlight} showContentActions={true} />
      </div>
    </div>
  </div>

  <div class="highlight-content">
    {#if shouldShowContext}
      {@html getHighlightedContext()}
    {:else}
      <MarkdownRenderer content={highlight.content} event={highlight} />
    {/if}
  </div>

  {#if getSourceEventUrl()}
    <div class="source-event-link">
      <a href={getSourceEventUrl()!} class="source-link" onclick={(e) => e.stopPropagation()}>
        View source event →
      </a>
    </div>
  {:else if loadingSource}
    <div class="source-event-link">
      <span class="text-xs text-fog-text-light dark:text-fog-dark-text-light">Loading source event...</span>
    </div>
  {/if}

  {#if getUrl()}
    <div class="source-event-link">
      <a href={getUrl()} target="_blank" rel="noopener noreferrer" class="source-link" onclick={(e) => e.stopPropagation()}>
        {getUrl()}
      </a>
    </div>
  {/if}

  <div class="kind-badge">
    <span class="kind-number">{getKindInfo(highlight.kind).number}</span>
    <span class="kind-description">{getKindInfo(highlight.kind).description}</span>
  </div>
</article>

<style>
  .highlight-card {
    padding: 1rem;
    margin-bottom: 1rem;
    background: var(--fog-post, #ffffff);
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.25rem;
    position: relative;
  }

  :global(.dark) .highlight-card {
    background: var(--fog-dark-post, #1f2937);
    border-color: var(--fog-dark-border, #374151);
  }

  .highlight-header {
    margin-bottom: 0.75rem;
  }

  .highlight-meta {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
  }

  .highlight-content {
    margin-bottom: 0.75rem;
    padding: 0.75rem;
    background: var(--fog-highlight, #f3f4f6);
    border-radius: 0.25rem;
    border-left: 3px solid #fbbf24;
  }

  :global(.dark) .highlight-content {
    background: var(--fog-dark-highlight, #374151);
    border-left-color: #fbbf24;
  }

  .source-event-link {
    padding-top: 0.5rem;
    border-top: 1px solid var(--fog-border, #e5e7eb);
    margin-top: 0.5rem;
  }

  :global(.dark) .source-event-link {
    border-top-color: var(--fog-dark-border, #374151);
  }

  .source-link {
    color: var(--fog-accent, #64748b);
    text-decoration: none;
    font-size: 0.875rem;
  }

  .source-link:hover {
    text-decoration: underline;
  }

  :global(.dark) .source-link {
    color: var(--fog-dark-accent, #94a3b8);
  }

  .highlight-card.cursor-pointer {
    cursor: pointer;
  }

  .highlight-card.cursor-pointer:hover {
    background: var(--fog-highlight, #f3f4f6);
  }

  :global(.dark) .highlight-card.cursor-pointer:hover {
    background: var(--fog-dark-highlight, #374151);
  }

  .kind-badge {
    position: absolute;
    bottom: 0.5rem;
    right: 0.5rem;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.625rem;
    line-height: 1;
    color: var(--fog-text-light, #9ca3af);
  }

  :global(.dark) .kind-badge {
    color: var(--fog-dark-text-light, #6b7280);
  }

  .kind-number {
    font-weight: 600;
  }

  .kind-description {
    font-size: 0.625rem;
    opacity: 0.8;
  }

  :global(.highlight-content mark.highlight-text) {
    background-color: #fef3c7;
    color: #92400e;
    padding: 0.125rem 0.25rem;
    border-radius: 0.125rem;
    font-weight: 500;
  }

  :global(.dark .highlight-content mark.highlight-text) {
    background-color: #78350f;
    color: #fef3c7;
  }

  .bookmark-indicator {
    display: inline-block;
    font-size: 1rem;
    line-height: 1;
    filter: grayscale(100%);
    transition: filter 0.2s;
  }

  .bookmark-indicator.bookmarked {
    filter: grayscale(0%);
  }
</style>
