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

  <section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
    <!-- 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 class="text-4xl text-center font-light">Invitations</h1>

    <!-- New Project -->
    <button
      v-if="isRegistered"
      class="fixed right-6 top-12 text-center text-4xl leading-none bg-blue-600 text-white w-14 py-2.5 rounded-full"
      @click="createInvite()"
    >
      <fa icon="plus" class="fa-fw"></fa>
    </button>

    <InviteDialog ref="inviteDialog" />

    <!-- Invites Table -->
    <div v-if="invites.length" class="mt-6">
      <table class="min-w-full bg-white">
        <thead>
          <tr>
            <th class="py-2">ID</th>
            <th class="py-2">Notes</th>
            <th class="py-2">Expires At</th>
            <th class="py-2">Redeemed By</th>
          </tr>
        </thead>
        <tbody>
          <tr
            v-for="invite in invites"
            :key="invite.inviteIdentifier"
            class="border-t"
          >
            <td
              class="py-2 text-center text-blue-500"
              @click="copyInviteAndNotify(invite.inviteIdentifier, invite.jwt)"
              title="{{ inviteLink(invite.jwt) }}"
            >
              {{ getTruncatedInviteId(invite.inviteIdentifier) }}
            </td>
            <td class="py-2 text-left" :data-testId="inviteLink(invite.jwt)">
              {{ invite.notes }}
            </td>
            <td class="py-2 text-center">
              {{ invite.expiresAt.substring(0, 10) }}
            </td>
            <td class="py-2 text-center">
              {{ getTruncatedRedeemedBy(invite.redeemedBy) }}
            </td>
            <td>
              <fa
                icon="trash-can"
                class="text-red-600 text-xl ml-2 mr-2 cursor-pointer"
                @click="deleteInvite(invite.inviteIdentifier)"
              />
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    <p v-else class="mt-6 text-center">No invites found.</p>
  </section>
</template>
<script lang="ts">
import axios from "axios";
import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core";

import { db, retrieveSettingsForActiveAccount } from "../db";
import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue";
import InviteDialog from "@/components/InviteDialog.vue";
import { APP_SERVER, NotificationIface } from "@/constants/app";
import { createInviteJwt, getHeaders } from "@/libs/endorserServer";

interface Invite {
  inviteIdentifier: string;
  expiresAt: string;
  jwt: string;
  notes: string;
  redeemedBy: string | null;
}

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

  invites: Invite[] = [];
  activeDid: string = "";
  apiServer: string = "";
  isRegistered: boolean = false;

  async mounted() {
    try {
      await db.open();
      const settings = await retrieveSettingsForActiveAccount();
      this.activeDid = settings.activeDid || "";
      this.apiServer = settings.apiServer || "";
      this.isRegistered = !!settings.isRegistered;

      const headers = await getHeaders(this.activeDid);
      const response = await axios.get(
        this.apiServer + "/api/userUtil/invite",
        { headers },
      );
      this.invites = response.data.data;
    } catch (error) {
      console.error("Error fetching invites:", error);
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Load Error",
          text: "Got an error loading your invites.",
        },
        5000,
      );
    }
  }

  getTruncatedInviteId(inviteId: string): string {
    if (inviteId.length <= 9) return inviteId;
    return `${inviteId.slice(0, 3)}...${inviteId.slice(-3)}`;
  }

  getTruncatedRedeemedBy(redeemedBy: string | null): string {
    if (!redeemedBy) return "";
    if (redeemedBy.length <= 19) return redeemedBy;
    return `${redeemedBy.slice(0, 13)}...${redeemedBy.slice(-3)}`;
  }

  inviteLink(jwt: string): string {
    return APP_SERVER + "/contacts?inviteJwt=" + jwt;
  }
  copyInviteAndNotify(inviteId: string, jwt: string) {
    useClipboard().copy(this.inviteLink(jwt));
    this.$notify(
      {
        group: "alert",
        type: "success",
        title: "Copied",
        text: "Link for invite " + inviteId + " is copied to clipboard.",
      },
      3000,
    );
  }

  lookForErrorAndNotify(error, title, defaultMessage) {
    console.error(title, "-", error);
    let message = defaultMessage;
    if (error.response && error.response.data && error.response.data.error) {
      if (error.response.data.error.message) {
        message = error.response.data.error.message;
      } else {
        message = error.response.data.error;
      }
    }
    this.$notify(
      {
        group: "alert",
        type: "danger",
        title: title,
        text: message,
      },
      5000,
    );
  }

  async createInvite() {
    const inviteIdentifier =
      Math.random().toString(36).substring(2) +
      Math.random().toString(36).substring(2) +
      Math.random().toString(36).substring(2);
    (this.$refs.inviteDialog as InviteDialog).open(
      inviteIdentifier,
      async (notes, expiresAt) => {
        try {
          const headers = await getHeaders(this.activeDid);
          if (!expiresAt) {
            throw {
              response: {
                data: { error: "You must select an expiration date." },
              },
            };
          }
          const expiresIn = (new Date(expiresAt).getTime() - Date.now()) / 1000;
          const inviteJwt = await createInviteJwt(
            this.activeDid,
            undefined,
            inviteIdentifier,
            expiresIn,
          );
          await axios.post(
            this.apiServer + "/api/userUtil/invite",
            { inviteJwt: inviteJwt, notes: notes },
            { headers },
          );
          this.invites.push({
            inviteIdentifier: inviteIdentifier,
            expiresAt: expiresAt,
            jwt: inviteJwt,
            notes: notes,
            redeemedBy: null,
          });
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
        } catch (error: any) {
          this.lookForErrorAndNotify(
            error,
            "Error Creating Invite",
            "Got an error creating your invite.",
          );
        }
      },
    );
  }

  deleteInvite(inviteId: string) {
    this.$notify(
      {
        group: "modal",
        type: "confirm",
        title: "Delete Invite?",
        text: "Are you sure you want to erase this invite? (There is no undo.)",
        onYes: async () => {
          const headers = await getHeaders(this.activeDid);
          try {
            const result = await axios.delete(
              this.apiServer + "/api/userUtil/invite/" + inviteId,
              { headers },
            );
            if (result.status !== 204) {
              throw result.data;
            }
            this.invites = this.invites.filter(
              (invite) => invite.inviteIdentifier !== inviteId,
            );
            this.$notify(
              {
                group: "alert",
                type: "success",
                title: "Deleted",
                text: "Invite deleted.",
              },
              3000,
            );
          } catch (e) {
            this.lookForErrorAndNotify(
              e,
              "Error Deleting Invite",
              "Got an error deleting your invite.",
            );
          }
        },
      },
      -1,
    );
  }
}
</script>