<script lang="ts">
  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 { signAndPublish } from '../../services/nostr/auth-handler.js';
  import { onMount } from 'svelte';
  import type { NostrEvent } from '../../types/nostr.js';
  import { KIND } from '../../types/kind-lookup.js';
  import PublicationStatusModal from '../modals/PublicationStatusModal.svelte';

  interface Props {
    pollEvent: NostrEvent; // The poll event (kind 1068)
  }

  let { pollEvent }: Props = $props();

  interface PollOption {
    id: string;
    label: string;
  }

  interface PollVote {
    pubkey: string;
    optionIds: string[];
    created_at: number;
  }

  let options = $state<PollOption[]>([]);
  let pollType = $state<'singlechoice' | 'multiplechoice'>('singlechoice');
  let endsAt = $state<number | null>(null);
  let relayUrls = $state<string[]>([]);
  let votes = $state<Map<string, PollVote>>(new Map()); // pubkey -> vote
  let loading = $state(true);
  let submittingVote = $state(false);
  let userVote = $state<string[]>([]); // Option IDs the current user has voted for
  let hasVoted = $state(false);
  let publicationModalOpen = $state(false);
  let publicationResults = $state<{ success: string[]; failed: Array<{ relay: string; error: string }> } | null>(null);

  // Parse poll event
  function parsePoll() {
    // Extract options
    const optionTags = pollEvent.tags.filter(t => t[0] === 'option' && t.length >= 3);
    options = optionTags.map(t => ({
      id: t[1],
      label: t[2]
    }));

    // Extract polltype (default to singlechoice)
    const polltypeTag = pollEvent.tags.find(t => t[0] === 'polltype');
    pollType = (polltypeTag?.[1] === 'multiplechoice') ? 'multiplechoice' : 'singlechoice';

    // Extract endsAt
    const endsAtTag = pollEvent.tags.find(t => t[0] === 'endsAt');
    if (endsAtTag?.[1]) {
      endsAt = parseInt(endsAtTag[1], 10);
      if (isNaN(endsAt)) endsAt = null;
    }

    // Extract relay URLs
    relayUrls = pollEvent.tags
      .filter(t => t[0] === 'relay' && t[1])
      .map(t => t[1]);
  }

  // Check if poll has ended
  let isExpired = $derived.by(() => {
    if (!endsAt) return false;
    return Date.now() / 1000 >= endsAt;
  });

  // Get vote counts per option
  let voteCounts = $derived.by(() => {
    const counts = new Map<string, number>();
    options.forEach(opt => counts.set(opt.id, 0));

    votes.forEach(vote => {
      if (pollType === 'singlechoice') {
        // For singlechoice, only count the first response
        if (vote.optionIds.length > 0) {
          const optionId = vote.optionIds[0];
          counts.set(optionId, (counts.get(optionId) || 0) + 1);
        }
      } else {
        // For multiplechoice, count all responses (deduplicated)
        const uniqueOptions = new Set(vote.optionIds);
        uniqueOptions.forEach(optionId => {
          counts.set(optionId, (counts.get(optionId) || 0) + 1);
        });
      }
    });

    return counts;
  });

  // Get total vote count
  let totalVotes = $derived.by(() => {
    return votes.size;
  });

  // Get percentage for each option
  function getPercentage(optionId: string): number {
    if (totalVotes === 0) return 0;
    const count = voteCounts.get(optionId) || 0;
    return (count / totalVotes) * 100;
  }

  // Load poll responses
  async function loadVotes() {
    if (relayUrls.length === 0) {
      // Use default relays if no relay URLs specified
      const relays = relayManager.getFeedReadRelays();
      await fetchVotesFromRelays(relays);
    } else {
      await fetchVotesFromRelays(relayUrls);
    }
  }

  async function fetchVotesFromRelays(relays: string[]) {
    loading = true;
    try {
      const now = Math.floor(Date.now() / 1000);
      const until = endsAt ? Math.min(endsAt, now) : now;

      const responseEvents = await nostrClient.fetchEvents(
        [{ kinds: [KIND.POLL_RESPONSE], '#e': [pollEvent.id], until, limit: 100 }],
        relays,
        { useCache: true, cacheResults: true }
      );

      // One vote per pubkey - keep only the newest vote (highest created_at)
      // Sort by created_at descending to process newest first
      const sortedEvents = [...responseEvents].sort((a, b) => b.created_at - a.created_at);
      
      const voteMap = new Map<string, PollVote>();
      sortedEvents.forEach(event => {
        // Only add if we haven't seen this pubkey yet, or if this event is newer
        // Since we sorted descending, the first occurrence is the newest
        if (!voteMap.has(event.pubkey)) {
          // Extract response option IDs
          const responseTags = event.tags.filter(t => t[0] === 'response' && t[1]);
          const optionIds = responseTags.map(t => t[1]);

          voteMap.set(event.pubkey, {
            pubkey: event.pubkey,
            optionIds,
            created_at: event.created_at
          });
        }
      });

      votes = voteMap;

      // Check if current user has voted
      const session = sessionManager.getSession();
      if (session) {
        const userVoteData = votes.get(session.pubkey);
        if (userVoteData) {
          userVote = userVoteData.optionIds;
          hasVoted = true;
        }
      }
    } catch (error) {
      console.error('Error loading poll votes:', error);
    } finally {
      loading = false;
    }
  }

  // Submit vote
  async function submitVote(optionId: string) {
    const session = sessionManager.getSession();
    if (!session) {
      alert('Please log in to vote');
      return;
    }

    if (isExpired) {
      alert('This poll has ended');
      return;
    }

    if (submittingVote) {
      return; // Prevent double-submission
    }

    if (pollType === 'singlechoice') {
      // Single choice: replace any existing vote
      userVote = [optionId];
    } else {
      // Multiple choice: toggle option
      if (userVote.includes(optionId)) {
        userVote = userVote.filter(id => id !== optionId);
      } else {
        userVote = [...userVote, optionId];
      }
    }

    // Create response event
    const responseTags = [
      ['e', pollEvent.id],
      ...userVote.map(id => ['response', id] as [string, string])
    ];

    submittingVote = true;
    try {
      const result = await signAndPublish({
        kind: KIND.POLL_RESPONSE,
        content: '',
        tags: responseTags,
        created_at: Math.floor(Date.now() / 1000),
        pubkey: session.pubkey
      }, relayUrls.length > 0 ? relayUrls : undefined);
      publicationResults = result;
      publicationModalOpen = true;

      if (result.success.length > 0) {
        // Reload votes after successful publish
        await loadVotes();
        hasVoted = true;
      } else {
        // Revert userVote on failure
        if (pollType === 'singlechoice') {
          userVote = [];
        } else {
          // For multiple choice, we need to check what the previous state was
          // For now, just keep the current state
        }
        alert('Failed to submit vote. Please try again.');
      }
    } catch (error) {
      console.error('Error submitting vote:', error);
      // Revert userVote on error
      if (pollType === 'singlechoice') {
        userVote = [];
      }
      alert('Failed to submit vote. Please try again.');
    } finally {
      submittingVote = false;
    }
  }

  onMount(() => {
    parsePoll();
    loadVotes();
  });
