<script lang="ts">
  import { readable, type Readable } from "svelte/store";
  import type { UpListing } from "upend";
  import type { Address } from "upend/types";
  import { query } from "../../lib/entity";
  import BlobPreview from "../display/BlobPreview.svelte";
  import UpLink from "../display/UpLink.svelte";
  import UpObject from "../display/UpObject.svelte";

  export let entities: Address[];
  export let thumbnails = true;
  export let sort = true;

  const deduplicatedEntities = Array.from(new Set(entities));

  let style: "list" | "grid" | "flex" = "grid";

  let clientWidth: number;
  $: style = !thumbnails || clientWidth < 600 ? "list" : "grid";

  // Sorting
  let sortedEntities = deduplicatedEntities || [];

  let sortKeys: { [key: string]: string[] } = {};
  function addSortKeys(key: string, vals: string[], resort = true) {
    if (!sortKeys[key]) {
      sortKeys[key] = [];
    }
    let changed = false;
    vals.forEach((val) => {
      if (!sortKeys[key].includes(val)) {
        changed = true;
        sortKeys[key].push(val);
      }
    });

    if (resort && changed) sortAttributes();
  }

  // Labelling
  let labelListing: Readable<UpListing> = readable(undefined);
  $: {
    const addresses = [];
    deduplicatedEntities.forEach((addr) => {
      if (!addresses.includes(addr)) {
        addresses.push(addr);
      }
    });

    const addressesString = addresses.map((addr) => `@${addr}`).join(" ");

    labelListing = query(`(matches (in ${addressesString}) "LBL" ? )`).result;
  }

  function sortAttributes() {
    if (!sort) return;

    sortedEntities = deduplicatedEntities.concat();

    sortedEntities.sort((a, b) => {
      if (!sortKeys[a]?.length || !sortKeys[b]?.length) {
        if (Boolean(sortKeys[a]?.length) && !sortKeys[b]?.length) {
          return -1;
        } else if (!sortKeys[a]?.length && Boolean(sortKeys[b]?.length)) {
          return 1;
        } else {
          return a.localeCompare(b);
        }
      } else {
        return sortKeys[a][0].localeCompare(sortKeys[b][0], undefined, {
          numeric: true,
        });
      }
    });
  }

  $: {
    if ($labelListing) {
      deduplicatedEntities.forEach((address) => {
        addSortKeys(address, $labelListing.getObject(address).identify());
      });
      sortAttributes();
    }
  }

  sortAttributes();
</script>

<div
  class="gallery style-{style}"
  class:has-thumbnails={thumbnails}
  bind:clientWidth
>
  <div class="header" />
  <div class="items">
    {#each sortedEntities as entity (entity)}
      {#if thumbnails}
        <div class="thumbnail">
          <UpLink to={{ entity }} passthrough>
            <BlobPreview address={entity} />
            <div class="label">
              <UpObject
                address={entity}
                on:resolved={(event) => {
                  addSortKeys(entity, event.detail);
                }}
              />
            </div>
          </UpLink>
        </div>
      {:else}
        <UpObject link address={entity} />
      {/if}
    {/each}
  </div>
</div>

<style lang="scss">
  .thumbnail {
    border: 1px solid var(--foreground-lighter);
    border-radius: 4px;
    padding: 0.25em;
    max-height: 420px;
  }

  .items {
    gap: 4px;
  }

  .gallery.has-thumbnails .items {
    gap: 1rem;
  }

  :global(.gallery.style-grid .items) {
    display: grid;
    grid-template-columns: repeat(4, 1fr);

    .thumbnail {
      height: 256px;
    }
  }

  :global(.gallery.style-flex .items) {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
  }

  :global(.gallery.style-list .items) {
    display: flex;
    flex-direction: column;
    align-items: stretch;
  }

  .thumbnail {
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
  }
</style>
