<script lang="ts">
  import { createEventDispatcher, getContext } from "svelte";
  import { BLOB_TYPE_ADDR } from "upend/constants";
  import HashBadge from "./HashBadge.svelte";
  import Ellipsis from "../utils/Ellipsis.svelte";
  import UpLink from "./UpLink.svelte";
  import { readable, type Readable } from "svelte/store";
  import { notify, UpNotification } from "../../notifications";
  import IconButton from "../utils/IconButton.svelte";
  import { vaultInfo } from "../../util/info";
  import type { BrowseContext } from "../../util/browse";
  import type { UpObject } from "upend";
  import { i18n } from "../../i18n";
  import type { EntityInfo } from "upend/types";
  import { useEntity } from "../../lib/entity";
  import api from "../../lib/api";
  const dispatch = createEventDispatcher();

  export let address: string;
  export let labels: string[] | undefined = undefined;
  export let link = false;
  export let banner = false;

  let entity: Readable<UpObject> = readable(undefined);
  let entityInfo: Readable<EntityInfo> = readable(undefined);
  $: if (labels === undefined || banner)
    ({ entity, entityInfo } = useEntity(address));

  // isFile
  $: isFile = $entity?.get("IS") === BLOB_TYPE_ADDR;

  // Identification
  let inferredIds: string[] = [];
  $: inferredIds = $entity?.identify() || [];
  $: resolving = inferredIds.concat(labels || []).length == 0 && !$entity;

  let displayLabel = address;
  $: {
    const allLabels = [].concat(inferredIds).concat(labels || []);
    displayLabel = Array.from(new Set(allLabels)).join(" | ");

    if (!displayLabel && $entityInfo?.t === "Attribute") {
      displayLabel = `${$entityInfo.c}`;
    }
    displayLabel = displayLabel || address;
  }

  $: dispatch("resolved", inferredIds);

  // Navigation highlights
  const context = getContext("browse") as BrowseContext | undefined;
  const index = context?.index || undefined;
  const addresses = context?.addresses || readable([]);

  // Native open
  function nativeOpen() {
    notify.emit(
      "notification",
      new UpNotification(
        `Opening ${
          inferredIds[0] || address
        } in a default native application...`
      )
    );
    api
      .nativeOpen(address)
      .then(async (response) => {
        if (!response.ok) {
          throw new Error(`${response.statusText} - ${await response.text()}`);
        }
        if (response.headers.has("warning")) {
          const warningText = response.headers
            .get("warning")
            .split(" ")
            .slice(2)
            .join(" ");
          notify.emit(
            "notification",
            new UpNotification(warningText, "warning")
          );
        }
      })
      .catch((err) => {
        notify.emit(
          "notification",
          new UpNotification(
            `Failed to open in native application! (${err})`,
            "error"
          )
        );
      });
  }
</script>

<div
  class="upobject"
  class:left-active={address == $addresses[$index - 1]}
  class:right-active={address == $addresses[$index + 1]}
>
  <div
    class="address"
    class:identified={inferredIds.length || labels?.length}
    class:banner
  >
    <HashBadge {address} />
    <div class="separator" />
    <div class="label" class:resolving title={displayLabel}>
      {#if banner && isFile}
        <a href="{api.apiUrl}/raw/{address}" download={inferredIds[0]}>
          <Ellipsis value={displayLabel} />
        </a>
      {:else if link}
        <UpLink to={{ entity: address }}>
          <Ellipsis value={displayLabel} />
        </UpLink>
      {:else}
        <Ellipsis value={displayLabel} />
      {/if}
      {#if banner}
        <div class="type">
          {$entityInfo?.t}
          {#if $entityInfo?.t === "Url" || $entityInfo?.t === "Attribute"}
            &mdash; {$entityInfo.c}
          {/if}
        </div>
      {/if}
    </div>
    {#if $vaultInfo?.desktop}
      {#if banner && isFile}
        <div class="icon">
          <IconButton
            name="window-open"
            on:click={nativeOpen}
            title="Open in default application..."
          />
        </div>
      {/if}
    {/if}
  </div>
</div>

<style scoped lang="scss">
  @use "../../styles/colors";

  .upobject {
    border-radius: 4px;

    &.left-active {
      background: linear-gradient(90deg, colors.$orange 0%, transparent 100%);
      padding: 2px 0 2px 2px;
    }

    &.right-active {
      background: linear-gradient(90deg, transparent 0%, colors.$orange 100%);
      padding: 2px 2px 2px 0;
    }
  }

  .address {
    display: flex;
    align-items: center;

    padding: 0.1em 0.25em;

    font-family: var(--monospace-font);
    line-break: anywhere;

    background: var(--background-lighter);
    border: 0.1em solid var(--foreground-lighter);
    border-radius: 0.2em;

    &.banner {
      border: 0.12em solid var(--foreground);
      padding: 0.5em 0.25em;
    }

    &.identified {
      font-family: var(--default-font);
      font-size: 0.95em;
      line-break: auto;
    }

    .type {
      font-size: 0.66em;
      opacity: 0.7;
    }
  }

  .label {
    flex-grow: 1;
    min-width: 0;

    :global(a) {
      text-decoration: none;
    }
  }

  .separator {
    width: 0.5em;
  }

  .icon {
    margin: 0 0.25em;
  }

  .resolving {
    opacity: 0.7;
  }
</style>