</script>

<div class="poll-card">
  <div class="poll-question">
    {pollEvent.content}
  </div>

  {#if isExpired}
    <div class="poll-status">
      Poll ended
    </div>
  {:else if submittingVote}
    <div class="poll-status">
      Submitting vote...
    </div>
  {:else if hasVoted}
    <div class="poll-status">
      You have already voted
    </div>
  {/if}

  <div class="poll-options">
    {#each options as option (option.id)}
      {@const percentage = getPercentage(option.id)}
      {@const count = voteCounts.get(option.id) || 0}
      {@const isSelected = userVote.includes(option.id)}
      
      <button
        class="poll-option" 
        class:selected={isSelected}
        class:expired={isExpired}
        class:voted={hasVoted}
        onclick={() => !isExpired && !submittingVote && !hasVoted && submitVote(option.id)}
        disabled={isExpired || submittingVote || hasVoted}
        onkeydown={(e) => {
          if (!isExpired && !submittingVote && !hasVoted && (e.key === 'Enter' || e.key === ' ')) {
            e.preventDefault();
            submitVote(option.id);
          }
        }}
      >
        <div class="poll-option-content">
          <div class="poll-option-label">
            {option.label}
          </div>
          <div class="poll-option-stats">
            <span class="poll-percentage">{percentage.toFixed(1)}%</span>
            {#if count > 0}
              <span class="poll-count">({count})</span>
            {/if}
          </div>
        </div>
        <div class="poll-bar-container">
          <div 
            class="poll-bar" 
            style="width: {percentage}%"
          ></div>
        </div>
      </button>
    {/each}
  </div>

  <div class="poll-footer">
    <span class="poll-vote-count">{totalVotes} {totalVotes === 1 ? 'vote' : 'votes'}</span>
    {#if !isExpired && !hasVoted}
      <button 
        class="poll-update-button"
        onclick={() => loadVotes()}
        disabled={loading}
      >
        {loading ? 'Loading...' : 'Update results'}
      </button>
    {/if}
  </div>
</div>

<PublicationStatusModal bind:open={publicationModalOpen} bind:results={publicationResults} />

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

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

  .poll-question {
    font-weight: 600;
    margin-bottom: 0.75rem;
    color: var(--fog-text, #1f2937);
  }

  :global(.dark) .poll-question {
    color: var(--fog-dark-text, #f9fafb);
  }

  .poll-status {
    font-size: 0.875rem;
    color: var(--fog-text-light, #52667a);
    margin-bottom: 0.75rem;
    font-style: italic;
  }

  :global(.dark) .poll-status {
    color: var(--fog-dark-text-light, #a8b8d0);
  }

  .poll-options {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
  }

  .poll-option {
    position: relative;
    padding: 0.75rem;
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.25rem;
    background: var(--fog-highlight, #f3f4f6);
    cursor: pointer;
    transition: all 0.2s;
    width: 100%;
    text-align: left;
    font-family: inherit;
    font-size: inherit;
  }

  :global(.dark) .poll-option {
    background: var(--fog-dark-highlight, #374151);
    border-color: var(--fog-dark-border, #4b5563);
  }

  .poll-option:not(.expired):hover {
    background: var(--fog-border, #e5e7eb);
    border-color: var(--fog-accent, #64748b);
  }

  :global(.dark) .poll-option:not(.expired):hover {
    background: var(--fog-dark-border, #4b5563);
    border-color: var(--fog-dark-accent, #94a3b8);
  }

  .poll-option.selected {
    border-color: var(--fog-accent, #64748b);
    background: var(--fog-highlight, #f3f4f6);
  }

  :global(.dark) .poll-option.selected {
    border-color: var(--fog-dark-accent, #94a3b8);
    background: var(--fog-dark-highlight, #374151);
  }

  .poll-option:disabled {
    cursor: default;
    opacity: 0.7;
  }

  .poll-option.voted {
    cursor: default;
  }

  .poll-option.voted:not(.selected) {
    opacity: 0.8;
  }

  .poll-option-content {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.25rem;
  }

  .poll-option-label {
    flex: 1;
    color: var(--fog-text, #1f2937);
  }

  :global(.dark) .poll-option-label {
    color: var(--fog-dark-text, #f9fafb);
  }

  .poll-option-stats {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.875rem;
    color: var(--fog-text-light, #52667a);
  }

  :global(.dark) .poll-option-stats {
    color: var(--fog-dark-text-light, #a8b8d0);
  }

  .poll-percentage {
    font-weight: 600;
  }

  .poll-count {
    font-size: 0.75rem;
  }

  .poll-bar-container {
    height: 4px;
    background: var(--fog-border, #e5e7eb);
    border-radius: 2px;
    overflow: hidden;
    margin-top: 0.5rem;
  }

  :global(.dark) .poll-bar-container {
    background: var(--fog-dark-border, #4b5563);
  }

  .poll-bar {
    height: 100%;
    background: var(--fog-accent, #64748b);
    transition: width 0.3s ease;
  }

  :global(.dark) .poll-bar {
    background: var(--fog-dark-accent, #94a3b8);
  }

  .poll-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 0.875rem;
    color: var(--fog-text-light, #52667a);
    padding-top: 0.5rem;
    border-top: 1px solid var(--fog-border, #e5e7eb);
  }

  :global(.dark) .poll-footer {
    color: var(--fog-dark-text-light, #a8b8d0);
    border-top-color: var(--fog-dark-border, #4b5563);
  }

  .poll-vote-count {
    font-weight: 500;
  }

  .poll-update-button {
    background: transparent;
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.25rem;
    padding: 0.25rem 0.5rem;
    font-size: 0.75rem;
    color: var(--fog-text, #1f2937);
    cursor: pointer;
    transition: all 0.2s;
  }

  :global(.dark) .poll-update-button {
    border-color: var(--fog-dark-border, #4b5563);
    color: var(--fog-dark-text, #f9fafb);
  }

  .poll-update-button:hover:not(:disabled) {
    background: var(--fog-highlight, #f3f4f6);
    border-color: var(--fog-accent, #64748b);
  }

  :global(.dark) .poll-update-button:hover:not(:disabled) {
    background: var(--fog-dark-highlight, #374151);
    border-color: var(--fog-dark-accent, #94a3b8);
  }

  .poll-update-button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
</style>
