<script lang="ts">
  /**
   * Media on a status.
   *
   * Sensitive media is blurred rather than hidden so the layout doesn't jump
   * when it's revealed, and the reveal is per-attachment because a single post
   * can mix flagged and unflagged media.
   */
  import type { CustomEmoji, MediaAttachment } from '$lib/api/types'
  import EmojiText from '../common/EmojiText.svelte'

  interface Props {
    attachments: MediaAttachment[]
    emojis?: CustomEmoji[]
    sensitive?: boolean
  }

  let { attachments, emojis, sensitive = false }: Props = $props()

  let revealed = $state<Record<string, boolean>>({})

  function isRevealed(id: string): boolean {
    return !sensitive || revealed[id] === true
  }

  function toggle(id: string): void {
    revealed = { ...revealed, [id]: !revealed[id] }
  }

  /**
   * Ask the browser to decode the first real frame while it loads metadata.
   * The tiny media-fragment seek also makes the video's intrinsic dimensions
   * available before playback on browsers that otherwise leave it at 300×150.
   */
  function videoPreviewUrl(url: string): string {
    const fragment = url.indexOf('#')
    const base = fragment >= 0 ? url.slice(0, fragment) : url
    return `${base}#t=0.001`
  }
</script>

{#if attachments.length > 0}
  <ul class="attachment-list">
    {#each attachments as media (media.id)}
      <li
        class="attachment"
        data-type={media.type}
        data-sensitive={sensitive ? 'true' : 'false'}
        data-revealed={isRevealed(media.id) ? 'true' : 'false'}
      >
        <figure class="attachment-figure">
          {#if media.type === 'video' || media.type === 'gifv'}
            <video
              class="attachment-media"
              src={videoPreviewUrl(media.url)}
              poster={media.preview_url ?? undefined}
              controls
              playsinline
              loop={media.type === 'gifv'}
              preload="metadata"
            >
              <!-- Remote media carries no caption track; declared so the
                   requirement is explicit rather than merely unmet. -->
              <track kind="captions" />
            </video>
          {:else if media.type === 'audio'}
            <audio class="attachment-media attachment-media--audio" src={media.url} controls preload="none"
            ></audio>
          {:else if media.type === 'image'}
            <a href={media.url} target="_blank" rel="noopener noreferrer">
              <img
                class="attachment-media"
                src={media.preview_url ?? media.url}
                alt={media.description ?? ''}
                loading="lazy"
                decoding="async"
              />
            </a>
          {:else}
            <a class="attachment-media attachment-media--file" href={media.url} target="_blank" rel="noopener noreferrer">
              Attachment
            </a>
          {/if}

          {#if media.description}
            <figcaption class="attachment-caption">
              <EmojiText text={media.description} {emojis} />
            </figcaption>
          {/if}
        </figure>

        {#if sensitive}
          <button type="button" class="button button--small attachment-reveal" onclick={() => toggle(media.id)}>
            {isRevealed(media.id) ? 'Hide' : 'Show'} sensitive media
          </button>
        {/if}
      </li>
    {/each}
  </ul>
{/if}
