<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 CommentComponent from '../comments/Comment.svelte';
  import ProfileMenu from '../../components/profile/ProfileMenu.svelte';
  import { fetchProfile, fetchUserStatus, fetchUserStatusEvent, fetchRelayLists, type ProfileData } from '../../services/user-data.js';
  import { nostrClient } from '../../services/nostr/nostr-client.js';
  import { relayManager } from '../../services/nostr/relay-manager.js';
  import { config } from '../../services/nostr/config.js';
  import { sessionManager } from '../../services/auth/session-manager.js';
  import { onMount } from 'svelte';
  import { page } from '$app/stores';
  import { goto } from '$app/navigation';
  import { nip19 } from 'nostr-tools';
  import type { NostrEvent } from '../../types/nostr.js';
  import { KIND } from '../../types/kind-lookup.js';
  import CommentForm from '../comments/CommentForm.svelte';
  import { getProfile } from '../../services/cache/profile-cache.js';
  

  let profile = $state<ProfileData | null>(null);
  let profileEvent = $state<NostrEvent | null>(null); // The kind 0 event
  let userStatus = $state<string | null>(null);
  let userStatusEvent = $state<NostrEvent | null>(null); // The kind 30315 event
  let notifications = $state<NostrEvent[]>([]);
  let interactionsWithMe = $state<NostrEvent[]>([]);
  let wallComments = $state<NostrEvent[]>([]); // Kind 1111 comments on the wall
  let loading = $state(true);
  let loadingWall = $state(false);
  let activeTab = $state<'pins' | 'notifications' | 'interactions' | 'wall'>('pins');
  let nip05Validations = $state<Record<string, boolean | null>>({}); // null = checking, true = valid, false = invalid
  // Compute pubkey from route params
  let profilePubkey = $derived.by(() => decodePubkey($page.params.pubkey));

  // Initialize activeTab from URL parameter
  function getTabFromUrl(): 'pins' | 'notifications' | 'interactions' | 'wall' {
    const tabParam = $page.url.searchParams.get('tab');
    const validTabs: Array<'pins' | 'notifications' | 'interactions' | 'wall'> = ['pins', 'notifications', 'interactions', 'wall'];
    if (tabParam && validTabs.includes(tabParam as any)) {
      return tabParam as 'pins' | 'notifications' | 'interactions' | 'wall';
    }
    return 'pins'; // Default
  }

  // Update activeTab when URL changes
  $effect(() => {
    const urlTab = getTabFromUrl();
    if (urlTab !== activeTab) {
      activeTab = urlTab;
      // Load data for the tab if needed
      if (activeTab === 'wall' && profileEvent && wallComments.length === 0 && !loadingWall) {
        loadWallComments(profileEvent.id);
      }
    }
  });

  // Function to change tab and update URL
  async function setActiveTab(tab: 'pins' | 'notifications' | 'interactions' | 'wall') {
    activeTab = tab;
    const url = new URL($page.url);
    url.searchParams.set('tab', tab);
    goto(url.pathname + url.search, { replaceState: true, noScroll: true });
    
    // Handle tab-specific logic
    if (tab === 'wall') {
      // Load profile event if not loaded yet
      if (!profileEvent && profilePubkey) {
        await loadProfileEvent(profilePubkey);
      }
      // Load wall comments if profile event is available and not already loaded
      if (profileEvent && wallComments.length === 0 && !loadingWall) {
        await loadWallComments(profileEvent.id);
      }
    }
  }
  
  // Cache for NIP-05 validation results (nip05+pubkey -> result)
  // This prevents re-validating the same NIP-05 address repeatedly
  const nip05ValidationCache = new Map<string, boolean>();
  
  // Get current logged-in user's pubkey
  let currentUserPubkey = $state<string | null>(sessionManager.getCurrentPubkey());
  
  // Pins state
  let pins = $state<NostrEvent[]>([]);
  
  // Cleanup tracking
  let isMounted = $state(true);
  let activeFetchPromises = $state<Set<Promise<any>>>(new Set());
  let currentLoadPubkey = $state<string | null>(null); // Track which pubkey is currently being loaded
  let loadAbortController = $state<AbortController | null>(null); // Abort controller for current load
  
  // Cleanup on unmount
  $effect(() => {
    return () => {
      isMounted = false;
      activeFetchPromises.clear();
      if (loadAbortController) {
        loadAbortController.abort();
        loadAbortController = null;
      }
      loading = false;
      currentLoadPubkey = null;
    };
  });

  const isOwnProfile = $derived.by(() => {
    const pubkey = decodePubkey($page.params.pubkey);
    return currentUserPubkey && pubkey && currentUserPubkey === pubkey;
  });
  
  // Subscribe to session changes
  $effect(() => {
    const unsubscribe = sessionManager.session.subscribe((session) => {
      currentUserPubkey = session?.pubkey || null;
      // Reload notifications/interactions if session changes
      if (profile) {
        const pubkey = decodePubkey($page.params.pubkey);
        if (pubkey && currentUserPubkey) {
          if (currentUserPubkey === pubkey) {
            // Reload notifications for own profile
            loadNotifications(pubkey);
        } else {
            // Reload interactions for other user's profile
            loadInteractionsWithMe(pubkey, currentUserPubkey);
          }
        }
      }
    });
    return unsubscribe;
  });
  
  /**
   * Get relays for loading a profile, including the profile owner's relay lists
   */
  async function getProfileRelaysForPubkey(pubkey: string): Promise<string[]> {
    // Start with base profile relays
    const baseRelays = relayManager.getProfileReadRelays();
    
    // Try to fetch relay lists from the profile owner (non-blocking)
    try {
      const { inbox } = await Promise.race([
        fetchRelayLists(pubkey, baseRelays),
        new Promise<{ inbox: string[]; outbox: string[] }>((resolve) => 
          setTimeout(() => resolve({ inbox: [], outbox: [] }), 2000)
        )
      ]);
      
      // Combine base relays with profile owner's inbox relays
      const allRelays = [...baseRelays, ...inbox];
      
      // Normalize and deduplicate
      const normalized = allRelays.map(r => r.toLowerCase().trim()).filter(r => r.length > 0);
      return Array.from(new Set(normalized));
    } catch (error) {
      // If fetching relay lists fails, just use base relays
      return baseRelays;
    }
  }

  async function loadProfileEvent(pubkey: string) {
    if (!isMounted) return;
    try {
      // Try cache first
      const cached = await getProfile(pubkey);
      if (cached) {
        profileEvent = cached.event;
        // Don't load wall comments here - load them when Wall tab is clicked
        return;
      }

      // Fetch from relays if not in cache - shorter timeout
      // Include profile owner's relay lists
      const relays = await getProfileRelaysForPubkey(pubkey);
      const events = await nostrClient.fetchEvents(
        [{ kinds: [KIND.METADATA], authors: [pubkey], limit: 1 }],
        relays,
        { useCache: 'cache-first', cacheResults: true, timeout: config.shortTimeout }
      );

      if (events.length > 0 && isMounted) {
        profileEvent = events[0];
        // Don't load wall comments here - load them when Wall tab is clicked
      }
    } catch (error) {
      // Failed to load profile event - non-critical
    }
  }

  async function loadWallComments(profileEventId: string) {
    if (!isMounted || !profileEventId) return;
    
    // Load from cache first (fast - instant display)
    try {
      const { getRecentCachedEvents } = await import('../../services/cache/event-cache.js');
      const cachedComments = await getRecentCachedEvents([KIND.COMMENT], 60 * 60 * 1000, 100); // 1 hour cache
      
      // Filter to only comments that reference this profile event as root
      const filtered = cachedComments.filter(comment => {
        const kTag = comment.tags.find(t => t[0] === 'K' && t[1] === '0');
        const eTag = comment.tags.find(t => t[0] === 'E' && t[1] === profileEventId);
        return kTag && eTag;
      });
      
      if (filtered.length > 0 && isMounted) {
        wallComments = filtered.sort((a, b) => b.created_at - a.created_at);
        loadingWall = false; // Show cached content immediately
      } else {
        loadingWall = true; // Only show loading if no cache
      }
    } catch (error) {
      // Cache error is non-critical
      loadingWall = true; // Show loading if cache check fails
    }
    
    // Stream fresh data from relays (progressive enhancement)
    try {
      // Fetch kind 1111 comments that reference this kind 0 event
      // NIP-22 format: K="0", E=profileEventId
      const relays = relayManager.getCommentReadRelays();
      const comments = await nostrClient.fetchEvents(
        [
          {
            kinds: [KIND.COMMENT],
            '#K': ['0'], // Root kind is 0
            '#E': [profileEventId], // Root event is the profile event
            limit: 100
          }
        ],
        relays,
        { 
          useCache: 'cache-first', // Already shown cache above, now stream updates
          cacheResults: true, 
          timeout: config.mediumTimeout,
          onUpdate: (newComments) => {
            if (!isMounted) return;
            // Merge with existing comments
            const commentMap = new Map(wallComments.map(c => [c.id, c]));
            for (const comment of newComments) {
              const kTag = comment.tags.find(t => t[0] === 'K' && t[1] === '0');
              const eTag = comment.tags.find(t => t[0] === 'E' && t[1] === profileEventId);
              if (kTag && eTag) {
                commentMap.set(comment.id, comment);
              }
            }
            wallComments = Array.from(commentMap.values()).sort((a, b) => b.created_at - a.created_at);
            loadingWall = false;
          }
        }
      );

      if (!isMounted) return;

      // Filter to only comments that actually reference this profile event as root
      // and sort by created_at descending
      wallComments = comments
        .filter(comment => {
          const kTag = comment.tags.find(t => t[0] === 'K' && t[1] === '0');
          const eTag = comment.tags.find(t => t[0] === 'E' && t[1] === profileEventId);
          return kTag && eTag;
        })
        .sort((a, b) => b.created_at - a.created_at);
    } catch (error) {
      // Failed to load wall comments
      if (isMounted) {
        wallComments = [];
      }
    } finally {
      if (isMounted) {
        loadingWall = false;
      }
    }
  }

  async function loadPins(pubkey: string) {
    if (!isMounted) return;
    try {
      // Fetch the user's pin list (kind 10001) - cache first, short timeout
      const profileRelays = relayManager.getProfileReadRelays();
      const pinLists = await nostrClient.fetchEvents(
        [{ kinds: [KIND.PIN_LIST], authors: [pubkey], limit: 1 }],
        profileRelays,
        { useCache: 'cache-first', cacheResults: true, timeout: config.shortTimeout }
      );
      
      if (!isMounted || pinLists.length === 0) {
        if (isMounted) pins = [];
        return;
      }

      // Extract event IDs from pin list
      const pinnedIds = new Set<string>();
      for (const tag of pinLists[0].tags) {
        if (tag[0] === 'e' && tag[1]) {
          pinnedIds.add(tag[1]);
        }
      }

      if (pinnedIds.size === 0) {
        if (isMounted) pins = [];
        return;
      }

      // Fetch the actual pinned events with cache-first and streaming
      // Use shorter timeout since cache should be fast
      const fetchPromise = nostrClient.fetchEvents(
        [{ ids: Array.from(pinnedIds), limit: config.feedLimit }],
        profileRelays,
        { 
          useCache: 'cache-first', // Load from cache first
          cacheResults: true, 
          timeout: config.shortTimeout, // Shorter timeout for cache-first
          onUpdate: (newPins) => {
            if (!isMounted) return;
            // Merge with existing pins
            const pinMap = new Map(pins.map(p => [p.id, p]));
            for (const pin of newPins) {
              pinMap.set(pin.id, pin);
            }
            pins = Array.from(pinMap.values()).sort((a, b) => b.created_at - a.created_at);
          }
        }
      );
      activeFetchPromises.add(fetchPromise);
      const pinnedEvents = await fetchPromise;
      activeFetchPromises.delete(fetchPromise);
      
      if (!isMounted) return;
      
      // Sort by created_at descending
      pins = pinnedEvents.sort((a, b) => b.created_at - a.created_at);
    } catch (error) {
      // Failed to load pins
      if (isMounted) pins = [];
    }
  }
  
  async function loadNotifications(pubkey: string) {
    if (!isMounted) return;
    try {
      const notificationRelays = relayManager.getFeedReadRelays();
      
      // Fetch user's posts to find replies - cache first, shorter timeout
      const userPosts = await nostrClient.fetchEvents(
        [{ kinds: [KIND.SHORT_TEXT_NOTE], authors: [pubkey], limit: 100 }],
        notificationRelays,
        { useCache: 'cache-first', cacheResults: true, timeout: config.shortTimeout }
      );
      
      if (!isMounted) return;
      
      const userPostIds = new Set(userPosts.map(p => p.id));
      
      // Only fetch notifications if we have posts to check
      if (userPostIds.size === 0) {
        if (isMounted) notifications = [];
        return;
      }
      
      // Fetch notifications: replies, mentions, reactions with cache-first and streaming
      // Use shorter timeout since cache should be fast
      const notificationEvents = await nostrClient.fetchEvents(
        [
          { kinds: [KIND.SHORT_TEXT_NOTE], '#e': Array.from(userPostIds).slice(0, 50), limit: 100 }, // Replies to user's posts
          { kinds: [KIND.SHORT_TEXT_NOTE], '#p': [pubkey], limit: 100 }, // Mentions
          { kinds: [KIND.REACTION], '#p': [pubkey], limit: 100 } // Reactions
        ],
        notificationRelays,
        { 
          useCache: 'cache-first', // Load from cache first
          cacheResults: true, 
          timeout: config.shortTimeout, // Shorter timeout for cache-first
          onUpdate: (newNotifications) => {
            if (!isMounted) return;
            // Merge with existing notifications
            const notificationMap = new Map(notifications.map(n => [n.id, n]));
            for (const notification of newNotifications) {
              notificationMap.set(notification.id, notification);
            }
            notifications = Array.from(notificationMap.values()).sort((a, b) => b.created_at - a.created_at);
          }
        }
      );
      
      if (!isMounted) return;
      
      // Deduplicate and sort by created_at descending
      const seenIds = new Set<string>();
      notifications = notificationEvents
        .filter(e => {
          if (seenIds.has(e.id)) return false;
          seenIds.add(e.id);
          // Exclude user's own events
          return e.pubkey !== pubkey;
        })
        .sort((a, b) => b.created_at - a.created_at)
        .slice(0, 100); // Limit to 100 most recent
    } catch (error) {
      // Failed to load notifications
      if (isMounted) notifications = [];
    }
  }
  
  async function loadInteractionsWithMe(profilePubkey: string, currentUserPubkey: string) {
    if (!isMounted || !currentUserPubkey || currentUserPubkey === profilePubkey) {
      if (isMounted) interactionsWithMe = [];
      return;
    }
    
    try {
      const interactionRelays = relayManager.getFeedResponseReadRelays();
      
      // Fetch current user's posts from cache first (fast) - shorter timeout
      const fetchPromise1 = nostrClient.fetchEvents(
        [{ kinds: [KIND.SHORT_TEXT_NOTE], authors: [currentUserPubkey], limit: config.mediumBatchLimit }],
        interactionRelays,
        { useCache: 'cache-first', cacheResults: true, timeout: config.shortTimeout } // Short timeout for cache
      );
      activeFetchPromises.add(fetchPromise1);
      const currentUserPosts = await fetchPromise1;
      activeFetchPromises.delete(fetchPromise1);
      
      if (!isMounted) return;
      
      const currentUserPostIds = new Set(currentUserPosts.map(p => p.id));
      
      // Only fetch interactions if we have some posts to check against
      if (currentUserPostIds.size === 0) {
        if (isMounted) interactionsWithMe = [];
        return;
      }
      
      // Fetch interactions with cache-first and streaming - shorter timeout
      const fetchPromise2 = nostrClient.fetchEvents(
        [
          { kinds: [KIND.SHORT_TEXT_NOTE], authors: [profilePubkey], '#e': Array.from(currentUserPostIds).slice(0, config.smallBatchLimit), limit: config.smallBatchLimit }, // Limit IDs to avoid huge queries
          { kinds: [KIND.SHORT_TEXT_NOTE], authors: [profilePubkey], '#p': [currentUserPubkey], limit: config.smallBatchLimit }
        ],
        interactionRelays,
        { useCache: 'cache-first', cacheResults: true, timeout: config.shortTimeout } // Shorter timeout for cache-first
      );
      activeFetchPromises.add(fetchPromise2);
      const interactionEvents = await fetchPromise2;
      activeFetchPromises.delete(fetchPromise2);
      
      if (!isMounted) return;
      
      // 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) {
      // Cache error is non-critical
      interactionsWithMe = [];
    }
  }
  

  onMount(async () => {
    await nostrClient.initialize();
    // Initialize tab from URL
    activeTab = getTabFromUrl();
    // 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) {
        // Invalid bech32 format
        return null;
      }
    }
    
    return null;
  }

  /**
   * Get well-known.json URL for a NIP-05 address
   * Uses URL constructor like jumble for proper URL building
   */
  function getNIP05WellKnownUrl(nip05: string): string | null {
    const [localPart, domain] = nip05.split('@');
    if (!localPart || !domain) {
      return null;
    }
    const url = new URL('/.well-known/nostr.json', `https://${domain}`);
    url.searchParams.set('name', localPart);
    return url.toString();
  }

  /**
   * Validate NIP-05 address against well-known.json
   * Uses caching like jumble to avoid repeated lookups
   */
  async function validateNIP05(nip05: string, expectedPubkey: string) {
    // Check cache first
    const cacheKey = `${nip05}:${expectedPubkey}`;
    if (nip05ValidationCache.has(cacheKey)) {
      nip05Validations[nip05] = nip05ValidationCache.get(cacheKey)!;
      return;
    }
    
    nip05Validations[nip05] = null;
    
    try {
      const [localPart, domain] = nip05.split('@');
      if (!localPart || !domain) {
        nip05Validations[nip05] = false;
        nip05ValidationCache.set(cacheKey, false);
        return;
      }

      const url = getNIP05WellKnownUrl(nip05);
      if (!url) {
        nip05Validations[nip05] = false;
        nip05ValidationCache.set(cacheKey, false);
        return;
      }
      
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 5000);
      
      try {
        const response = await fetch(url, {
          method: 'GET',
          headers: { 'Accept': 'application/json' },
          signal: controller.signal
        });

        clearTimeout(timeoutId);

        if (!response.ok) {
          nip05Validations[nip05] = false;
          nip05ValidationCache.set(cacheKey, false);
          return;
        }

        let data;
        try {
          data = await response.json();
        } catch {
          nip05Validations[nip05] = false;
          nip05ValidationCache.set(cacheKey, false);
          return;
        }
        
        const verifiedPubkey = data.names?.[localPart];
        const isValid = verifiedPubkey && typeof verifiedPubkey === 'string' 
          ? verifiedPubkey.toLowerCase() === expectedPubkey.toLowerCase()
          : false;
        
        nip05Validations[nip05] = isValid;
        nip05ValidationCache.set(cacheKey, isValid);
      } catch (fetchError) {
        clearTimeout(timeoutId);
        if (fetchError instanceof Error && fetchError.name === 'AbortError') {
          nip05Validations[nip05] = false;
          nip05ValidationCache.set(cacheKey, false);
        } else {
          throw fetchError;
        }
      }
    } catch (error) {
      nip05Validations[nip05] = false;
      nip05ValidationCache.set(cacheKey, false);
    }
  }

  async function loadProfile() {
    if (!isMounted) return;
    const param = $page.params.pubkey;
    if (!param) {
      // Invalid route parameter
      loading = false;
      profile = null;
      currentLoadPubkey = null;
      return;
    }

    // Decode the parameter to hex pubkey
    const pubkey = decodePubkey(param);
    if (!pubkey) {
      // Invalid pubkey format
      loading = false;
      profile = null;
      currentLoadPubkey = null;
      return;
    }

    // Cancel any previous load for a different pubkey
    if (loadAbortController && currentLoadPubkey !== pubkey) {
      loadAbortController.abort();
      loadAbortController = null;
    }

    // If we're already loading this pubkey, don't start another load
    if (currentLoadPubkey === pubkey && loading) {
      return;
    }

    // Create new abort controller for this load
    const abortController = new AbortController();
    loadAbortController = abortController;
    currentLoadPubkey = pubkey;

    loading = true;
    try {
      // Step 0: Get relays including profile owner's relay lists (non-blocking, with timeout)
      const profileRelaysPromise = getProfileRelaysForPubkey(pubkey);
      
      // Step 1: Load profile and status first (fast from cache) - display immediately
      // fetchProfile uses parseProfile which prioritizes tags over JSON content
      // Use profile owner's relays if available, otherwise fall back to default
      const relaysPromise = profileRelaysPromise.catch(() => relayManager.getProfileReadRelays());
      const relays = await relaysPromise;
      
      const profilePromise = fetchProfile(pubkey, relays);
      const statusPromise = fetchUserStatus(pubkey, relays);
      const statusEventPromise = fetchUserStatusEvent(pubkey, relays);
      activeFetchPromises.add(profilePromise);
      activeFetchPromises.add(statusPromise);
      activeFetchPromises.add(statusEventPromise);
      const [profileData, status, statusEvent] = await Promise.all([profilePromise, statusPromise, statusEventPromise]);
      activeFetchPromises.delete(profilePromise);
      activeFetchPromises.delete(statusPromise);
      activeFetchPromises.delete(statusEventPromise);
      
      // Check if this load was aborted or if pubkey changed
      if (!isMounted || abortController.signal.aborted || currentLoadPubkey !== pubkey) {
        return;
      }
      
      profile = profileData;
      userStatus = status;
      userStatusEvent = statusEvent;
      loading = false; // Show profile immediately, even if posts are still loading
      
      // Validate NIP-05 addresses in background (non-blocking)
      if (profileData?.nip05 && profileData.nip05.length > 0) {
        for (const nip05 of profileData.nip05) {
          validateNIP05(nip05, pubkey).catch(err => {
            // NIP-05 validation failed
            // Ensure state is set even on unhandled errors
            nip05Validations[nip05] = false;
            const cacheKey = `${nip05}:${pubkey}`;
            nip05ValidationCache.set(cacheKey, false);
          });
        }
      }

      // Load pins and notifications/interactions in parallel (non-blocking)
      // Don't wait for these - they'll update the UI as they load
      const loadPromises: Promise<void>[] = [];
      
      // Always load pins (for both own and other profiles)
      loadPromises.push(loadPins(pubkey).catch(() => {
        // Failed to load pins - non-critical
      }));
      
      // Load notifications or interactions based on profile type
      if (isOwnProfile) {
        loadPromises.push(loadNotifications(pubkey).catch(() => {
          // Failed to load notifications - non-critical
        }));
        interactionsWithMe = [];
      } else {
        notifications = [];
        // Load interactions if logged in and viewing another user's profile
        if (currentUserPubkey) {
          loadPromises.push(loadInteractionsWithMe(pubkey, currentUserPubkey).catch(() => {
            // Failed to load interactions - non-critical
          }));
        } else {
          interactionsWithMe = [];
        }
      }
      
      // Wait for initial loads to complete to set default tab
      Promise.all(loadPromises).then(() => {
        if (!isMounted || abortController.signal.aborted || currentLoadPubkey !== pubkey) return;
        
        if (isOwnProfile) {
          // Set default tab: if no pins, default to notifications
          if (pins.length === 0 && notifications.length > 0) {
            activeTab = 'notifications';
          } else if (pins.length > 0) {
            activeTab = 'pins';
          }
        } else {
          // Set default tab to pins if available
          if (pins.length > 0) {
            activeTab = 'pins';
          }
        }
      });
      
      // Load profile event in background (only needed for wall tab)
      // Don't await - load it when user clicks Wall tab
      loadProfileEvent(pubkey).catch(() => {
        // Failed to load profile event - non-critical
      });
    } catch (error) {
      // Only update state if this load wasn't aborted
      if (!abortController.signal.aborted && currentLoadPubkey === pubkey) {
      // Failed to load profile
      loading = false;
      profile = null;
      }
    } finally {
      // Clear load tracking if this was the current load
      if (currentLoadPubkey === pubkey) {
        loadAbortController = null;
        currentLoadPubkey = null;
      }
    }
  }
