<script lang="ts">
  import { nostrClient } from '../../services/nostr/nostr-client.js';
  import { onMount } from 'svelte';
  import ThreadCard from './ThreadCard.svelte';
  import type { NostrEvent } from '../../types/nostr.js';

  let threads = $state<NostrEvent[]>([]);
  let loading = $state(true);
  let sortBy = $state<'newest' | 'active' | 'upvoted'>('newest');
  let showOlder = $state(false);
  let selectedTopic = $state<string | null | undefined>(null); // null = All, undefined = General, string = specific topic

  $effect(() => {
    loadThreads();
  });

  async function loadThreads() {
    loading = true;
    try {
      const config = nostrClient.getConfig();
      const since = showOlder
        ? undefined
        : Math.floor(Date.now() / 1000) - config.threadTimeoutDays * 86400;

      // Fetch with cache-first, background refresh
      // onUpdate callback will refresh the UI when new data arrives
      const events = await nostrClient.fetchEvents(
        [{ kinds: [11], since, limit: 50 }],
        [...config.defaultRelays],
        {
          useCache: true,
          cacheResults: true,
          onUpdate: async (updatedEvents) => {
            // Update threads when fresh data arrives from relays
            threads = await sortThreads(updatedEvents);
          }
        }
      );

      // Set initial cached data immediately
      if (sortBy === 'newest') {
        threads = sortThreadsSync(events);
      } else {
        threads = await sortThreads(events);
      }
    } catch (error) {
      console.error('Error loading threads:', error);
      threads = []; // Set empty array on error to prevent undefined issues
    } finally {
      loading = false;
    }
  }

  function sortThreadsSync(events: NostrEvent[]): NostrEvent[] {
    // Synchronous version for 'newest' sorting
    return [...events].sort((a, b) => b.created_at - a.created_at);
  }

  async function sortThreads(events: NostrEvent[]): Promise<NostrEvent[]> {
    switch (sortBy) {
      case 'newest':
        return sortThreadsSync(events);
      case 'active':
        // Sort by most recent comment activity
        const activeSorted = await Promise.all(
          events.map(async (event) => {
            const config = nostrClient.getConfig();
            const comments = await nostrClient.fetchEvents(
              [{ kinds: [1111], '#E': [event.id], '#K': ['11'], limit: 1 }],
              [...config.defaultRelays],
              { useCache: true }
            );
            const lastCommentTime = comments.length > 0 
              ? comments.sort((a, b) => b.created_at - a.created_at)[0].created_at
              : event.created_at;
            return { event, lastActivity: lastCommentTime };
          })
        );
        return activeSorted
          .sort((a, b) => b.lastActivity - a.lastActivity)
          .map(({ event }) => event);
      case 'upvoted':
        // Sort by upvote count
        const upvotedSorted = await Promise.all(
          events.map(async (event) => {
            const config = nostrClient.getConfig();
            const reactions = await nostrClient.fetchEvents(
              [{ kinds: [7], '#e': [event.id] }],
              [...config.defaultRelays],
              { useCache: true }
            );
            const upvoteCount = reactions.filter(
              (r) => r.content.trim() === '+' || r.content.trim() === '⬆️' || r.content.trim() === '↑'
            ).length;
            return { event, upvotes: upvoteCount };
          })
        );
        return upvotedSorted
          .sort((a, b) => b.upvotes - a.upvotes)
          .map(({ event }) => event);
      default:
        return events;
    }
  }

  function getTopics(): string[] {
    const topicSet = new Set<string>();
    // Use age-filtered threads for topic extraction
    const ageFiltered = filterByAge(threads);
    for (const thread of ageFiltered) {
      const topics = thread.tags.filter((t) => t[0] === 't').map((t) => t[1]);
      topics.forEach((t) => topicSet.add(t));
    }
    return Array.from(topicSet).sort();
  }

  function getTopicsWithCounts(): Array<{ topic: string | null; count: number }> {
    // Use age-filtered threads for counts
    const ageFiltered = filterByAge(threads);
    const topics = getTopics();
    const result: Array<{ topic: string | null; count: number }> = [];
    
    // Add "General" (threads without topics)
    const generalCount = ageFiltered.filter((t) => !t.tags.some((tag) => tag[0] === 't')).length;
    if (generalCount > 0) {
      result.push({ topic: null, count: generalCount });
    }
    
    // Add topics with counts
    for (const topic of topics) {
      const count = ageFiltered.filter((t) => t.tags.some((tag) => tag[0] === 't' && tag[1] === topic)).length;
      if (count > 0) {
        result.push({ topic, count });
      }
    }
    
    return result;
  }

  /**
   * Filter threads by age (30 days)
   */
  function filterByAge(events: NostrEvent[]): NostrEvent[] {
    if (showOlder) {
      return events; // Show all threads if "show older" is checked
    }
    
    const config = nostrClient.getConfig();
    const cutoffTime = Math.floor(Date.now() / 1000) - config.threadTimeoutDays * 86400;
    return events.filter((t) => t.created_at >= cutoffTime);
  }

  function getFilteredThreads(): NostrEvent[] {
    let filtered = threads;
    
    // Filter by age first
    filtered = filterByAge(filtered);
    
    // Then filter by topic
    // selectedTopic === null means "All" - show all threads (handled in template)
    // selectedTopic === undefined means "General" - show threads without topics
    if (selectedTopic === undefined) {
      return filtered.filter((t) => !t.tags.some((tag) => tag[0] === 't'));
    }
    // selectedTopic is a string - show threads with that topic
    return filtered.filter((t) => t.tags.some((tag) => tag[0] === 't' && tag[1] === selectedTopic));
  }

  function getThreadsByTopic(topic: string | null): NostrEvent[] {
    let filtered = threads;
    
    // Filter by age first
    filtered = filterByAge(filtered);
    
    // Then filter by topic
    if (topic === null) {
      return filtered.filter((t) => !t.tags.some((tag) => tag[0] === 't'));
    }
    return filtered.filter((t) => t.tags.some((tag) => tag[0] === 't' && tag[1] === topic));
  }
