<template>
  <QuickNav selected="Contacts" />
  <TopMessage />

  <!-- CONTENT -->
  <section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
    <!-- Breadcrumb -->
    <div id="ViewBreadcrumb" class="mb-8">
      <h1 class="text-lg text-center font-light relative px-7">
        <!-- Back -->
        <button
          @click="$router.go(-1)"
          class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
        >
          <fa icon="chevron-left" class="fa-fw"></fa>
        </button>
        Identifier Details
      </h1>
    </div>

    <!-- Identity Details -->
    <div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4">
      <div>
        <h2 class="text-xl font-semibold">
          {{
            didInfoForContact(viewingDid, activeDid, contact, allMyDids)
              .displayName
          }}
        </h2>
        <span class="mt-2 text-xl font-semibold break-words">
          {{ viewingDid }}
        </span>
      </div>
      <div class="flex justify-center mt-4">
        <span v-if="contact?.profileImageUrl" class="flex justify-between">
          <EntityIcon
            :icon-size="96"
            :profileImageUrl="contact?.profileImageUrl"
            class="inline-block align-text-bottom border border-slate-300 rounded"
            @click="showLargeIdenticonUrl = contact?.profileImageUrl"
          />
        </span>
      </div>
      <div class="mt-4">
        <div class="flex justify-center">Auto-Generated Icon:</div>
        <div class="flex justify-center">
          <EntityIcon
            :entityId="viewingDid"
            :iconSize="64"
            class="inline-block align-middle border border-slate-300 rounded-md mr-1"
            @click="showLargeIdenticonId = viewingDid"
          />
        </div>
      </div>
      <div
        v-if="showLargeIdenticonId || showLargeIdenticonUrl"
        class="fixed z-[100] top-0 inset-x-0 w-full"
      >
        <div
          class="absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50"
        >
          <EntityIcon
            :entityId="showLargeIdenticonId"
            :iconSize="512"
            :profileImageUrl="showLargeIdenticonUrl"
            class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg"
            @click="
              showLargeIdenticonId = undefined;
              showLargeIdenticonUrl = undefined;
            "
          />
        </div>
      </div>
    </div>

    <!-- Loading Animation -->
    <div
      class="fixed left-6 bottom-24 text-center text-4xl leading-none bg-slate-400 text-white w-14 py-2.5 rounded-full"
      v-if="isLoading"
    >
      <fa icon="spinner" class="fa-spin-pulse"></fa>
    </div>
    <!-- Results List -->
    <div v-if="claims.length > 0" class="mt-4">
      <div class="text-l font-bold text-center">Claims That Involve Them</div>
    </div>
    <InfiniteScroll @reached-bottom="loadMoreData">
      <ul>
        <li
          class="border-b border-slate-300"
          v-for="claim in claims"
          :key="claim.handleId"
        >
          <div class="grid grid-cols-12 gap-4">
            <span class="col-span-2">
              {{ claim.issuedAt.substring(0, 10) }}
            </span>
            <span class="col-span-2">
              {{ capitalizeAndInsertSpacesBeforeCaps(claim.claimType) }}
            </span>
            <span class="col-span-2">
              {{ claimAmount(claim) }}
            </span>
            <span class="col-span-5">
              {{ claimDescription(claim) }}
            </span>
            <span class="col-span-1">
              <a
                @click="onClickLoadClaim(claim.handleId)"
                class="cursor-pointer"
              >
                <fa icon="file-lines" class="pl-2 pt-1 text-blue-500" />
              </a>
            </span>
          </div>
        </li>
      </ul>
    </InfiniteScroll>

    <div
      v-if="!isLoading && claims.length === 0"
      class="flex justify-center mt-4"
    >
      <span>They Are in No Claims Visible to You</span>
    </div>
  </section>
</template>

<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";

