<template>
  <!-- QUICK NAV -->
  <nav id="QuickNav" class="fixed bottom-0 left-0 right-0 bg-slate-200 z-50">
    <ul class="flex text-2xl p-2 gap-2">
      <!-- Home Feed -->
      <li class="basis-1/5 rounded-md text-slate-500">
        <router-link :to="{ name: 'home' }" class="block text-center py-3 px-1"
          ><fa icon="house-chimney" class="fa-fw"></fa
        ></router-link>
      </li>
      <!-- Search -->
      <li class="basis-1/5 rounded-md text-slate-500">
        <router-link
          :to="{ name: 'discover' }"
          class="block text-center py-3 px-1"
          ><fa icon="magnifying-glass" class="fa-fw"></fa
        ></router-link>
      </li>
      <!-- Contacts -->
      <li class="basis-1/5 rounded-md text-slate-500">
        <router-link
          :to="{ name: 'projects' }"
          class="block text-center py-3 px-1"
          ><fa icon="folder-open" class="fa-fw"></fa
        ></router-link>
      </li>
      <!-- Contacts -->
      <li class="basis-1/5 rounded-md text-slate-500">
        <router-link
          :to="{ name: 'contacts' }"
          class="block text-center py-3 px-1"
          ><fa icon="users" class="fa-fw"></fa
        ></router-link>
      </li>
      <!-- Profile -->
      <li class="basis-1/5 rounded-md text-slate-500">
        <router-link
          :to="{ name: 'account' }"
          class="block text-center py-3 px-1"
          ><fa icon="circle-user" class="fa-fw"></fa
        ></router-link>
      </li>
    </ul>
  </nav>

  <section id="Content" class="p-6 pb-24">
    <h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
      Given with {{ contact?.name }}
    </h1>

    <!-- Results List -->
    <div>
      <div class="border-b border-slate-300 flex">
        <div class="w-1/4"></div>
        <div class="w-1/4">from them</div>
        <div class="w-1/4"></div>
        <div class="w-1/4">to them</div>
      </div>
      <div
        class="border-b border-slate-300 flex"
        v-for="record in giveRecords"
        :key="record.id"
      >
        <div class="w-1/4">
          {{ new Date(record.issuedAt).toLocaleString() }}
        </div>
        <div class="w-1/4">
          <span v-if="record.agentDid == contact.did">
            <div class="font-bold">
              {{ record.amount }} {{ record.unit }}
              <span v-if="record.amountConfirmed" class="tooltip">
                <fa icon="circle-check" class="text-green-600 fa-fw ml-1" />
                <span class="tooltiptext">Confirmed</span>
              </span>
              <button v-else class="tooltip" @click="confirm(record)">
                <fa icon="circle" class="text-blue-600 fa-fw ml-1" />
                <span class="tooltiptext">Unconfirmed</span>
              </button>
            </div>
            <br />
            {{ record.description }}
          </span>
        </div>
        <div class="w-1/8">
          <span v-if="record.agentDid == contact.did">
            <fa icon="long-arrow-alt-left" class="text-slate-900 fa-fw ml-1" />
          </span>
          <span v-else>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
            <fa icon="long-arrow-alt-right" class="text-slate-900 fa-fw ml-1" />
          </span>
        </div>
        <div class="w-1/4">
          <span v-if="record.agentDid != contact.did">
            <div class="font-bold">
              {{ record.amount }} {{ record.unit }}
              <span v-if="record.amountConfirmed" class="tooltip">
                <fa icon="circle-check" class="text-green-600 fa-fw ml-1" />
                <span class="tooltiptext">Confirmed</span>
              </span>
              <button v-else class="tooltip" @click="cannotConfirmMessage()">
                <fa icon="circle" class="text-slate-600 fa-fw ml-1" />
                <span class="tooltiptext">Unconfirmed</span>
              </button>
            </div>
            <br />
            {{ record.description }}
          </span>
        </div>
      </div>
    </div>

    <!-- This same popup code is in many files. -->
    <div v-bind:class="computedAlertClassNames()">
      <button
        class="close-button bg-slate-200 w-8 leading-loose rounded-full absolute top-2 right-2"
        @click="onClickClose()"
      >
        <fa icon="xmark"></fa>
      </button>
      <h4 class="font-bold pr-5">{{ alertTitle }}</h4>
      <p>{{ alertMessage }}</p>
    </div>
  </section>
