<script lang="ts">
  import { useEntity } from "../../lib/entity";
  import Spinner from "../utils/Spinner.svelte";
  import FragmentViewer from "./blobs/FragmentViewer.svelte";
  import ModelViewer from "./blobs/ModelViewer.svelte";
  import VideoViewer from "./blobs/VideoViewer.svelte";
  import HashBadge from "./HashBadge.svelte";
  import api from "../../lib/api";
  import { createEventDispatcher } from "svelte";
  import { getTypes } from "../../util/mediatypes";
  import { formatDuration } from "../../util/fragments/time";
  const dispatch = createEventDispatcher();

  export let address: string;
  export let recurse = 3;

  $: ({ entity, entityInfo } = useEntity(address));
  $: types = $entity && getTypes($entity, $entityInfo);

  $: handled =
    types &&
    (!$entity ||
      types.audio ||
      types.video ||
      types.image ||
      types.text ||
      types.model ||
      types.web ||
      types.fragment ||
      (types.group && recurse > 0));

  $: dispatch("handled", handled);

  let loaded = null;
  $: dispatch("loaded", Boolean(loaded));

  let failedChildren: string[] = [];
  let loadedChildren: string[] = [];
  $: groupChildren = ($entity?.attr["HAS"] || [])
    .map((e) => String(e.value.c))
    .filter(
      (addr) =>
        !failedChildren
          .slice(0, ($entity?.attr["HAS"] || []).length - 4)
          .includes(addr)
    )
    .slice(0, 4);

  $: if (groupChildren)
    loaded = groupChildren.every(
      (addr) => loadedChildren.includes(addr) || failedChildren.includes(addr)
    );

  let clientHeight = 0;
  let mediaDuration = "";
  $: {
    let duration = $entity?.get("MEDIA_DURATION") as number | undefined;
    if (duration) {
      mediaDuration = formatDuration(duration);
    }
  }
</script>

<div class="preview">
  {#if handled}
    <div class="inner" bind:clientHeight>
      {#if !loaded}
        <Spinner centered="absolute" />
      {/if}
      {#if types.group}
        <ul class="group">
          {#each groupChildren as address (address)}
            <li>
              <svelte:self
                {address}
                recurse={recurse - 1}
                on:handled={(ev) => {
                  if (!ev.detail && !failedChildren.includes(address))
                    failedChildren = [...failedChildren, address];
                }}
                on:loaded={(ev) => {
                  if (ev.detail && !loadedChildren.includes(address))
                    loadedChildren = [...loadedChildren, address];
                }}
              />
            </li>
          {/each}
        </ul>
      {:else if types.model}
        <ModelViewer
          lookonly
          src="{api.apiUrl}/raw/{address}"
          on:loaded={() => (loaded = address)}
        />
      {:else if types.web}
        <img
          src={String($entity?.get("OG_IMAGE"))}
          alt="OpenGraph image for {$entityInfo?.t == 'Url' && $entityInfo?.c}"
          on:load={() => (loaded = address)}
          on:error={() => (handled = false)}
        />
      {:else if types.fragment}
        <FragmentViewer
          {address}
          detail={false}
          on:loaded={() => (loaded = address)}
        />
      {:else if types.audio}
        <div class="audiopreview image">
          <img
            src="{api.apiUrl}/thumb/{address}?mime=audio"
            alt="Thumbnail for {address}..."
            loading="lazy"
            on:load={() => (loaded = address)}
            on:error={() => (handled = false)}
          />
          {#if mediaDuration}
            <div class="duration" style="--font-size: {clientHeight * 0.66}px">
              {mediaDuration}
            </div>
          {/if}
        </div>
      {:else if types.video}
        <VideoViewer
          {address}
          detail={false}
          on:loaded={() => (loaded = address)}
        />
      {:else}
        <div class="image" class:loaded={loaded == address || !handled}>
          <img
            src="{api.apiUrl}/{types.mimeType?.includes('svg+xml')
              ? 'raw'
              : 'thumb'}/{address}?size=512&quality=75"
            alt="Thumbnail for {address}..."
            loading="lazy"
            on:load={() => (loaded = address)}
            on:error={() => (handled = false)}
          />
        </div>
      {/if}
    </div>
  {:else}
    <div class="hashbadge">
      <HashBadge {address} />
    </div>
  {/if}
</div>

<style lang="scss">
  .preview {
    flex-grow: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;

    .inner {
      display: flex;
      min-height: 0;
    }
  }

  .hashbadge {
    font-size: 48px;
    opacity: 0.25;
    text-align: center;
    line-height: 1;
  }

  .image {
    display: flex;
    min-height: 0;

    justify-content: center;

    img {
      max-width: 100%;
      object-fit: contain;
    }
  }

  .audiopreview {
    position: relative;

    .duration {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);

      font-size: var(--font-size);
      font-weight: bold;
      color: var(--foreground-lightest);
      text-shadow: 0px 0px 0.2em var(--background-lighter);
    }
  }

  .group {
    padding: 0;

    flex-grow: 1;
    min-height: 0;
    width: 100%;

    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(2, 1fr);

    padding: 0.25rem;
    gap: 0.25rem;
    border: 1px solid var(--foreground);
    border-radius: 4px;

    li {
      display: flex;
      flex-direction: column;
      justify-content: end;
      list-style: none;
      min-height: 0;
    }
  }
</style>