</script>

<div class="thread-list">
  <div class="controls mb-4 flex gap-4 items-center flex-wrap">
    <label class="text-fog-text dark:text-fog-dark-text">
      <input
        type="checkbox"
        bind:checked={showOlder}
        onchange={() => {
          // If showing older threads, reload to fetch them
          // If hiding older threads, just filter client-side (no reload needed)
          if (showOlder) {
            loadThreads();
          }
        }}
        class="mr-2"
      />
      Show older threads
    </label>
    <select bind:value={sortBy} onchange={async () => { threads = await sortThreads(threads); }} class="border border-fog-border dark:border-fog-dark-border bg-fog-post dark:bg-fog-dark-post text-fog-text dark:text-fog-dark-text px-2 py-1 rounded">
      <option value="newest">Newest</option>
      <option value="active">Most Active</option>
      <option value="upvoted">Most Upvoted</option>
    </select>
  </div>

  {#if loading}
    <p class="text-fog-text dark:text-fog-dark-text">Loading threads...</p>
  {:else}
    <!-- Topic Filter -->
    <div class="mb-6">
      <div class="flex flex-wrap gap-2 items-center">
        <span class="text-sm font-semibold text-fog-text dark:text-fog-dark-text mr-2">Filter by topic:</span>
        <button
          onclick={() => (selectedTopic = null)}
          class="px-3 py-1 rounded border transition-colors {selectedTopic === null
            ? 'bg-fog-accent dark:bg-fog-dark-accent text-white border-fog-accent dark:border-fog-dark-accent'
            : 'bg-fog-post dark:bg-fog-dark-post text-fog-text dark:text-fog-dark-text border-fog-border dark:border-fog-dark-border hover:bg-fog-highlight dark:hover:bg-fog-dark-highlight'}"
        >
          All ({filterByAge(threads).length})
        </button>
        {#each getTopicsWithCounts() as { topic, count }}
        <button
          onclick={() => (selectedTopic = topic === null ? undefined : topic)}
          class="px-3 py-1 rounded border transition-colors {selectedTopic === (topic === null ? undefined : topic)
            ? 'bg-fog-accent dark:bg-fog-dark-accent text-white border-fog-accent dark:border-fog-dark-accent'
            : 'bg-fog-post dark:bg-fog-dark-post text-fog-text dark:text-fog-dark-text border-fog-border dark:border-fog-dark-border hover:bg-fog-highlight dark:hover:bg-fog-dark-highlight'}"
        >
          {topic === null ? 'General' : topic} ({count})
        </button>
        {/each}
      </div>
    </div>

    <!-- Threads Display -->
    <div>
      {#if selectedTopic === null}
        <!-- Show all threads grouped by topic -->
        <h2 class="text-xl font-bold mb-4 text-fog-text dark:text-fog-dark-text">General</h2>
        {#each getThreadsByTopic(null) as thread}
          <ThreadCard {thread} />
        {/each}

        {#each getTopics() as topic}
          <h2 class="text-xl font-bold mb-4 mt-8 text-fog-text dark:text-fog-dark-text">{topic}</h2>
          {#each getThreadsByTopic(topic) as thread}
            <ThreadCard {thread} />
          {/each}
        {/each}
      {:else}
        <!-- Show filtered threads -->
        <h2 class="text-xl font-bold mb-4 text-fog-text dark:text-fog-dark-text">
          {selectedTopic === undefined ? 'General' : selectedTopic}
        </h2>
        {#each getFilteredThreads() as thread}
          <ThreadCard {thread} />
        {/each}
        {#if getFilteredThreads().length === 0}
          <p class="text-fog-text-light dark:text-fog-dark-text-light">No threads found in this topic.</p>
        {/if}
      {/if}
    </div>
  {/if}
</div>

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