<script lang="ts">
  import ProfileBadge from '../../components/layout/ProfileBadge.svelte';
  import MarkdownRenderer from '../../components/content/MarkdownRenderer.svelte';
  import PaymentAddresses from './PaymentAddresses.svelte';
  import FeedPost from '../feed/FeedPost.svelte';
  import ThreadDrawer from '../feed/ThreadDrawer.svelte';
  import { fetchProfile, fetchUserStatus, type ProfileData } from '../../services/user-data.js';
  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 { page } from '$app/stores';
  import { nip19 } from 'nostr-tools';
  import type { NostrEvent } from '../../types/nostr.js';

  let profile = $state<ProfileData | null>(null);
  let userStatus = $state<string | null>(null);
  let posts = $state<NostrEvent[]>([]);
  let responses = $state<NostrEvent[]>([]);
  let interactionsWithMe = $state<NostrEvent[]>([]);
  let loading = $state(true);
  let activeTab = $state<'posts' | 'responses' | 'interactions'>('posts');
  let nip05Validations = $state<Map<string, boolean | null>>(new Map()); // null = checking, true = valid, false = invalid
  
  // Get current logged-in user's pubkey
  let currentUserPubkey = $state<string | null>(sessionManager.getCurrentPubkey());
  
  // Drawer state for viewing threads
  let drawerOpen = $state(false);
  let drawerEvent = $state<NostrEvent | null>(null);
  
  function openDrawer(event: NostrEvent) {
    drawerEvent = event;
    drawerOpen = true;
  }
  
  function closeDrawer() {
    drawerOpen = false;
    drawerEvent = null;
  }
  
  // Subscribe to session changes
  $effect(() => {
    const unsubscribe = sessionManager.session.subscribe((session) => {
      currentUserPubkey = session?.pubkey || null;
      // Reload interactions if session changes and we're viewing another user's profile
      if (profile) {
        const pubkey = decodePubkey($page.params.pubkey);
        if (pubkey && currentUserPubkey && currentUserPubkey !== pubkey) {
          // Reload interactions tab data
          loadInteractionsWithMe(pubkey, currentUserPubkey);
        } else {
          interactionsWithMe = [];
        }
      }
    });
    return unsubscribe;
  });
  
  async function loadInteractionsWithMe(profilePubkey: string, currentUserPubkey: string) {
    if (!currentUserPubkey || currentUserPubkey === profilePubkey) {
      interactionsWithMe = [];
      return;
    }
    
    try {
      const interactionRelays = relayManager.getFeedResponseReadRelays();
      // Fetch current user's posts to find replies
      const currentUserPosts = await nostrClient.fetchEvents(
        [{ kinds: [1], authors: [currentUserPubkey], limit: 50 }],
        interactionRelays,
        { useCache: true, cacheResults: true }
      );
      const currentUserPostIds = new Set(currentUserPosts.map(p => p.id));
      
      const interactionEvents = await nostrClient.fetchEvents(
        [
          { kinds: [1], authors: [profilePubkey], '#e': Array.from(currentUserPostIds), limit: 20 }, // Replies to current user's posts
          { kinds: [1], authors: [profilePubkey], '#p': [currentUserPubkey], limit: 20 } // Mentions of current user
        ],
        interactionRelays,
        { useCache: true, cacheResults: true }
      );
      
      // Deduplicate and filter to only include actual interactions
      const seenIds = new Set<string>();
      interactionsWithMe = interactionEvents
        .filter(e => {
          if (seenIds.has(e.id)) return false;
          seenIds.add(e.id);
          
          // Check if it's a reply to current user's post
          const eTag = e.tags.find(t => t[0] === 'e');
          const isReplyToCurrentUser = eTag && currentUserPostIds.has(eTag[1]);
          
          // Check if it mentions current user
          const pTag = e.tags.find(t => t[0] === 'p' && t[1] === currentUserPubkey);
          const mentionsCurrentUser = !!pTag;
          
          return isReplyToCurrentUser || mentionsCurrentUser;
        })
        .sort((a, b) => b.created_at - a.created_at);
    } catch (error) {
      console.error('Error loading interactions with me:', error);
      interactionsWithMe = [];
    }
  }

  onMount(async () => {
    await nostrClient.initialize();
    // Load profile after initialization
    if ($page.params.pubkey) {
      loadProfile();
    } else {
      // No pubkey provided - show error state
      loading = false;
      profile = null;
    }
  });

  // React to route param changes
  let lastParam = $state<string | null>(null);
  $effect(() => {
    const param = $page.params.pubkey;
    // Only reload if parameter actually changed
    if (param && param !== lastParam) {
      lastParam = param;
      loadProfile();
    }
  });

  /**
   * Decode route parameter to hex pubkey
   * Supports: hex pubkey, npub, or nprofile
   */
  function decodePubkey(param: string): string | null {
    if (!param) return null;
    
    // Check if it's already a hex pubkey (64 hex characters)
    if (/^[0-9a-f]{64}$/i.test(param)) {
      return param.toLowerCase();
    }
    
    // Check if it's a bech32 encoded format (npub or nprofile)
    if (/^(npub|nprofile)1[a-z0-9]+$/i.test(param)) {
      try {
        const decoded = nip19.decode(param);
        if (decoded.type === 'npub') {
          return String(decoded.data);
        } else if (decoded.type === 'nprofile') {
          // nprofile contains pubkey and optional relays
          if (decoded.data && typeof decoded.data === 'object' && 'pubkey' in decoded.data) {
            return String(decoded.data.pubkey);
          }
        }
      } catch (error) {
        console.error('Error decoding bech32:', error);
        return null;
      }
    }
    
    return null;
  }

  /**
   * Validate NIP-05 address against well-known.json
   */
  async function validateNIP05(nip05: string, expectedPubkey: string) {
    // Mark as checking
    nip05Validations.set(nip05, null);
    
    try {
      // Parse NIP-05: format is "local@domain.com"
      const [localPart, domain] = nip05.split('@');
      if (!localPart || !domain) {
        nip05Validations.set(nip05, false);
        return;
      }

      // Fetch well-known JSON
      // NIP-05 spec: https://[domain]/.well-known/nostr.json?name=[local]
      const url = `https://${domain}/.well-known/nostr.json?name=${encodeURIComponent(localPart)}`;
      
      const response = await fetch(url, {
        method: 'GET',
        headers: {
          'Accept': 'application/json'
        }
      });

      if (!response.ok) {
        nip05Validations.set(nip05, false);
        return;
      }

      const data = await response.json();
      
      // Check if the response contains the expected pubkey
      // NIP-05 format: { "names": { "local": "hex-pubkey" } }
      if (data.names && data.names[localPart]) {
        const verifiedPubkey = data.names[localPart].toLowerCase();
        const expected = expectedPubkey.toLowerCase();
        nip05Validations.set(nip05, verifiedPubkey === expected);
      } else {
        nip05Validations.set(nip05, false);
      }
    } catch (error) {
      console.error('Error validating NIP-05:', nip05, error);
      nip05Validations.set(nip05, false);
    }
  }

  async function loadProfile() {
    const param = $page.params.pubkey;
    if (!param) {
      console.warn('No pubkey parameter provided to ProfilePage');
      loading = false;
      profile = null;
      return;
    }

    // Decode the parameter to hex pubkey
    const pubkey = decodePubkey(param);
    if (!pubkey) {
      console.warn('Invalid pubkey format:', param);
      loading = false;
      profile = null;
      return;
    }

    loading = true;
    try {
      console.log('Loading profile for pubkey:', pubkey, '(decoded from:', param + ')');

      // Load profile
      const profileData = await fetchProfile(pubkey);
      profile = profileData;
      console.log('Profile loaded:', profileData);

      // Validate NIP-05 addresses (async, don't wait)
      if (profileData?.nip05 && profileData.nip05.length > 0) {
        for (const nip05 of profileData.nip05) {
          // Validate in background - don't block page load
          validateNIP05(nip05, pubkey).catch(err => {
            console.error('NIP-05 validation error:', err);
          });
        }
      }

      // Load user status
      const status = await fetchUserStatus(pubkey);
      userStatus = status;

      // Load kind 1 posts
      const profileRelays = relayManager.getProfileReadRelays();
      const feedEvents = await nostrClient.fetchEvents(
        [{ kinds: [1], authors: [pubkey], limit: 20 }],
        profileRelays,
        { useCache: true, cacheResults: true }
      );
      posts = feedEvents.sort((a, b) => b.created_at - a.created_at);

      // Load kind 1 responses (replies to this user's posts)
      const responseRelays = relayManager.getFeedResponseReadRelays();
      const responseEvents = await nostrClient.fetchEvents(
        [{ kinds: [1], '#p': [pubkey], limit: 20 }],
        responseRelays,
        { useCache: true, cacheResults: true }
      );
      // Filter to only include actual replies (have e tag pointing to user's posts)
      // AND exclude self-replies (where author is the same as the profile owner)
      const userPostIds = new Set(posts.map(p => p.id));
      responses = responseEvents
        .filter(e => {
          // Exclude self-replies
          if (e.pubkey === pubkey) {
            return false;
          }
          const eTag = e.tags.find(t => t[0] === 'e');
          return eTag && userPostIds.has(eTag[1]);
        })
        .sort((a, b) => b.created_at - a.created_at);

      // Load "Interactions with me" if user is logged in and viewing another user's profile
      if (currentUserPubkey && currentUserPubkey !== pubkey) {
        await loadInteractionsWithMe(pubkey, currentUserPubkey);
      } else {
        interactionsWithMe = [];
      }
    } catch (error) {
      console.error('Error loading profile:', error);
      // Set loading to false even on error so UI can show error state
      loading = false;
      profile = null; // Clear profile on error
    } finally {
      // Ensure loading is always set to false
      if (loading) {
      loading = false;
      }
    }
  }