</template>

<script lang="ts">
import * as R from "ramda";
import { Options, Vue } from "vue-class-component";

import { accountsDB, db } from "@/db";
import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken, SimpleSigner } from "@/libs/crypto";
import {
  AgreeVerifiableCredential,
  GiveServerRecord,
  GiveVerifiableCredential,
  SCHEMA_ORG_CONTEXT,
} from "@/libs/endorserServer";
import * as didJwt from "did-jwt";
import { AxiosError } from "axios";

@Options({})
export default class ContactsView extends Vue {
  activeDid = "";
  apiServer = "";
  contact: Contact | null = null;
  giveRecords: Array<GiveServerRecord> = [];

  // 'created' hook runs when the Vue instance is first created
  async created() {
    await db.open();
    const contactDid = this.$route.query.contactDid as string;
    this.contact = (await db.contacts.get(contactDid)) || null;

    const settings = await db.settings.get(MASTER_SETTINGS_KEY);
    this.activeDid = settings?.activeDid || "";
    this.apiServer = settings?.apiServer || "";

    if (this.activeDid && this.contact) {
      this.loadGives(this.activeDid, this.contact);
    }
  }

  async loadGives(activeDid: string, contact: Contact) {
    // only load the private keys temporarily when needed
    await accountsDB.open();
    const accounts = await accountsDB.accounts.toArray();
    const account = R.find((acc) => acc.did === activeDid, accounts);
    const identity = JSON.parse(account?.identity || "null");
    if (!identity) {
      throw new Error("No identity found.");
    }

    // load all the time I have given to them
    try {
      let result = [];

      const url =
        this.apiServer +
        "/api/v2/report/gives?agentDid=" +
        encodeURIComponent(identity.did) +
        "&recipientDid=" +
        encodeURIComponent(contact.did);
      const token = await accessToken(identity);
      const headers = {
        "Content-Type": "application/json",
        Authorization: "Bearer " + token,
      };
      const resp = await this.axios.get(url, { headers });
      if (resp.status === 200) {
        result = resp.data.data;
      } else {
        console.error(
          "Got bad response status & data of",
          resp.status,
          resp.data
        );
        this.alertTitle = "Error With Server";
        this.alertMessage =
          "Got an error retrieving your given time from the server.";
        this.isAlertVisible = true;
      }

      const url2 =
        this.apiServer +
        "/api/v2/report/gives?agentDid=" +
        encodeURIComponent(contact.did) +
        "&recipientDid=" +
        encodeURIComponent(identity.did);
      const token2 = await accessToken(identity);
      const headers2 = {
        "Content-Type": "application/json",
        Authorization: "Bearer " + token2,
      };
      const resp2 = await this.axios.get(url2, { headers: headers2 });
      if (resp2.status === 200) {
        result = R.concat(result, resp2.data.data);
      } else {
        console.error(
          "Got bad response status & data of",
          resp2.status,
          resp2.data
        );
        this.alertTitle = "Error With Server";
        this.alertMessage =
          "Got an error retrieving your given time from the server.";
        this.isAlertVisible = true;
      }

      const sortedResult: Array<GiveServerRecord> = R.sort(
        (a, b) =>
          new Date(b.issuedAt).getTime() - new Date(a.issuedAt).getTime(),
        result
      );
      this.giveRecords = sortedResult;
    } catch (error) {
      this.alertTitle = "Error With Server";
      this.alertMessage = error as string;
      this.isAlertVisible = true;
    }
  }

