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

  interface Props {
    event: NostrEvent;
  }

  let { event }: Props = $props();
  
  // Track which media items should be loaded
  let loadedMedia = $state<Set<string>>(new Set());
  let mediaRefs = $state<Map<string, HTMLElement>>(new Map());

  interface MediaItem {
    url: string;
    type: 'image' | 'video' | 'audio' | 'file';
    mimeType?: string;
    width?: number;
    height?: number;
    size?: number;
    source: 'image-tag' | 'imeta' | 'file-tag' | 'content';
  }

  function normalizeUrl(url: string): string {
    try {
      const parsed = new URL(url);
      // Remove query params and fragments for comparison
      return `${parsed.protocol}//${parsed.host}${parsed.pathname}`.replace(/\/$/, '');
    } catch {
      return url;
    }
  }

  // Check if a URL appears in the content (as plain URL or in markdown)
  function isUrlInContent(url: string): boolean {
    const normalized = normalizeUrl(url);
    const content = event.content.toLowerCase();
    
    // Check if URL appears as plain text (with or without protocol)
    const urlWithoutProtocol = normalized.replace(/^https?:\/\//i, '');
    if (content.includes(normalized.toLowerCase()) || content.includes(urlWithoutProtocol.toLowerCase())) {
      return true;
    }
    
    // Check if URL appears in markdown image syntax ![alt](url)
    const markdownImageRegex = /!\[.*?\]\((.*?)\)/gi;
    let match;
    while ((match = markdownImageRegex.exec(event.content)) !== null) {
      const markdownUrl = normalizeUrl(match[1]);
      if (markdownUrl === normalized) {
        return true;
      }
    }
    
    // Check if URL appears in HTML img/video/audio tags
    const htmlTagRegex = /<(img|video|audio)[^>]+src=["']([^"']+)["']/gi;
    while ((match = htmlTagRegex.exec(event.content)) !== null) {
      const htmlUrl = normalizeUrl(match[2]);
      if (htmlUrl === normalized) {
        return true;
      }
    }
    
    return false;
  }

  function extractMedia(): MediaItem[] {
    const media: MediaItem[] = [];
    const seen = new Set<string>();

    // 1. Image tag (NIP-23) - cover image
    const imageTag = event.tags.find((t) => t[0] === 'image');
    if (imageTag && imageTag[1]) {
      const normalized = normalizeUrl(imageTag[1]);
      if (!seen.has(normalized)) {
        media.push({
          url: imageTag[1],
          type: 'image',
          source: 'image-tag'
        });
        seen.add(normalized);
      }
    }

    // 2. imeta tags (NIP-92) - only display if NOT already in content
    for (const tag of event.tags) {
      if (tag[0] === 'imeta') {
        let url: string | undefined;
        let mimeType: string | undefined;
        let width: number | undefined;
        let height: number | undefined;

        for (let i = 1; i < tag.length; i++) {
          const item = tag[i];
          if (item.startsWith('url ')) {
            url = item.substring(4).trim();
          } else if (item.startsWith('m ')) {
            mimeType = item.substring(2).trim();
          } else if (item.startsWith('x ')) {
            width = parseInt(item.substring(2).trim(), 10);
          } else if (item.startsWith('y ')) {
            height = parseInt(item.substring(2).trim(), 10);
          }
        }

        if (url) {
          const normalized = normalizeUrl(url);
          // Skip if already displayed in content (imeta is just metadata reference)
          if (isUrlInContent(url)) {
            continue;
          }
          
          if (!seen.has(normalized)) {
            let type: 'image' | 'video' | 'audio' = 'image';
            if (mimeType) {
              if (mimeType.startsWith('video/')) type = 'video';
              else if (mimeType.startsWith('audio/')) type = 'audio';
            }

            media.push({
              url,
              type,
              mimeType,
              width,
              height,
              source: 'imeta'
            });
            seen.add(normalized);
          }
        }
      }
    }

    // 3. file tags (NIP-94)
    for (const tag of event.tags) {
      if (tag[0] === 'file' && tag[1]) {
        const normalized = normalizeUrl(tag[1]);
        if (!seen.has(normalized)) {
          let mimeType: string | undefined;
          let size: number | undefined;

          for (let i = 2; i < tag.length; i++) {
            const item = tag[i];
            if (item && !item.startsWith('size ')) {
              mimeType = item;
            } else if (item.startsWith('size ')) {
              size = parseInt(item.substring(5).trim(), 10);
            }
          }

          media.push({
            url: tag[1],
            type: 'file',
            mimeType,
            size,
            source: 'file-tag'
          });
          seen.add(normalized);
        }
      }
    }

    // 4. Extract from markdown content (images in markdown syntax)
    const imageRegex = /!\[.*?\]\((.*?)\)/g;
    let match;
    while ((match = imageRegex.exec(event.content)) !== null) {
      const url = match[1];
      const normalized = normalizeUrl(url);
      if (!seen.has(normalized)) {
        media.push({
          url,
          type: 'image',
          source: 'content'
        });
        seen.add(normalized);
      }
    }

    // 5. Don't extract plain image URLs from content - let markdown render them inline
    // This ensures images appear where the URL is in the content, not at the top
    // Only extract images from tags (image, imeta, file) which are handled above

    return media;
  }

  const mediaItems = $derived(extractMedia());
  const coverImage = $derived(mediaItems.find((m) => m.source === 'image-tag'));
  const otherMedia = $derived(mediaItems.filter((m) => m.source !== 'image-tag'));

  // Intersection Observer for lazy loading
  let observer: IntersectionObserver | null = $state(null);

  onMount(() => {
    observer = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            const url = entry.target.getAttribute('data-media-url');
            if (url) {
              loadedMedia.add(url);
              // Force reactivity update
              loadedMedia = new Set(loadedMedia);
              observer?.unobserve(entry.target);
            }
          }
        });
      },
      {
        rootMargin: '100px' // Start loading 100px before element is visible
      }
    );

    // Observe all existing placeholders
    $effect(() => {
      if (observer && containerRef) {
        const placeholders = containerRef.querySelectorAll('[data-media-url]');
        placeholders.forEach((placeholder) => {
          if (observer) {
            observer.observe(placeholder);
          }
        });
      }
    });

    return () => {
      observer?.disconnect();
      observer = null;
    };
  });

  let containerRef = $state<HTMLElement | null>(null);

  // Action to set media ref and observe it
  function mediaRefAction(node: HTMLElement, url: string) {
    mediaRefs.set(url, node);
    // Observe the element when it's added
    if (observer) {
      observer.observe(node);
      // Also check if it's already visible (in case IntersectionObserver hasn't fired yet)
      const rect = node.getBoundingClientRect();
      const isVisible = rect.top < window.innerHeight + 100 && rect.bottom > -100;
      if (isVisible) {
        loadedMedia.add(url);
        loadedMedia = new Set(loadedMedia);
        observer.unobserve(node);
      }
    }
    return {
      destroy() {
        if (observer) {
          observer.unobserve(node);
        }
        mediaRefs.delete(url);
      }
    };
  }

  function shouldLoad(url: string): boolean {
    // Always load cover images immediately
    if (coverImage && coverImage.url === url) {
      return true;
    }
    return loadedMedia.has(url);
  }