</script>

<div class="profile-page">
  {#if loading}
    <p class="text-fog-text-light dark:text-fog-dark-text-light">Loading profile...</p>
  {:else if profile}
    <div class="profile-header mb-6">
      {#if profile.picture}
        <img
          src={profile.picture}
          alt={profile.name || 'Profile picture'}
          class="profile-picture w-24 h-24 rounded-full mb-4"
        />
      {/if}
      <h1 class="text-3xl font-bold mb-2">{profile.name || 'Anonymous'}</h1>
      {#if profile.about}
        <p class="text-fog-text dark:text-fog-dark-text mb-2">{profile.about}</p>
      {/if}
      {#if userStatus}
        <p class="text-sm text-fog-text-light dark:text-fog-dark-text-light italic mb-2">
          {userStatus}
        </p>
      {/if}
      {#if profile.website && profile.website.length > 0}
        <div class="websites mb-2">
          {#each profile.website as website}
            <a
              href={website}
              target="_blank"
              rel="noopener noreferrer"
              class="text-fog-accent dark:text-fog-dark-accent hover:underline mr-2"
            >
              {website}
            </a>
          {/each}
        </div>
      {/if}
      {#if profile.nip05 && profile.nip05.length > 0}
        <div class="nip05 mb-2">
          {#each profile.nip05 as nip05}
            {@const isValid = nip05Validations.get(nip05)}
            <span class="text-sm text-fog-text-light dark:text-fog-dark-text-light mr-2">
              {nip05}
              {#if isValid === true}
                <span class="nip05-valid" title="NIP-05 verified">✓</span>
              {:else if isValid === false}
                <span class="nip05-invalid" title="NIP-05 verification failed">✗</span>
              {:else}
                <span class="nip05-checking" title="Verifying NIP-05...">⟳</span>
              {/if}
            </span>
          {/each}
        </div>
      {/if}
      <PaymentAddresses pubkey={decodePubkey($page.params.pubkey) || ''} />
    </div>

    <div class="profile-posts">
      <div class="tabs mb-4 flex gap-4 border-b border-fog-border dark:border-fog-dark-border">
        <button
          onclick={() => activeTab = 'posts'}
          class="px-4 py-2 font-semibold {activeTab === 'posts' ? 'border-b-2 border-fog-accent dark:border-fog-dark-accent' : ''}"
        >
          Posts ({posts.length})
        </button>
        <button
          onclick={() => activeTab = 'responses'}
          class="px-4 py-2 font-semibold {activeTab === 'responses' ? 'border-b-2 border-fog-accent dark:border-fog-dark-accent' : ''}"
        >
          Responses ({responses.length})
        </button>
        {#if currentUserPubkey && currentUserPubkey !== decodePubkey($page.params.pubkey)}
          <button
            onclick={() => activeTab = 'interactions'}
            class="px-4 py-2 font-semibold {activeTab === 'interactions' ? 'border-b-2 border-fog-accent dark:border-fog-dark-accent' : ''}"
          >
            Interactions with me ({interactionsWithMe.length})
          </button>
        {/if}
      </div>

      {#if activeTab === 'posts'}
        {#if posts.length === 0}
          <p class="text-fog-text-light dark:text-fog-dark-text-light">No posts yet.</p>
        {:else}
          <div class="posts-list">
            {#each posts as post (post.id)}
              <FeedPost post={post} onOpenEvent={openDrawer} />
            {/each}
          </div>
        {/if}
      {:else if activeTab === 'responses'}
        {#if responses.length === 0}
          <p class="text-fog-text-light dark:text-fog-dark-text-light">No responses yet.</p>
        {:else}
          <div class="responses-list">
            {#each responses as response (response.id)}
              <FeedPost post={response} onOpenEvent={openDrawer} />
            {/each}
          </div>
        {/if}
      {:else if activeTab === 'interactions'}
        {#if interactionsWithMe.length === 0}
          <p class="text-fog-text-light dark:text-fog-dark-text-light">No interactions with you yet.</p>
        {:else}
          <div class="interactions-list">
            {#each interactionsWithMe as interaction (interaction.id)}
              <FeedPost post={interaction} onOpenEvent={openDrawer} />
            {/each}
          </div>
        {/if}
      {/if}
    </div>
  {:else}
    <p class="text-fog-text-light dark:text-fog-dark-text-light">Profile not found</p>
  {/if}
  
  <ThreadDrawer opEvent={drawerEvent} isOpen={drawerOpen} onClose={closeDrawer} />
</div>

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

  .profile-picture {
    object-fit: cover;
  }
  
  .profile-header {
    overflow-wrap: break-word;
    word-break: break-word;
  }
  
  .profile-header h1 {
    overflow-wrap: break-word;
    word-break: break-word;
  }
  
  .profile-header p {
    overflow-wrap: break-word;
    word-break: break-word;
  }
  
  .profile-header .websites {
    overflow-wrap: break-word;
    word-break: break-word;
  }
  
  .profile-header .websites a {
    display: inline-block;
    max-width: 100%;
    overflow-wrap: break-word;
    word-break: break-word;
  }
  
  .profile-header .nip05 {
    overflow-wrap: break-word;
    word-break: break-word;
  }
  
  .profile-header .nip05 span {
    display: inline-block;
    max-width: 100%;
    overflow-wrap: break-word;
    word-break: break-word;
  }
  
  .nip05-valid {
    color: #60a5fa;
    margin-left: 0.25rem;
    font-weight: bold;
  }
  
  .nip05-invalid {
    color: #ef4444;
    margin-left: 0.25rem;
    font-weight: bold;
  }
  
  .nip05-checking {
    color: #9ca3af;
    margin-left: 0.25rem;
    display: inline-block;
    animation: spin 1s linear infinite;
  }
  
  @keyframes spin {
    from {
      transform: rotate(0deg);
    }
    to {
      transform: rotate(360deg);
    }
  }
</style>
