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

      <!-- Heading -->
      <h1 id="ViewHeading" class="text-4xl text-center font-light pt-4">
        Your Contact Info
      </h1>
      <p
        v-if="!givenName"
        class="bg-amber-200 rounded-md overflow-hidden text-center px-4 py-3 mb-4"
      >
        <span class="text-red">Beware!</span>
        You aren't sharing your name, so quickly
        <router-link
          :to="{ name: 'new-edit-account' }"
          class="bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-1 rounded-md"
        >
          click here to set it for them.
        </router-link>
      </p>
    </div>

    <div @click="onCopyToClipboard()" v-if="activeDid" class="text-center">
      <!--
        Play with display options: https://qr-code-styling.com/
        See docs: https://www.npmjs.com/package/qr-code-generator-vue3
      -->
      <QRCodeVue3
        :value="this.qrValue"
        :cornersSquareOptions="{ type: 'extra-rounded' }"
        :dotsOptions="{ type: 'square' }"
        class="flex justify-center"
      />
      <span> Click that QR to copy your contact URL to your clipboard. </span>
      <div>Not scanning? Show it in pieces.</div>
    </div>
    <div class="text-center" v-else>
      You have no identitifiers yet, so
      <router-link
        :to="{ name: 'start' }"
        class="bg-blue-500 text-white px-1.5 py-1 rounded-md"
      >
        create your identifier.
      </router-link>
      <br />
      If you don't that first, these contacts won't see your activity.
    </div>

    <div class="text-center">
      <h1 class="text-4xl text-center font-light pt-6">Scan Contact Info</h1>
      <qrcode-stream @detect="onScanDetect" @error="onScanError" />
      <span>
        If you do not see a scanning camera window here, check your camera
        permissions.
      </span>
    </div>
  </section>
</template>

<script lang="ts">
import * as didJwt from "did-jwt";
import { sha256 } from "ethereum-cryptography/sha256.js";
import QRCodeVue3 from "qr-code-generator-vue3";
import * as R from "ramda";
import { Component, Vue } from "vue-facing-decorator";
import { QrcodeStream } from "vue-qrcode-reader";
import { useClipboard } from "@vueuse/core";

import { NotificationIface } from "@/constants/app";
import { accountsDB, db } from "@/db/index";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import {
  deriveAddress,
  getContactPayloadFromJwtUrl,
  nextDerivationPath,
  SimpleSigner,
} from "@/libs/crypto";
import QuickNav from "@/components/QuickNav.vue";
import { Account } from "@/db/tables/accounts";
import {
  CONTACT_URL_PREFIX,
  ENDORSER_JWT_URL_LOCATION,
} from "@/libs/endorserServer";
import { Buffer } from "buffer/";

@Component({
  components: {
    QrcodeStream,
    QRCodeVue3,
    QuickNav,
  },
})
export default class ContactQRScanShow extends Vue {
  $notify!: (notification: NotificationIface, timeout?: number) => void;

  activeDid = "";
  apiServer = "";
  givenName = "";
  qrValue = "";

  public async getIdentity(activeDid: string) {
    await accountsDB.open();
    const accounts = await accountsDB.accounts.toArray();
    const account: Account | undefined = R.find(
      (acc) => acc.did === activeDid,
      accounts,
    );
    const identity = JSON.parse(account?.identity || "null");

    if (!identity) {
      throw new Error(
        "Attempted to show contact info with no identifier available.",
      );
    }
    return identity;
  }

  async created() {
    await db.open();
    const settings = await db.settings.get(MASTER_SETTINGS_KEY);
    this.activeDid = settings?.activeDid || "";
    this.apiServer = settings?.apiServer || "";
    this.givenName = settings?.firstName || "";

    await accountsDB.open();
    const accounts = await accountsDB.accounts.toArray();
    const account = R.find((acc) => acc.did === this.activeDid, accounts);
    if (account) {
      const identity = await this.getIdentity(this.activeDid);
      const publicKeyHex = identity.keys[0].publicKeyHex;
      const publicEncKey = Buffer.from(publicKeyHex, "hex").toString("base64");

      const newDerivPath = nextDerivationPath(account.derivationPath);
      const nextPublicHex = deriveAddress(account.mnemonic, newDerivPath)[2];
      const nextPublicEncKey = Buffer.from(nextPublicHex, "hex");
      const nextPublicEncKeyHash = sha256(nextPublicEncKey);
      const nextPublicEncKeyHashBase64 =
        Buffer.from(nextPublicEncKeyHash).toString("base64");

      const contactInfo = {
        iat: Date.now(),
        iss: this.activeDid,
        own: {
          name:
            (settings?.firstName || "") +
            (settings?.lastName ? ` ${settings.lastName}` : ""), // deprecated, pre v 0.1.3
          publicEncKey,
          nextPublicEncKeyHash: nextPublicEncKeyHashBase64,
          profileImageUrl: settings?.profileImageUrl,
        },
      };

      const alg = undefined;
      const privateKeyHex: string = identity.keys[0].privateKeyHex;
      const signer = await SimpleSigner(privateKeyHex);
      // create a JWT for the request
      const vcJwt: string = await didJwt.createJWT(contactInfo, {
        alg: alg,
        issuer: identity.did,
        signer: signer,
      });
      const viewPrefix = CONTACT_URL_PREFIX + ENDORSER_JWT_URL_LOCATION;
      this.qrValue = viewPrefix + vcJwt;
    }
  }

  /**
   *
   * @param content is the result of a QR scan, an array with one item with a rawValue property
   */
  // Unfortunately, there are not typescript definitions for the qrcode-stream component yet.
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  onScanDetect(content: any) {
    const url = content[0]?.rawValue;
    if (url) {
      try {
        const fullData = getContactPayloadFromJwtUrl(url);
        console.log("fullData", fullData);
        localStorage.setItem("contactEndorserUrl", url);
        this.$router.push({ name: "contacts" });
      } catch (e) {
        this.$notify(
          {
            group: "alert",
            type: "warning",
            title: "Invalid Contact QR Code",
            text: "The QR code isn't in the right format.",
          },
          5000,
        );
      }
    } else {
      this.$notify(
        {
          group: "alert",
          type: "warning",
          title: "Invalid Contact QR Code",
          text: "No QR code detected with contact information.",
        },
        5000,
      );
    }
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  onScanError(error: any) {
    console.error("Scan was invalid:", error);
    this.$notify(
      {
        group: "alert",
        type: "warning",
        title: "Invalid Scan",
        text: "The scan was invalid.",
      },
      5000,
    );
  }

  onCopyToClipboard() {
    useClipboard()
      .copy(this.qrValue)
      .then(() => {
        console.log("Contact URL:", this.qrValue);
        this.$notify(
          {
            group: "alert",
            type: "toast",
            title: "Copied",
            text: "Contact URL was copied to clipboard.",
          },
          2000,
        );
      });
  }
}
</script>