  async confirm(record: GiveServerRecord) {
    // Make claim
    // I use clone here because otherwise it gets a Proxy object.
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const origClaim: GiveVerifiableCredential = R.clone(record.fullClaim);
    if (record.fullClaim["@context"] == SCHEMA_ORG_CONTEXT) {
      delete origClaim["@context"];
    }
    origClaim["identifier"] = record.handleId;
    const vcClaim: AgreeVerifiableCredential = {
      "@context": SCHEMA_ORG_CONTEXT,
      "@type": "AgreeAction",
      object: origClaim,
    };

    // Make a payload for the claim
    const vcPayload = {
      vc: {
        "@context": ["https://www.w3.org/2018/credentials/v1"],
        type: ["VerifiableCredential"],
        credentialSubject: vcClaim,
      },
    };

    // Create a signature using private key of identity
    await accountsDB.open();
    const accounts = await accountsDB.accounts.toArray();
    const account = R.find((acc) => acc.did === this.activeDid, accounts);
    const identity = JSON.parse(account?.identity || "null");
    if (!identity) {
      throw new Error("No identity found.");
    }
    if (identity.keys[0].privateKeyHex !== null) {
      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
      const privateKeyHex: string = identity.keys[0].privateKeyHex!;
      const signer = await SimpleSigner(privateKeyHex);
      const alg = undefined;
      // Create a JWT for the request
      const vcJwt: string = await didJwt.createJWT(vcPayload, {
        alg: alg,
        issuer: identity.did,
        signer: signer,
      });

      // Make the xhr request payload
      const payload = JSON.stringify({ jwtEncoded: vcJwt });
      const url = this.apiServer + "/api/v2/claim";
      const token = await accessToken(identity);
      const headers = {
        "Content-Type": "application/json",
        Authorization: "Bearer " + token,
      };

      try {
        const resp = await this.axios.post(url, payload, { headers });
        //console.log("Got resp data:", resp.data);
        if (resp.data?.success) {
          record.amountConfirmed = origClaim.object?.amountOfThisGood || 1;
        }
      } catch (error) {
        let userMessage = "There was an error. See logs for more info.";
        const serverError = error as AxiosError;
        if (serverError) {
          if (serverError.message) {
            userMessage = serverError.message; // Info for the user
          } else {
            userMessage = JSON.stringify(serverError.toJSON());
          }
        } else {
          userMessage = error as string;
        }
        // Now set that error for the user to see.
        this.alertTitle = "Error With Server";
        this.alertMessage = userMessage;
        this.isAlertVisible = true;
      }
    }
  }

  cannotConfirmMessage() {
    this.alertTitle = "Not Allowed";
    this.alertMessage = "Only the recipient can confirm final receipt.";
    this.isAlertVisible = true;
  }

  // This same popup code is in many files.
  alertTitle = "";
  alertMessage = "";
  isAlertVisible = false;
  public onClickClose() {
    this.isAlertVisible = false;
    this.alertTitle = "";
    this.alertMessage = "";
  }
  public computedAlertClassNames() {
    return {
      hidden: !this.isAlertVisible,
      "dismissable-alert": true,
      "bg-slate-100": true,
      "p-5": true,
      rounded: true,
      "drop-shadow-lg": true,
      fixed: true,
      "top-3": true,
      "inset-x-3": true,
      "transition-transform": true,
      "ease-in": true,
      "duration-300": true,
    };
  }
}
</script>

<style>
/* Tooltip from https://www.w3schools.com/css/css_tooltip.asp */
/* Tooltip container */
.tooltip {
  position: relative;
  display: inline-block;
  border-bottom: 1px dotted black; /* If you want dots under the hoverable text */
}

/* Tooltip text */
.tooltip .tooltiptext {
  visibility: hidden;
  width: 200px;
  background-color: black;
  color: #fff;
  text-align: center;
  padding: 5px 0;
  border-radius: 6px;

  position: absolute;
  z-index: 1;
}

/* Show the tooltip text when you mouse over the tooltip container */
.tooltip:hover .tooltiptext {
  visibility: visible;
}
.tooltip:hover .tooltiptext-left {
  visibility: visible;
}
</style>
