<script lang="ts">
  import { nostrClient } from '../../services/nostr/nostr-client.js';
  import { relayManager } from '../../services/nostr/relay-manager.js';
  import FeedPost from './FeedPost.svelte';
  import ThreadDrawer from './ThreadDrawer.svelte';
  import type { NostrEvent } from '../../types/nostr.js';
  import { onMount, tick } from 'svelte';

  let posts = $state<NostrEvent[]>([]);
  let loading = $state(true);
  let loadingMore = $state(false);
  let hasMore = $state(true);
  let oldestTimestamp = $state<number | null>(null);
  
  // Drawer state for viewing parent/quoted events
  let drawerOpen = $state(false);
  let drawerEvent = $state<NostrEvent | null>(null);
  
  // Debounce updates to prevent rapid re-renders
  let updateTimeout: ReturnType<typeof setTimeout> | null = null;
  let pendingUpdates: NostrEvent[] = [];
  
  function openDrawer(event: NostrEvent) {
    drawerEvent = event;
    drawerOpen = true;
  }
  
  function closeDrawer() {
    drawerOpen = false;
    drawerEvent = null;
  }

  let sentinelElement = $state<HTMLElement | null>(null);
  let observer: IntersectionObserver | null = null;

  onMount(async () => {
    await nostrClient.initialize();
    await loadFeed();
  });

  // Listen for custom event from EmbeddedEvent components
  $effect(() => {
    const handleOpenEvent = (e: CustomEvent) => {
      if (e.detail?.event) {
        openDrawer(e.detail.event);
      }
    };
    
    window.addEventListener('openEventInDrawer', handleOpenEvent as EventListener);
    
    return () => {
      window.removeEventListener('openEventInDrawer', handleOpenEvent as EventListener);
    };
  });

  // Cleanup on unmount
  $effect(() => {
    return () => {
      if (observer) {
        observer.disconnect();
      }
      if (updateTimeout) {
        clearTimeout(updateTimeout);
      }
    };
  });

  // Set up observer when sentinel element is available
  $effect(() => {
    if (sentinelElement && !loading && !observer) {
      observer = new IntersectionObserver((entries) => {
        if (entries[0].isIntersecting && hasMore && !loadingMore) {
          loadMore();
        }
      }, { threshold: 0.1 });

      observer.observe(sentinelElement);
      
      return () => {
        if (observer) {
          observer.disconnect();
          observer = null;
        }
      };
    }
  });

  async function loadFeed() {
    loading = true;
    try {
      const config = nostrClient.getConfig();
      const relays = relayManager.getFeedReadRelays();
      
      // Load initial feed - cache first, then background refresh
      const filters = [{ kinds: [1], limit: 20 }];
      const events = await nostrClient.fetchEvents(
        filters,
        relays,
        {
          useCache: true,
          cacheResults: true,
          onUpdate: handleUpdate,
          timeout: 10000
        }
      );

      // Sort by created_at descending
      const sorted = events.sort((a, b) => b.created_at - a.created_at);
      posts = sorted;
      
      if (sorted.length > 0) {
        oldestTimestamp = Math.min(...sorted.map(e => e.created_at));
      }
      
      hasMore = events.length >= 20;
    } catch (error) {
      console.error('Error loading feed:', error);
    } finally {
      loading = false;
    }
  }

  async function loadMore() {
    if (loadingMore || !hasMore) return;
    
    loadingMore = true;
    try {
      const config = nostrClient.getConfig();
      const relays = relayManager.getFeedReadRelays();
      
      const filters = [{ 
        kinds: [1], 
        limit: 20,
        until: oldestTimestamp || undefined
      }];
      
      const events = await nostrClient.fetchEvents(
        filters,
        relays,
        {
          useCache: true,
          cacheResults: true,
          timeout: 10000
        }
      );

      if (events.length === 0) {
        hasMore = false;
        return;
      }

      // Filter out duplicates
      const existingIds = new Set(posts.map(p => p.id));
      const newEvents = events.filter(e => !existingIds.has(e.id));
      
      if (newEvents.length > 0) {
        const sorted = newEvents.sort((a, b) => b.created_at - a.created_at);
        posts = [...posts, ...sorted];
        
        const oldest = Math.min(...newEvents.map(e => e.created_at));
        if (oldest < (oldestTimestamp || Infinity)) {
          oldestTimestamp = oldest;
        }
        hasMore = events.length >= 20;
      } else if (events.length > 0) {
        // All events were duplicates, but we got some results
        // This might mean we've reached the end, or we need to adjust the timestamp
        if (oldestTimestamp) {
          // Try moving the timestamp forward slightly to avoid getting the same results
          oldestTimestamp = oldestTimestamp - 1;
          hasMore = events.length >= 20;
        } else {
          hasMore = false;
        }
      } else {
        // No events returned at all
        hasMore = false;
      }
    } catch (error) {
      console.error('Error loading more:', error);
    } finally {
      loadingMore = false;
    }
  }

  // Debounced update handler to prevent rapid re-renders
  function handleUpdate(updated: NostrEvent[]) {
    console.log(`[FeedPage] handleUpdate called with ${updated.length} events, current posts: ${posts.length}`);
    pendingUpdates.push(...updated);
    
    if (updateTimeout) {
      clearTimeout(updateTimeout);
    }
    
    // Batch updates every 500ms
    updateTimeout = setTimeout(() => {
      if (pendingUpdates.length === 0) return;
      
      const existingIds = new Set(posts.map(p => p.id));
      const newEvents = pendingUpdates.filter(e => !existingIds.has(e.id));
      
      console.log(`[FeedPage] Processing ${newEvents.length} new events, existing: ${posts.length}`);
      
      if (newEvents.length > 0) {
        // Merge and sort
        const merged = [...posts, ...newEvents];
        const sorted = merged.sort((a, b) => b.created_at - a.created_at);
        console.log(`[FeedPage] Setting posts to ${sorted.length} events`);
        posts = sorted;
      }
      
      pendingUpdates = [];
    }, 500);
  }
</script>

<div class="feed-page">
  {#if loading}
    <div class="loading-state">
      <p class="text-fog-text dark:text-fog-dark-text">Loading feed...</p>
    </div>
  {:else if posts.length === 0}
    <div class="empty-state">
      <p class="text-fog-text dark:text-fog-dark-text">No posts found. Check back later!</p>
    </div>
  {:else}
    <div class="feed-posts">
      {#each posts as post (post.id)}
        <FeedPost post={post} onOpenEvent={openDrawer} />
      {/each}
    </div>
    
    {#if drawerOpen && drawerEvent}
      <ThreadDrawer opEvent={drawerEvent} isOpen={drawerOpen} onClose={closeDrawer} />
    {/if}
    
    <div id="feed-sentinel" class="feed-sentinel" bind:this={sentinelElement}>
      {#if loadingMore}
        <p class="text-fog-text-light dark:text-fog-dark-text-light">Loading more...</p>
      {:else if hasMore}
        <p class="text-fog-text-light dark:text-fog-dark-text-light">Scroll for more</p>
      {:else}
        <p class="text-fog-text-light dark:text-fog-dark-text-light">No more posts</p>
      {/if}
    </div>
  {/if}
</div>

<style>
  .feed-page {
    max-width: 100%;
  }

  .loading-state,
  .empty-state {
    padding: 2rem;
    text-align: center;
  }

  .feed-posts {
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }

  .feed-sentinel {
    padding: 2rem;
    text-align: center;
    min-height: 100px;
  }
</style>