</script>

<div bind:this={containerRef}>
{#if coverImage}
  <div class="cover-image mb-4">
    {#if shouldLoad(coverImage.url)}
    <img
      src={coverImage.url}
      alt=""
      class="w-full max-h-96 object-cover rounded"
      loading="lazy"
    />
    {:else}
      <div
        class="media-placeholder w-full max-h-96 bg-fog-border dark:bg-fog-dark-border rounded flex items-center justify-center"
        use:mediaRefAction={coverImage.url}
        data-media-url={coverImage.url}
        style="min-height: 200px;"
      >
        <span class="text-fog-text-light dark:text-fog-dark-text-light">Loading image...</span>
      </div>
    {/if}
  </div>
{/if}

{#if otherMedia.length > 0}
  <div class="media-gallery mb-4">
    {#each otherMedia as item}
      {#if item.type === 'image'}
        <div class="media-item">
          {#if shouldLoad(item.url)}
          <img
            src={item.url}
            alt=""
            class="max-w-full rounded"
            loading="lazy"
          />
          {:else}
            <div
              class="media-placeholder bg-fog-border dark:bg-fog-dark-border rounded flex items-center justify-center"
              use:mediaRefAction={item.url}
              data-media-url={item.url}
              style="min-height: 150px; min-width: 150px;"
            >
              <span class="text-fog-text-light dark:text-fog-dark-text-light text-sm">Loading...</span>
            </div>
          {/if}
        </div>
      {:else if item.type === 'video'}
        <div class="media-item">
          {#if shouldLoad(item.url)}
          <video
            src={item.url}
            controls
              preload="none"
            class="max-w-full rounded"
            style="max-height: 500px;"
              autoplay={false}
              muted={false}
          >
            <track kind="captions" />
            Your browser does not support the video tag.
          </video>
          {:else}
            <div
              class="media-placeholder bg-fog-border dark:bg-fog-dark-border rounded flex items-center justify-center"
              use:mediaRefAction={item.url}
              data-media-url={item.url}
              style="min-height: 200px; min-width: 200px;"
            >
              <span class="text-fog-text-light dark:text-fog-dark-text-light">▶️ Video</span>
            </div>
          {/if}
        </div>
      {:else if item.type === 'audio'}
        <div class="media-item">
          {#if shouldLoad(item.url)}
            <audio
              src={item.url}
              controls
              preload="none"
              class="w-full"
              autoplay={false}
            >
            Your browser does not support the audio tag.
          </audio>
          {:else}
            <div
              class="media-placeholder bg-fog-border dark:bg-fog-dark-border rounded flex items-center justify-center"
              use:mediaRefAction={item.url}
              data-media-url={item.url}
              style="min-height: 60px; width: 100%;"
            >
              <span class="text-fog-text-light dark:text-fog-dark-text-light">🎵 Audio</span>
            </div>
          {/if}
        </div>
      {:else if item.type === 'file'}
        <div class="media-item file-item">
          <a
            href={item.url}
            target="_blank"
            rel="noopener noreferrer"
            class="file-link"
          >
            📎 {item.mimeType || 'File'} {item.size ? `(${(item.size / 1024).toFixed(1)} KB)` : ''}
          </a>
        </div>
      {/if}
    {/each}
  </div>
{/if}
</div>

<style>
  .cover-image {
    margin-bottom: 1rem;
  }

  .cover-image img {
    border: 1px solid var(--fog-border, #e5e7eb);
    max-width: 600px;
  }

  :global(.dark) .cover-image img {
    border-color: var(--fog-dark-border, #374151);
  }

  .media-gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 1rem;
    margin-top: 1rem;
  }

  .media-item {
    border: 1px solid var(--fog-border, #e5e7eb);
    border-radius: 0.25rem;
    overflow: hidden;
    background: var(--fog-post, #ffffff);
    padding: 0.5rem;
  }

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

  .media-item img,
  .media-item video {
    max-width: 600px;
    height: auto;
  }

  .file-item {
    padding: 1rem;
  }

  .file-link {
    color: var(--fog-accent, #64748b);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
  }

  .file-link:hover {
    text-decoration: underline;
  }

  .media-placeholder {
    border: 1px solid var(--fog-border, #e5e7eb);
  }

  :global(.dark) .media-placeholder {
    border-color: var(--fog-dark-border, #374151);
  }
</style>
