<script lang="ts">
  import filesize from "filesize";
  import { format, fromUnixTime } from "date-fns";
  import type { Readable } from "svelte/store";
  import type { OrderedListing } from "upend/types";
  import Marquee from "../Marquee.svelte";
  import Address from "../Address.svelte";

  export let columns = "attribute, value";
  export let header = true;

  export let attributes: OrderedListing;
  export let editable = false;

  // Display
  $: showEntity = columns.includes("entity");
  $: showAttribute = columns.includes("attribute");
  $: showValue = columns.includes("value");

  // Pagination
  let currentDisplay = 999;
  const MAX_DISPLAY = 50;

  // Editing
  let newEntryAttribute = "'";
  let newEntryValue = "";

  async function addEntry() {
    // this.$emit("edit", {
    //   type: "create",
    //   attribute: this.newEntryAttribute,
    //   value: this.newEntryValue,
    // } as AttributeChange);
    // this.newEntryAttribute = "";
    // this.newEntryValue = "";
  }
  async function removeEntry(addr: string) {
    // if (confirm("Are you sure you want to remove the attribute?")) {
    //   this.$emit("edit", { type: "delete", addr } as AttributeChange);
    // }
  }
  async function updateEntry(addr: string, attribute: string, value: string) {
    // this.$emit("edit", {
    //   type: "update",
    //   addr,
    //   value
    // } as AttributeChange);
    // this.$emit("edit", {
    //   type: "delete",
    //   addr,
    // } as AttributeChange);
    // this.$emit("edit", {
    //   type: "create",
    //   attribute,
    //   value,
    // } as AttributeChange);
  }

  // Sorting
  let resolvedValues: { [key: string]: string } = {};
  $: sortedAttributes = attributes
    .concat()
    .sort(([aHash, _], [bHash, __]) => {
      if (
        resolvedValues[aHash] === undefined ||
        resolvedValues[bHash] === undefined
      ) {
        return 0;
      } else {
        return resolvedValues[aHash].localeCompare(resolvedValues[bHash]);
      }
    })
    .sort(([_, aEntry], [__, bEntry]) => {
      return aEntry.attribute.localeCompare(bEntry.attribute);
    })
    .sort(([_, aEntry], [__, bEntry]) => {
      return aEntry.entity.localeCompare(bEntry.entity);
    });

  // Formatting & Display
  const ATTRIBUTE_LABELS: { [key: string]: string } = {
    FILE_MIME: "MIME type",
    FILE_MTIME: "Last modified",
    FILE_SIZE: "File size",
  };

  const VALUE_FORMATTERS: { [key: string]: (val: string) => string } = {
    FILE_MTIME: (val) => format(fromUnixTime(parseInt(val, 10)), "PPpp"),
    FILE_SIZE: (val) => filesize(parseInt(val, 10), { base: 2 }),
  };

  function formatAttribute(attribute: string) {
    return ATTRIBUTE_LABELS[attribute];
  }

  function formatValue(value: string, attribute: string): string | undefined {
    const handler = VALUE_FORMATTERS[attribute];
    if (handler) {
      return handler(value);
    }
  }

  // Optimizations
  let resolve = [];
</script>

<table>
  <colgroup>
    {#if editable}
      <col class="attr-action-col" />
    {/if}
    {#if showEntity}
      <col class="entity-col" />
    {/if}
    {#if showAttribute}
      <col class="attr-col" />
    {/if}
    {#if showValue}
      <col class="val-col" />
    {/if}
  </colgroup>

  {#if header}
    <tr>
      {#if editable}
        <th />
      {/if}
      {#if showEntity}
        <th>Entity</th>
      {/if}
      {#if showAttribute}
        <th>Attribute</th>
      {/if}
      {#if showValue}
        <th>Value</th>
      {/if}
    </tr>
  {/if}

  {#each sortedAttributes as [id, entry] (id)}
    <tr>
      {#if editable}
        <td class="attr-action">
          <sl-icon-button name="x-circle" on:click={removeEntry(id)} />
        </td>
      {/if}

      {#if showEntity}
        <td>
          <Address link address={entry.entity} />
        </td>
      {/if}

      {#if showAttribute}
        <td class:formatted={Boolean(formatAttribute(entry.attribute))}>
          <Marquee>
            {formatAttribute(entry.attribute) || entry.attribute}
          </Marquee>
        </td>
      {/if}

      {#if showValue}
        <td class="value">
          <text-input
            {editable}
            value={entry.value.c}
            on:edit={(val) => updateEntry(id, entry.attribute, val)}
          >
            {#if entry.value.t === "Address"}
              <Address
                link
                address={entry.value.c}
                resolve={Boolean(resolve[id]) || true}
                on:resolved={(event) => {
                  resolvedValues[id] = event.detail[0];
                }}
              />
            {:else}
              <div
                class:formatted={Boolean(
                  formatValue(entry.value.c, entry.attribute)
                )}
              >
                <Marquee>
                  {formatValue(entry.value.c, entry.attribute) || entry.value.c}
                </Marquee>
              </div>
            {/if}
          </text-input>
        </td>
      {/if}
    </tr>
  {/each}

  {#if attributes.length > currentDisplay}
    <tr>
      <td colspan={editable ? 3 : 2}>
        <sl-button
          class="more-button"
          on:click={(currentDisplay += MAX_DISPLAY)}
        >
          + {attributes.length - currentDisplay} more...
        </sl-button>
      </td>
    </tr>
  {/if}

  {#if editable}
    <tr>
      <td class="attr-action">
        <sl-icon-button name="plus-circle" on:click={addEntry()} />
      </td>
      {#if showAttribute}
        <td>
          <sl-input v-sl-model:newEntryAttribute size="small" />
        </td>
      {/if}
      {#if showValue}
        <td>
          <sl-input v-sl-model:newEntryValue size="small" />
        </td>
      {/if}
    </tr>
  {/if}
</table>

<style lang="scss" scoped>
  table {
    width: 100%;
    table-layout: fixed;

    th {
      text-align: left;
    }

    td {
      font-family: var(--monospace-font);
      padding-right: 1em;
      line-height: 1em;
      line-break: anywhere;

      &.attr-action {
        max-width: 1em;
      }

      .formatted {
        font-family: var(--default-font);
      }
    }

    .attr-action-col {
      width: 1.5em;
    }

    .attr-col {
      width: 33%;
    }

    sl-icon-button {
      &::part(base) {
        padding: 2px;
      }
    }

    .more-button {
      width: 100%;
    }
  }
</style>
