<script lang="ts">
  import debounce from "lodash/debounce";
  import { type Readable, readable } from "svelte/store";
  import type { UpListing } from "upend";
  import Spinner from "../components/utils/Spinner.svelte";
  import UpEntryDisplay from "../components/display/UpEntry.svelte";
  import UpObjectCard from "../components/display/UpObjectCard.svelte";
  import { useNavigate } from "svelte-navigator";
  import { baseSearch, createLabelled } from "../util/search";
  import { updateTitle } from "../util/title";
  import { query as queryFn } from "../lib/entity";
  import AttributeView from "../components/AttributeView.svelte";
  import api from "../lib/api";
  import Gallery from "../components/widgets/Gallery.svelte";
  import type { Widget } from "src/lib/types";
  import { matchSorter } from "match-sorter";
  const navigate = useNavigate();

  export let query: string;

  let debouncedQuery = "";
  const updateQuery = debounce((query: string) => {
    debouncedQuery = query;
  }, 200);
  $: updateQuery(query);

  $: looksLikeQuery =
    debouncedQuery.startsWith("(") && debouncedQuery.endsWith(")");

  let result: Readable<UpListing> = readable();
  let error: Readable<unknown> = readable();
  $: if (debouncedQuery.length) {
    ({ result, error } = looksLikeQuery
      ? queryFn(debouncedQuery)
      : baseSearch(debouncedQuery));
    exactHits = [];
  }

  $: objects = ($result?.entries || []).filter((e) => e.attribute === "LBL");
  $: sortedObjects = matchSorter(objects, debouncedQuery, {
    keys: ["value.c"],
  });

  let exactHits: string[] = [];
  $: {
    const addressesString = objects.map((e) => `@${e.entity}`).join(" ");
    api.query(`(matches (in ${addressesString}) "LBL" ? )`).then(
      (labelListing) => {
        exactHits = labelListing.entries
          .filter(
            (e) => String(e.value.c).toLowerCase() === query.toLowerCase()
          )
          .map((e) => e.entity);
      }
    );
  }

  async function create() {
    const createdAddress = await createLabelled(query);
    navigate(`/browse/${createdAddress}`);
  }

  $: updateTitle("Search", query);

  const searchWidgets: Widget[] = [
    {
      name: "list-table",
      icon: "list-ul",
      components: [
        {
          component: Gallery,
          props: (entries) => {
            return {
              entities: entries.map((e) => e.entity),
              sort: false,
              thumbnails: false,
            };
          },
        },
      ],
    },
    {
      name: "gallery-view",
      icon: "image",
      components: [
        {
          component: Gallery,
          props: (entries) => {
            return {
              entities: entries.map((e) => e.entity),
              sort: false,
              thumbnails: true,
            };
          },
        },
      ],
    },
  ];
  let lastWidget: string;
</script>

<div>
  {#if !$error}
    {#if !looksLikeQuery}
      <section class="exact">
        {#if exactHits.length}
          <ul>
            {#each exactHits as address}
              <li>
                <UpObjectCard {address} --width="100%" --height="100%" />
              </li>
            {/each}
          </ul>
        {:else}
          <div class="create">
            <div>Create new object?</div>
            <button class="create-object" on:click={create}>"{query}"</button>
          </div>
        {/if}
      </section>
    {/if}
    {#if $result}
      <section class="objects">
        {#if sortedObjects.length}
          <h2>Objects</h2>
          <AttributeView
            --current-background="var(--background)"
            entries={sortedObjects}
            widgets={searchWidgets}
            initialWidget={lastWidget}
            on:widgetSwitched={(ev) => {
              lastWidget = ev.detail;
            }}
          />
        {/if}
      </section>

      <section class="raw">
        {#if $result?.entries.length}
          <h2>Raw results</h2>
          <ul>
            {#each $result.entries as entry}
              <li><UpEntryDisplay {entry} resolve={false} /></li>
            {/each}
          </ul>
        {:else}
          <div class="global">No results found.</div>
        {/if}
      </section>
    {:else}
      <div class="global">
        <Spinner centered />
      </div>
    {/if}
  {:else}
    <div class="error global">
      {$error}
    </div>
  {/if}
</div>

<style lang="scss">
  h2 {
    text-align: center;
  }

  ul {
    list-style: none;
    margin: 0;
    padding: 0;
  }

  .exact {
    margin-top: 1rem;

    ul {
      display: flex;
      gap: 1rem;
      justify-content: center;
      flex-wrap: wrap;

      margin: 0 1rem;
    }

    li {
      width: 14rem;
      height: 8rem;
    }

    .create {
      text-align: center;
    }

    .create-object {
      display: inline-block;
      color: var(--foreground);
      background: var(--background-lighter);
      border: 1px solid var(--foreground);
      border-radius: 4px;
      padding: 0.2em;
      font-size: 1.25em;
      cursor: pointer;
      margin-top: 1rem;
    }
  }

  .objects {
    max-width: 66em;
    margin: auto;
  }

  .raw {
    li {
      margin: 1em auto;
      max-width: 66em;
    }
  }

  .global {
    font-size: 48px;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
</style>
