<script lang="ts">
  import FeedPost from './FeedPost.svelte';
  import ReplaceableEventCard from './ReplaceableEventCard.svelte';
  import ThreadDrawer from './ThreadDrawer.svelte';
  import { nostrClient } from '../../services/nostr/nostr-client.js';
  import { relayManager } from '../../services/nostr/relay-manager.js';
  import { sessionManager } from '../../services/auth/session-manager.js';
  import { onMount } from 'svelte';
  import type { NostrEvent } from '../../types/nostr.js';
  import { getFeedKinds, getReplaceableKinds } from '../../types/kind-lookup.js';

  let posts = $state<NostrEvent[]>([]);
  let replaceableEvents = $state<NostrEvent[]>([]);
  let loading = $state(true);
  let hasMore = $state(true);
  let loadingMore = $state(false);
  let newPostsCount = $state(0);
  let lastPostId = $state<string | null>(null);
  let showOPsOnly = $state(false);
  let showResponsesToMe = $state(false);
  let isLoadingFeed = false; // Guard to prevent concurrent loads
  let scrollTimeout: ReturnType<typeof setTimeout> | null = null;
  let pendingNewPosts = $state<NostrEvent[]>([]); // Store new posts until user clicks button
  let pendingNewReplaceable = $state<NostrEvent[]>([]); // Store new replaceable events
  let loadedParentQuotedEvents = $state<Map<string, NostrEvent>>(new Map()); // Store loaded parent/quoted events separately (doesn't trigger feed re-render)
  
  // Thread drawer state
  let drawerOpen = $state(false);
  let selectedEvent = $state<NostrEvent | null>(null);
  
  // Get current user pubkey
  let currentPubkey = $state<string | null>(sessionManager.getCurrentPubkey());
  
  // Subscribe to session changes
  $effect(() => {
    const unsubscribe = sessionManager.session.subscribe(() => {
      currentPubkey = sessionManager.getCurrentPubkey();
    });
    return unsubscribe;
  });

  onMount(() => {
    nostrClient.initialize().then(() => {
      loadFeed();
    });
    
    // Set up infinite scroll
    window.addEventListener('scroll', handleScroll);
    
    return () => {
      window.removeEventListener('scroll', handleScroll);
      if (scrollTimeout) {
        clearTimeout(scrollTimeout);
        scrollTimeout = null;
      }
    };
  });

  async function loadFeed(reset = true) {
    // Prevent concurrent loads
    if (isLoadingFeed) {
      return;
    }
    
    isLoadingFeed = true;
    
    if (reset) {
      loading = true;
      posts = [];
      hasMore = true;
    } else {
      loadingMore = true;
    }

    try {
      const oldestTimestamp = posts.length > 0 
        ? Math.min(...posts.map(p => p.created_at))
        : undefined;

      const relays = relayManager.getFeedReadRelays();
      const feedKinds = getFeedKinds();
      const replaceableKinds = getReplaceableKinds();

      // Phase 1: Fetch all feed kinds - one request per relay, sent in parallel
      // Update cache in background (10 second timeout), view updates when cache is done
      const feedFilter = feedKinds.length > 0 ? [{
        kinds: feedKinds,
        limit: 100,
        ...(oldestTimestamp ? { until: oldestTimestamp } : {})
      }] : [];

      let allFeedEvents: NostrEvent[] = [];

      if (feedFilter.length > 0) {
        // Debounce onUpdate to prevent rapid-fire updates
        let updateTimeout: ReturnType<typeof setTimeout> | null = null;
        let pendingUpdate: NostrEvent[] | null = null;
        
        // Capture reset value to avoid stale closure
        const isReset = reset;
        
        const debouncedOnUpdate = (updated: NostrEvent[]) => {
          pendingUpdate = updated;
          
          if (updateTimeout) {
            clearTimeout(updateTimeout);
          }
          
          updateTimeout = setTimeout(() => {
            if (!pendingUpdate) return;
            
            const updated = pendingUpdate;
            pendingUpdate = null;
            
            // Don't update the feed automatically - only store new posts for manual update
            // This prevents feed jumping and allows user to control when to refresh
            // Works the same whether drawer is open or closed - events go to pending arrays
            
            const updatedRegularPosts = updated.filter((e: NostrEvent) => e.kind === 1);
            const updatedReplaceable = updated.filter((e: NostrEvent) => 
              replaceableKinds.includes(e.kind) &&
              e.tags.some(t => t[0] === 'd')
            );
            const updatedOtherFeedEvents = updated.filter((e: NostrEvent) => 
              e.kind !== 1 && 
              !replaceableKinds.includes(e.kind) &&
              feedKinds.includes(e.kind)
            );
            
            // NEVER update the feed automatically from onUpdate callback
            // This prevents feed jumping - user must click button to see updates
            // Only store new posts in pending arrays (works for both drawer open and closed)
            if (!isReset) {
              // Store new posts in pending arrays instead of updating feed automatically
              const existingIds = new Set([...posts, ...pendingNewPosts].map(p => p.id));
              const allNewEvents = [...updatedRegularPosts, ...updatedOtherFeedEvents];
              const newPosts = allNewEvents.filter(e => !existingIds.has(e.id));
              
              if (newPosts.length > 0) {
                // Add to pending posts instead of directly to feed
                const existingPendingIds = new Set(pendingNewPosts.map(p => p.id));
                const trulyNewPosts = newPosts.filter(e => !existingPendingIds.has(e.id));
                if (trulyNewPosts.length > 0) {
                  pendingNewPosts = [...pendingNewPosts, ...trulyNewPosts];
                  
                  // Update counter for new posts (only if drawer is closed, to avoid confusion)
                  if (!drawerOpen) {
                    if (lastPostId) {
                      const newCount = trulyNewPosts.filter(e => e.id !== lastPostId).length;
                      if (newCount > 0) {
                        newPostsCount += newCount;
                      }
                    } else {
                      // If no lastPostId, count all new posts
                      newPostsCount += trulyNewPosts.length;
                    }
                  }
                }
              }
              
              // Store new replaceable events in pending array
              const existingReplaceableIds = new Set([...replaceableEvents, ...pendingNewReplaceable].map(e => e.id));
              const newReplaceable = updatedReplaceable.filter(e => !existingReplaceableIds.has(e.id));
              if (newReplaceable.length > 0) {
                pendingNewReplaceable = [...pendingNewReplaceable, ...newReplaceable];
              }
            }
            
            allFeedEvents = updated;
          }, 1000); // Debounce to 1 second to reduce update frequency
        };
        
        // For initial load (reset), don't use onUpdate to prevent incremental updates
        // Wait for the full fetch to complete before displaying anything
        const fetchOptions = reset 
          ? { 
              useCache: true, 
              cacheResults: true, 
              timeout: 10000
              // No onUpdate during initial load to prevent scrolling
            }
          : { 
              useCache: true, 
              cacheResults: true, 
              timeout: 10000,
              onUpdate: debouncedOnUpdate
            };
        
        // Get cached events first for immediate display, then refresh in background
        // For initial load, wait for full fetch without onUpdate to prevent scrolling
        const cachedEvents = await nostrClient.fetchEvents(
          feedFilter,
          relays,
          fetchOptions
        );
        
        // Process cached events
        // Load ALL feed events into posts array (including replies and kind 1111)
        // Filtering happens client-side in getFilteredPosts() based on showOPsOnly checkbox
        const regularPosts = cachedEvents.filter((e: NostrEvent) => e.kind === 1);
        const replaceable = cachedEvents.filter((e: NostrEvent) => 
          replaceableKinds.includes(e.kind) &&
          e.tags.some(t => t[0] === 'd')
        );
        // Include all other feed kinds (including kind 1111 comments)
        const otherFeedEvents = cachedEvents.filter((e: NostrEvent) => 
          e.kind !== 1 && 
          !replaceableKinds.includes(e.kind) &&
          feedKinds.includes(e.kind)
        );

        if (reset) {
          // For initial load, batch all updates at once to prevent scrolling
          // Load ALL events into posts array - filtering happens client-side
          // Only sort if we have posts to prevent unnecessary re-renders
          if (regularPosts.length > 0 || otherFeedEvents.length > 0) {
            posts = sortPosts([...regularPosts, ...otherFeedEvents]);
          }
          replaceableEvents = replaceable.sort((a, b) => b.created_at - a.created_at);
          lastPostId = regularPosts.length > 0 ? regularPosts[0].id : null;
        } else {
          // For infinite scroll (loading more), add new posts directly to feed
          // This is a user-initiated action, so update immediately
          // BUT: Don't update if drawer is open - freeze the feed
          if (!drawerOpen) {
            // Don't re-sort existing posts - just append new ones to prevent jumping
            const existingIds = new Set(posts.map(p => p.id));
            const allNewEvents = [...regularPosts, ...otherFeedEvents];
            const newPosts = allNewEvents.filter(e => !existingIds.has(e.id));
            
            if (newPosts.length > 0) {
              // Sort only the new posts, then append to existing (preserve existing order)
              const sortedNewPosts = sortPosts(newPosts);
              posts = [...posts, ...sortedNewPosts];
            }
            
            const existingReplaceableIds = new Set(replaceableEvents.map(e => e.id));
            const newReplaceable = replaceable.filter(e => !existingReplaceableIds.has(e.id));
            if (newReplaceable.length > 0) {
              // Append new replaceable events without re-sorting existing ones
              replaceableEvents = [...replaceableEvents, ...newReplaceable.sort((a, b) => b.created_at - a.created_at)];
            }
          }
        }
        
        allFeedEvents = cachedEvents;
      }

      // For initial load, wait a moment to ensure all data is processed before showing feed
      // This prevents scrolling issues from incremental updates
      if (reset) {
        // Small delay to ensure DOM is ready and prevent scroll jumping
        await new Promise(resolve => setTimeout(resolve, 100));
      }

      // Background refresh is handled automatically by fetchEvents with useCache: true
      // For initial load, we don't use onUpdate, so background refresh won't cause scrolling

      // Phase 2: Fetch secondary kinds (reactions, zaps) for displayed events
      // One request per relay with all filters, sent in parallel, update cache in background (10s timeout)
      // Only fetch if we're not in a loading state to prevent excessive requests
      // Don't fetch during initial load to prevent scrolling
      if (!isLoadingFeed && !loading && !loadingMore && !reset) {
        const displayedEventIds = [...posts, ...replaceableEvents].map(e => e.id);
        if (displayedEventIds.length > 0) {
          // Fetch reactions (kind 7) and zap receipts (kind 9735) for displayed events
          const secondaryFilter = [{
            kinds: [7, 9735],
            '#e': displayedEventIds.slice(0, 100) // Limit to avoid huge requests
          }];

          // Fetch in background, update cache, view will update automatically via cache
          // Don't use onUpdate here to prevent triggering UI updates that cause jumping
          nostrClient.fetchEvents(
            secondaryFilter,
            relays,
            { 
              useCache: true, 
              cacheResults: true, 
              timeout: 10000 
            }
          ).catch(err => {
            console.error('Error fetching secondary events:', err);
          });
        }

      // Phase 3: Fetch kind 0 profiles, statuses, and activity data for npubs in feed
      // Batch fetch all at once to prevent individual requests from ProfileBadge components
      // This runs on both initial load and background refresh
      const uniquePubkeys = new Set<string>();
      for (const event of [...posts, ...replaceableEvents]) {
        uniquePubkeys.add(event.pubkey);
      }

      if (uniquePubkeys.size > 0) {
        const pubkeysArray = Array.from(uniquePubkeys).slice(0, 100); // Limit to avoid huge requests
        
        // Batch fetch profiles (kind 0)
        const profileFilter = [{
          kinds: [0],
          authors: pubkeysArray
        }];

        // Batch fetch user statuses (kind 30315)
        const statusFilter = [{
          kinds: [30315],
          authors: pubkeysArray,
          '#d': ['general'],
          limit: 1
        } as any];

        // Batch fetch activity data (recent events from each pubkey)
        const activityFilter = [{
          authors: pubkeysArray,
          kinds: [0, 1, 7, 11, 1111],
          limit: 1
        }];

        // Fetch all in parallel, update cache, view will update automatically via cache
        // Don't use onUpdate here to prevent triggering UI updates that cause jumping
        // Run in background to not block initial render
        Promise.all([
          nostrClient.fetchEvents(profileFilter, relays, { 
            useCache: true, 
            cacheResults: true, 
            timeout: 10000 
          }),
          nostrClient.fetchEvents(statusFilter, relays, { 
            useCache: true, 
            cacheResults: true, 
            timeout: 10000 
          }),
          nostrClient.fetchEvents(activityFilter, relays, { 
            useCache: true, 
            cacheResults: true, 
            timeout: 10000 
          })
        ]).catch(err => {
          console.error('Error fetching profiles/statuses/activity:', err);
        });
      }

        // Fetch missing parent events (batch, one request per relay)
        const allEventIds = new Set(posts.map(e => e.id));
        const missingParentIds = new Set<string>();
        
        for (const event of posts) {
          const replyTag = event.tags.find((t) => t[0] === 'e' && t[3] === 'reply');
          const parentId = replyTag?.[1];
          if (parentId && !allEventIds.has(parentId)) {
            missingParentIds.add(parentId);
          }
        }
        
        if (missingParentIds.size > 0) {
          const parentIdsArray = Array.from(missingParentIds).slice(0, 50);
          // Don't use onUpdate here to prevent triggering UI updates that cause jumping
          nostrClient.fetchEvents(
            [{ kinds: [1], ids: parentIdsArray }],
              relays,
            { useCache: true, cacheResults: true, timeout: 10000 }
          ).catch(err => {
            console.error('Error fetching parent events:', err);
          });
        }
      }

      hasMore = allFeedEvents.length >= 100;
    } catch (error) {
      console.error('Error loading feed:', error);
    } finally {
      loading = false;
      loadingMore = false;
      isLoadingFeed = false;
    }
  }

  function handleScroll() {
    // Throttle scroll handler to prevent doom loops
    if (scrollTimeout) {
      return;
    }
    
    scrollTimeout = setTimeout(() => {
      scrollTimeout = null;
    }, 500); // Increase throttle to 500ms to reduce frequency
    
    if (loadingMore || !hasMore || isLoadingFeed) return;
    
    const scrollTop = window.scrollY || document.documentElement.scrollTop;
    const windowHeight = window.innerHeight;
    const documentHeight = document.documentElement.scrollHeight;
    
    // Load more when within 500px of bottom (increased threshold to reduce triggers)
    if (scrollTop + windowHeight >= documentHeight - 500) {
      loadFeed(false);
    }
  }

  function sortPosts(events: NostrEvent[]): NostrEvent[] {
    // Build thread structure
    const eventMap = new Map<string, NostrEvent>();
    const replyMap = new Map<string, string[]>(); // parentId -> childIds[]
    const rootEvents: NostrEvent[] = [];

    // First pass: build maps
    for (const event of events) {
      eventMap.set(event.id, event);
      
      // Check if this is a reply
      const replyTag = event.tags.find((t) => t[0] === 'e' && t[3] === 'reply');
      const parentId = replyTag?.[1];
      
      if (parentId && eventMap.has(parentId)) {
        // This is a reply to an event we have
        if (!replyMap.has(parentId)) {
          replyMap.set(parentId, []);
        }
        replyMap.get(parentId)!.push(event.id);
      } else {
        // This is a root event (not a reply, or parent not loaded)
        rootEvents.push(event);
      }
    }

    // Second pass: recursively collect all events in thread order
    const result: NostrEvent[] = [];
    const processed = new Set<string>();

    function addThread(event: NostrEvent) {
      if (processed.has(event.id)) return;
      processed.add(event.id);
      
      result.push(event);
      
      // Add all replies to this event
      const replies = replyMap.get(event.id) || [];
      const replyEvents = replies
        .map(id => eventMap.get(id))
        .filter((e): e is NostrEvent => e !== undefined)
        .sort((a, b) => a.created_at - b.created_at); // Sort replies chronologically
      
      for (const reply of replyEvents) {
        addThread(reply);
      }
    }

    // Add all root events sorted by newest first
    rootEvents.sort((a, b) => b.created_at - a.created_at);
    for (const root of rootEvents) {
      addThread(root);
    }

    return result;
  }

  function handleShowNewPosts() {
    // Don't update feed while drawer is open - freeze in place
    if (drawerOpen) return;
    
    // Merge pending new posts into the feed
    if (pendingNewPosts.length > 0) {
      // Sort the merged array to maintain proper order
      const merged = [...pendingNewPosts, ...posts];
      posts = sortPosts(merged);
      pendingNewPosts = [];
    }
    
    if (pendingNewReplaceable.length > 0) {
      replaceableEvents = [...pendingNewReplaceable, ...replaceableEvents].sort((a, b) => b.created_at - a.created_at);
      pendingNewReplaceable = [];
    }
    
    // Scroll to top and reset new posts count
    window.scrollTo({ top: 0, behavior: 'smooth' });
    newPostsCount = 0;
    lastPostId = posts.length > 0 ? posts[0].id : null;
  }

  function isReply(post: NostrEvent): boolean {
    // Check if this event references another event (reply, quote, or replaceable event reference)
    // Filter out anything with "e", "a", or "q" tags
    
    // Check for "e" tag (references another event - reply)
    if (post.tags.some((t) => t[0] === 'e' && t[1] !== undefined && t[1] !== post.id)) {
      return true;
    }
    
    // Check for "a" tag (references a replaceable event)
    if (post.tags.some((t) => t[0] === 'a' && t[1] !== undefined)) {
      return true;
    }
    
    // Check for "q" tag (quotes another event)
    if (post.tags.some((t) => t[0] === 'q' && t[1] !== undefined)) {
      return true;
    }
    
    return false;
  }

  /**
   * Filter posts client-side based on showOPsOnly and showResponsesToMe checkboxes.
   * This is purely reactive - no queries are triggered.
   * All events are already loaded into the posts array from cache.
   */
  function getFilteredPosts(): NostrEvent[] {
    let filtered = posts;
    
    // Filter for responses to me (events where current user is in "p" tag)
    if (showResponsesToMe && currentPubkey) {
      filtered = filtered.filter(post => {
        // Check if current user's pubkey is in any "p" tag
        return post.tags.some((t) => t[0] === 'p' && t[1] === currentPubkey);
      });
    }
    
    // Filter for OPs only (original posts, no replies, quotes, or references)
    if (showOPsOnly) {
      filtered = filtered.filter(post => {
        // Filter out all kind 1111 events (comments)
        if (post.kind === 1111) return false;
        // Filter out any event that is a reply, quote, or reference
        if (isReply(post)) return false;
        // Keep everything else (original posts)
        return true;
      });
    }
    
    return filtered;
  }

  function openThreadDrawer(event: NostrEvent, e?: MouseEvent) {
    // Don't open drawer if clicking on interactive elements (but allow the wrapper itself)
    if (e) {
      const target = e.target as HTMLElement;
      const wrapper = target.closest('.post-wrapper');
      
      // If the target itself is a button, link, or has role="button" (but not the wrapper)
      if (target.tagName === 'BUTTON' || target.tagName === 'A' || 
          (target.getAttribute('role') === 'button' && target !== wrapper)) {
        return;
      }
      
      // Check if clicking inside a button or link (but not the wrapper)
      const button = target.closest('button');
      const link = target.closest('a');
      if ((button && button !== wrapper) || (link && link !== wrapper)) {
        return;
      }
    }
    selectedEvent = event;
    drawerOpen = true;
  }

  function closeThreadDrawer() {
    drawerOpen = false;
    selectedEvent = null;
    
    // Events that arrived while drawer was open are already in pendingNewPosts/pendingNewReplaceable
    // Update the counter now that drawer is closed so user sees the notification
    if (pendingNewPosts.length > 0 && lastPostId) {
      const newCount = pendingNewPosts.filter(e => e.id !== lastPostId).length;
      if (newCount > 0) {
        newPostsCount = newCount;
      }
    } else if (pendingNewPosts.length > 0) {
      newPostsCount = pendingNewPosts.length;
    }
  }

  // Use $derived to make this reactive and prevent infinite loops
  let allFeedItems = $derived.by(() => {
    const items: Array<{ id: string; event: NostrEvent; type: 'post' | 'replaceable'; created_at: number }> = [];
    
    // Add filtered posts
    const filteredPosts = getFilteredPosts();
    for (const post of filteredPosts) {
      items.push({
        id: post.id,
        event: post,
        type: 'post',
        created_at: post.created_at
      });
    }
    
    // Add replaceable events
    for (const event of replaceableEvents) {
      items.push({
        id: event.id,
        event: event,
        type: 'replaceable',
        created_at: event.created_at
      });
    }
    
    // Sort by created_at, newest first
    return items.sort((a, b) => b.created_at - a.created_at);
  });