import QuickNav from "@/components/QuickNav.vue";
import InfiniteScroll from "@/components/InfiniteScroll.vue";
import TopMessage from "@/components/TopMessage.vue";
import { NotificationIface } from "@/constants/app";
import { accountsDB, db } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import { BoundingBox, MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto";
import {
  capitalizeAndInsertSpacesBeforeCaps,
  didInfoForContact,
  displayAmount,
  GenericCredWrapper,
  GenericVerifiableCredential,
  GiveVerifiableCredential,
  OfferVerifiableCredential,
} from "@/libs/endorserServer";
import EntityIcon from "@/components/EntityIcon.vue";

@Component({
  components: {
    EntityIcon,
    InfiniteScroll,
    QuickNav,
    TopMessage,
  },
})
export default class DIDView extends Vue {
  $notify!: (notification: NotificationIface, timeout?: number) => void;

  activeDid = "";
  allMyDids: Array<string> = [];
  apiServer = "";
  claims: Array<GenericCredWrapper> = [];
  contact?: Contact;
  hitEnd = false;
  isLoading = false;
  searchBox: { name: string; bbox: BoundingBox } | null = null;
  showLargeIdenticonId?: string;
  showLargeIdenticonUrl?: string;
  viewingDid?: string;

  capitalizeAndInsertSpacesBeforeCaps = capitalizeAndInsertSpacesBeforeCaps;
  didInfoForContact = didInfoForContact;
  displayAmount = displayAmount;

  async mounted() {
    await db.open();
    const settings = await db.settings.get(MASTER_SETTINGS_KEY);
    this.activeDid = (settings?.activeDid as string) || "";
    this.apiServer = (settings?.apiServer as string) || "";

    const pathParam = window.location.pathname.substring("/did/".length);
    if (pathParam) {
      this.viewingDid = decodeURIComponent(pathParam);
      this.contact = await db.contacts.get(this.viewingDid);
      await this.loadClaimsAbout();
    } else {
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Error",
          text: "No claim ID was provided.",
        },
        -1,
      );
    }

    await accountsDB.open();
    const allAccounts = await accountsDB.accounts.toArray();
    this.allMyDids = allAccounts.map((acc) => acc.did);
  }

  public async buildHeaders(): Promise<HeadersInit> {
    const headers: HeadersInit = {
      "Content-Type": "application/json",
    };

    if (this.activeDid) {
      await accountsDB.open();
      const allAccounts = await accountsDB.accounts.toArray();
      const account = allAccounts.find((acc) => acc.did === this.activeDid);
      const identity = JSON.parse((account?.identity as string) || "null");

      if (!identity) {
        throw new Error(
          "An ID is chosen but there are no keys for it so it cannot be used to talk with the service. Switch your ID.",
        );
      }

      headers["Authorization"] = "Bearer " + (await accessToken(identity));
    } else {
      // it's OK without auth... we just won't get any identifiers
    }
    return headers;
  }

  /**
   * Data loader used by infinite scroller
   * @param payload is the flag from the InfiniteScroll indicating if it should load
   **/
  async loadMoreData(payload: boolean) {
    if (this.claims.length > 0 && !this.hitEnd && payload) {
      this.loadClaimsAbout();
    }
  }

  public async loadClaimsAbout() {
    if (!this.viewingDid) {
      console.error("This should never be called without a DID.");
      return;
    }

    const queryParams = "claimContents=" + encodeURIComponent(this.viewingDid);
    let postfix = "";
    if (this.claims.length > 0) {
      postfix = "&beforeId=" + this.claims[this.claims.length - 1].id;
    }

    try {
      this.isLoading = true;
      const response = await fetch(
        this.apiServer + "/api/v2/report/claims?" + queryParams + postfix,
        {
          method: "GET",
          headers: await this.buildHeaders(),
        },
      );

      if (response.status !== 200) {
        const details = await response.text();
        console.error("Problem with full search:", details);
        this.$notify(
          {
            group: "alert",
            type: "danger",
            title: "Error",
            text: `There was a problem accessing the server. Try again later.`,
          },
          5000,
        );
        return;
      }

      const results = await response.json();
      this.claims = this.claims.concat(results.data);
      this.hitEnd = !results.hitLimit;

      // eslint-disable-next-line @typescript-eslint/no-explicit-any
    } catch (e: any) {
      console.error("Error with feed load:", e);
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Error",
          text: e.userMessage || "There was a problem retrieving claims.",
        },
        -1,
      );
    } finally {
      this.isLoading = false;
    }
  }

  onClickLoadClaim(jwtId: string) {
    const route = {
      path: "/claim/" + encodeURIComponent(jwtId),
    };
    this.$router.push(route);
  }

  public claimAmount(claim: GenericVerifiableCredential) {
    if (claim.claimType === "GiveAction") {
      const giveClaim = claim.claim as GiveVerifiableCredential;
      if (giveClaim.object?.unitCode && giveClaim.object?.amountOfThisGood) {
        return displayAmount(
          giveClaim.object.unitCode,
          giveClaim.object.amountOfThisGood,
        );
      } else {
        return "";
      }
    } else if (claim.claimType === "Offer") {
      const offerClaim = claim.claim as OfferVerifiableCredential;
      if (
        offerClaim.includesObject?.unitCode &&
        offerClaim.includesObject?.amountOfThisGood
      ) {
        return displayAmount(
          offerClaim.includesObject.unitCode,
          offerClaim.includesObject.amountOfThisGood,
        );
      } else {
        return "";
      }
    }
    return "";
  }

  claimDescription(claim: GenericVerifiableCredential) {
    return claim.claim.name || claim.claim.description || "";
  }
}
</script>
