<script lang="ts">
  import AttributeView from "./AttributeView.svelte";
  import { query, useEntity } from "../lib/entity";
  import Address from "./Address.svelte";
  import { UpType } from "../lib/types";
  import BlobPreview from "./BlobPreview.svelte";
  import { setContext } from "svelte";
  import { writable } from "svelte/store";
  import type { UpEntry } from "upend";

  export let address: string;
  export let index: number | undefined;
  export let editable = false;

  let indexStore = writable(index);
  $: $indexStore = index;

  setContext("browse", { index: indexStore });

  $: ({ entity, error, revalidate } = useEntity(address));

  $: allTypeAddresses = ($entity?.attr["IS"] || []).map((attr) => attr.value.c);

  $: allTypeEntries = query(
    () =>
      `(matches (in ${allTypeAddresses
        .map((addr) => `"${addr}"`)
        .join(" ")}) ? ?)`
  ).result;

  let allTypes: { [key: string]: UpType } = {};
  $: {
    allTypes = {};
    ($allTypeEntries?.entries || []).forEach((entry) => {
      if (allTypes[entry.entity] === undefined) {
        allTypes[entry.entity] = new UpType(entry.entity);
      }

      switch (entry.attribute) {
        case "TYPE":
          allTypes[entry.entity].name = String(entry.value.c);
          break;
        case "TYPE_HAS":
          allTypes[entry.entity].attributes.push(String(entry.value.c));
          break;
      }
    });

    allTypes = allTypes;
  }

  let typedAttributes = {} as { [key: string]: UpEntry[] };
  let untypedAttributes = [] as UpEntry[];

  $: {
    typedAttributes = {};
    untypedAttributes = [];

    ($entity?.attributes || []).forEach((entry) => {
      const entryTypes = Object.entries(allTypes).filter(([_, t]) =>
        t.attributes.includes(entry.attribute)
      );
      if (entryTypes.length > 0) {
        entryTypes.forEach(([addr, _]) => {
          if (typedAttributes[addr] == undefined) {
            typedAttributes[addr] = [];
          }
          typedAttributes[addr].push(entry);
        });
      } else {
        untypedAttributes.push(entry);
      }
    });

    typedAttributes = typedAttributes;
    untypedAttributes = untypedAttributes.filter(
      (entry) => !["IS", "LBL"].includes(entry.attribute)
    );
  }
</script>

<div class="inspect">
  <h2>
    {#if $entity}
      <Address banner {address} />
    {/if}
  </h2>
  <BlobPreview {address} />
  {#if !$error}
    <div class="attributes">
      {#each Object.entries(typedAttributes) as [typeAddr, entries] (typeAddr)}
        <AttributeView
          {address}
          {entries}
          type={allTypes[typeAddr]}
          {editable}
          on:changed={revalidate}
        />
      {/each}

      {#if untypedAttributes.length > 0 || editable}
        <AttributeView
          title="Other attributes"
          {editable}
          {address}
          entries={untypedAttributes}
          on:changed={revalidate}
        />
      {/if}

      {#if $entity?.backlinks.length > 0}
        <AttributeView
          title={`Referred to (${$entity.backlinks.length})`}
          {address}
          entries={$entity.backlinks}
          reverse
          on:changed={revalidate}
        />
      {/if}
    </div>
  {:else}
    <div class="error">
      {JSON.stringify($error)}
    </div>
  {/if}
</div>

<style scoped lang="scss">
  .inspect {
    flex: auto;
    display: flex;
    flex-direction: column;
    & > * {
      padding: 0 1rem;
    }
  }

  .attributes {
    flex: auto;
    height: 0; // https://stackoverflow.com/a/14964944
    overflow-y: auto;
  }

  .error {
    color: red;
  }
</style>