</script>

<div class="Feed-feed">
  <div class="feed-header mb-4">
    <h1 class="text-2xl font-bold mb-4">Feed</h1>
    <div class="feed-controls flex flex-wrap items-center gap-2 sm:gap-4">
      <label class="flex items-center gap-2 cursor-pointer">
        <input
          type="checkbox"
          bind:checked={showOPsOnly}
          class="checkbox"
        />
        <span class="text-sm text-fog-text dark:text-fog-dark-text">Show OPs only</span>
      </label>
      {#if currentPubkey}
        <label class="flex items-center gap-2 cursor-pointer">
          <input
            type="checkbox"
            bind:checked={showResponsesToMe}
            class="checkbox"
          />
          <span class="text-sm text-fog-text dark:text-fog-dark-text">Show responses to me</span>
        </label>
      {/if}
    </div>
  </div>

  {#if loading}
    <p class="text-fog-text-light dark:text-fog-dark-text-light">Loading feed...</p>
  {:else if posts.length === 0 && replaceableEvents.length === 0}
    <p class="text-fog-text-light dark:text-fog-dark-text-light">No posts yet. Be the first to post!</p>
  {:else}
    {#if newPostsCount > 0}
      <div class="new-posts-indicator mb-4">
        <button
          onclick={handleShowNewPosts}
          class="px-4 py-2 bg-fog-accent dark:bg-fog-dark-accent text-white rounded hover:opacity-90 text-sm"
        >
          {newPostsCount} new {newPostsCount === 1 ? 'post' : 'posts'} - Click to view
        </button>
      </div>
    {/if}
    <div class="posts-list">
      {#each allFeedItems as item (item.id)}
        {#if item.type === 'post'}
          {@const parentId = item.event.tags.find((t) => t[0] === 'e' && t[3] === 'reply')?.[1]}
        {@const parentEvent = parentId ? (posts.find(p => p.id === parentId) || loadedParentQuotedEvents.get(parentId)) : undefined}
        {@const quotedId = item.event.tags.find((t) => t[0] === 'q')?.[1]}
        {@const quotedEvent = quotedId ? (posts.find(p => p.id === quotedId) || loadedParentQuotedEvents.get(quotedId)) : undefined}
          <div 
            data-post-id={item.event.id} 
            class="post-wrapper" 
            class:keyboard-selected={false}
            onclick={(e) => openThreadDrawer(item.event, e)}
            role="button"
            tabindex="0"
            onkeydown={(e) => {
              if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                openThreadDrawer(item.event);
              }
            }}
          >
            <FeedPost 
              post={item.event} 
              parentEvent={parentEvent}
              quotedEvent={quotedEvent}
              onParentLoaded={(event) => {
                // Store loaded parent/quoted events in separate map to prevent feed re-rendering
                // NEVER add to main posts array - this causes feed jumping
                if (!loadedParentQuotedEvents.has(event.id)) {
                  loadedParentQuotedEvents.set(event.id, event);
                }
              }}
              onQuotedLoaded={(event) => {
                // Store loaded parent/quoted events in separate map to prevent feed re-rendering
                // NEVER add to main posts array - this causes feed jumping
                if (!loadedParentQuotedEvents.has(event.id)) {
                  loadedParentQuotedEvents.set(event.id, event);
                }
              }}
            />
          </div>
        {:else if item.type === 'replaceable'}
          <div data-event-id={item.event.id} class="post-wrapper" class:keyboard-selected={false}>
            <ReplaceableEventCard event={item.event} />
        </div>
        {/if}
      {/each}
    </div>
    {#if loadingMore}
      <p class="text-center text-fog-text-light dark:text-fog-dark-text-light mt-4">Loading more...</p>
    {/if}
    {#if !hasMore && allFeedItems.length > 0}
      <p class="text-center text-fog-text-light dark:text-fog-dark-text-light mt-4">No more posts</p>
    {/if}
    {#if (showOPsOnly || showResponsesToMe) && getFilteredPosts().length === 0 && posts.length > 0 && replaceableEvents.length === 0}
      <p class="text-center text-fog-text-light dark:text-fog-dark-text-light mt-4">
        {#if showResponsesToMe && showOPsOnly}
          No original posts responding to you found. Try unchecking the filters.
        {:else if showResponsesToMe}
          No responses to you found. Try unchecking "Show responses to me".
        {:else}
          No original posts found. Try unchecking "Show OPs only".
        {/if}
      </p>
    {/if}
  {/if}
</div>

<ThreadDrawer 
  opEvent={selectedEvent}
  isOpen={drawerOpen}
  onClose={closeThreadDrawer}
/>

<style>
  .Feed-feed {
    max-width: var(--content-width);
    margin: 0 auto;
    padding: 1rem;
  }

  .feed-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem;
  }

  .feed-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem 1rem; /* row-gap column-gap for better wrapping */
  }
  
  @media (max-width: 768px) {
    .feed-controls {
      gap: 0.5rem 0.75rem; /* Smaller gaps on mobile */
    }
  }

  .checkbox {
    width: 1rem;
    height: 1rem;
    cursor: pointer;
  }

  .post-wrapper {
    transition: background 0.2s;
    cursor: pointer;
  }

  .post-wrapper:hover {
    background: var(--fog-highlight, #f3f4f6);
    border-radius: 0.25rem;
  }

  :global(.dark) .post-wrapper:hover {
    background: var(--fog-dark-highlight, #374151);
  }

  .post-wrapper.keyboard-selected {
    background: var(--fog-highlight, #f3f4f6);
    border-radius: 0.25rem;
    padding: 0.25rem;
    margin: -0.25rem;
  }

  :global(.dark) .post-wrapper.keyboard-selected {
    background: var(--fog-dark-highlight, #374151);
  }
</style>