</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 rounded-full mb-4"
        />
      {/if}
      <h1 class="profile-name 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 userStatusEvent && userStatusEvent.content && userStatusEvent.content.trim()}
        <div class="user-status-content mb-2">
          <MarkdownRenderer content={userStatusEvent.content} event={userStatusEvent} />
        </div>
      {:else if userStatus && userStatus.trim()}
        <p class="text-fog-text-light dark:text-fog-dark-text-light italic mb-2" style="font-size: 0.875em;">
          {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[nip05]}
            {@const wellKnownUrl = getNIP05WellKnownUrl(nip05)}
            <span class="text-fog-text-light dark:text-fog-dark-text-light mr-2" style="font-size: 0.875em;">
              {nip05}
              {#if isValid === true}
                <span class="nip05-valid" title="NIP-05 verified">✓</span>
              {:else if isValid === false}
                {#if wellKnownUrl}
                  <button
                    onclick={() => window.open(wellKnownUrl, '_blank', 'noopener,noreferrer')}
                    class="nip05-invalid-button"
                    title="NIP-05 verification failed - Click to view well-known.json"
                    aria-label="Open well-known.json for verification"
                  >
                    ✗
                  </button>
                {:else}
                  <span class="nip05-invalid" title="NIP-05 verification failed">✗</span>
                {/if}
              {:else}
                <span class="nip05-checking" title="Verifying NIP-05...">⟳</span>
              {/if}
            </span>
          {/each}
        </div>
      {/if}
        
        {#if profilePubkey}
          <div class="profile-npub-section mb-2">
            <div class="npub-display">
              <code class="npub-text">{nip19.npubEncode(profilePubkey)}</code>
              <ProfileMenu pubkey={profilePubkey} />
            </div>
          </div>
        {/if}
      
      <PaymentAddresses pubkey={decodePubkey($page.params.pubkey) || ''} />
    </div>

    <div class="profile-posts">
      <div class="tabs mb-4 flex gap-2 sm:gap-4 border-b border-fog-border dark:border-fog-dark-border overflow-x-auto scrollbar-hide">
        <button
          onclick={() => setActiveTab('pins')}
          class="px-2 sm:px-4 py-2 font-semibold whitespace-nowrap flex-shrink-0 {activeTab === 'pins' ? 'border-b-2 border-fog-accent dark:border-fog-dark-accent' : ''}"
        >
          Pins ({pins.length})
        </button>
        <button
          onclick={() => setActiveTab('wall')}
          class="px-2 sm:px-4 py-2 font-semibold whitespace-nowrap flex-shrink-0 {activeTab === 'wall' ? 'border-b-2 border-fog-accent dark:border-fog-dark-accent' : ''}"
        >
          Wall ({wallComments.length})
        </button>
        {#if isOwnProfile}
        <button
            onclick={() => setActiveTab('notifications')}
            class="px-2 sm:px-4 py-2 font-semibold whitespace-nowrap flex-shrink-0 {activeTab === 'notifications' ? 'border-b-2 border-fog-accent dark:border-fog-dark-accent' : ''}"
        >
            Notifications ({notifications.length})
        </button>
        {:else if currentUserPubkey && currentUserPubkey !== profilePubkey}
          <button
            onclick={() => setActiveTab('interactions')}
            class="px-2 sm:px-4 py-2 font-semibold whitespace-nowrap flex-shrink-0 {activeTab === 'interactions' ? 'border-b-2 border-fog-accent dark:border-fog-dark-accent' : ''}"
          >
            Interactions ({interactionsWithMe.length})
          </button>
        {/if}
      </div>

      {#if activeTab === 'pins'}
        {#if pins.length === 0}
          <p class="text-fog-text-light dark:text-fog-dark-text-light">No pinned posts yet.</p>
        {:else}
          <div class="pins-list">
            {#each pins as pin (pin.id)}
              <FeedPost post={pin} />
            {/each}
              </div>
            {/if}
      {:else if activeTab === 'notifications'}
        {#if notifications.length === 0}
          <p class="text-fog-text-light dark:text-fog-dark-text-light">No notifications yet.</p>
        {:else}
          <div class="notifications-list">
            {#each notifications as notification (notification.id)}
              <FeedPost post={notification} />
            {/each}
          </div>
        {/if}
      {:else if activeTab === 'wall'}
        {#if profileEvent}
          <div class="wall-section">
            {#if sessionManager.isLoggedIn()}
              <div class="wall-form mb-6">
                <h3 class="wall-title mb-4">Write on the Wall</h3>
                <CommentForm
                  threadId={profileEvent.id}
                  rootEvent={profileEvent}
                  onPublished={async () => {
                    // Reload wall comments after publishing
                    if (profileEvent) {
                      await loadWallComments(profileEvent.id);
                    }
                  }}
                />
              </div>
            {:else}
              <p class="text-fog-text-light dark:text-fog-dark-text-light mb-4">Log in to write on the wall</p>
            {/if}
            
            <div class="wall-comments-section">
              <h3 class="wall-title mb-4">Wall Posts</h3>
              {#if loadingWall}
                <p class="text-fog-text-light dark:text-fog-dark-text-light">Loading wall...</p>
              {:else if wallComments.length === 0}
                <p class="text-fog-text-light dark:text-fog-dark-text-light">No wall posts yet. Be the first to write on the wall!</p>
              {:else}
                <div class="wall-comments">
                  {#each wallComments as comment (comment.id)}
                    <CommentComponent
                      comment={comment}
                      rootEventKind={KIND.METADATA}
                    />
                  {/each}
                </div>
              {/if}
            </div>
          </div>
        {:else}
          <p class="text-fog-text-light dark:text-fog-dark-text-light">Loading profile event...</p>
        {/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} />
            {/each}
              </div>
            {/if}
      {/if}
    </div>
  {:else}
    <p class="text-fog-text-light dark:text-fog-dark-text-light">Profile not found</p>
  {/if}
</div>

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

  @media (min-width: 640px) {
    .profile-page {
      padding: 1rem;
    }
  }

  .profile-picture {
    object-fit: cover;
    width: 4rem;
    height: 4rem;
  }

  @media (min-width: 640px) {
    .profile-picture {
      width: 6rem;
      height: 6rem;
    }
  }
  
  .profile-header {
    overflow-wrap: break-word;
    word-break: break-word;
  }
  
  .profile-header h1 {
    overflow-wrap: break-word;
    word-break: break-word;
  }

  .profile-name {
    font-size: 1.5rem;
    line-height: 1.2;
  }

  @media (min-width: 640px) {
    .profile-name {
      font-size: 2rem;
    }
  }
  
  .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-invalid-button {
    color: #ef4444;
    margin-left: 0.25rem;
    font-weight: bold;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    font-size: inherit;
    line-height: inherit;
    transition: opacity 0.2s;
  }
  
  .nip05-invalid-button:hover {
    opacity: 0.7;
    text-decoration: underline;
  }
  
  .nip05-invalid-button:active {
    opacity: 0.5;
  }
  
  .nip05-checking {
    color: #a8b8d0;
    margin-left: 0.25rem;
    display: inline-block;
    animation: spin 1s linear infinite;
  }
  
  @keyframes spin {
    from {
      transform: rotate(0deg);
    }
    to {
      transform: rotate(360deg);
    }
  }

  .profile-npub-section {
    margin-top: 0.5rem;
  }

  .npub-display {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
  }

  .npub-text {
    font-family: monospace;
    font-size: 0.875rem;
    color: var(--fog-text-light, #52667a);
    word-break: break-all;
    padding: 0.25rem 0.5rem;
    background: var(--fog-highlight, #f3f4f6);
    border-radius: 0.25rem;
    border: 1px solid var(--fog-border, #e5e7eb);
  }

  :global(.dark) .npub-text {
    color: var(--fog-dark-text-light, #a8b8d0);
    background: var(--fog-dark-highlight, #374151);
    border-color: var(--fog-dark-border, #475569);
  }

  .wall-section {
    margin-top: 1rem;
  }

  .wall-title {
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--fog-text, #1f2937);
    margin: 0 0 1rem 0;
  }

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

  .wall-form {
    padding: 1rem;
    background: var(--fog-post, #ffffff);
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.375rem;
  }

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

  .wall-comments-section {
    margin-top: 2rem;
  }

  .wall-comments {
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }

  /* Hide scrollbar for tabs on mobile */
  .scrollbar-hide {
    -ms-overflow-style: none;
    scrollbar-width: none;
  }

  .scrollbar-hide::-webkit-scrollbar {
    display: none;
  }

  /* Responsive tabs */
  .tabs {
    scrollbar-width: thin;
    scrollbar-color: var(--fog-border, #e5e7eb) transparent;
  }

  :global(.dark) .tabs {
    scrollbar-color: var(--fog-dark-border, #374151) transparent;
  }

  @media (max-width: 640px) {
    .tabs {
      -webkit-overflow-scrolling: touch;
    }

    .tabs button {
      font-size: 0.875rem;
    }
  }

  /* Responsive profile header */
  @media (max-width: 640px) {
    .profile-header {
      margin-bottom: 1rem;
    }

    .profile-header p {
      font-size: 0.875rem;
    }
  }

  /* Responsive npub display */
  @media (max-width: 640px) {
    .npub-display {
      flex-direction: column;
      align-items: flex-start;
      gap: 0.5rem;
    }

    .npub-text {
      font-size: 0.75rem;
      word-break: break-all;
      max-width: 100%;
    }
  }
</style>