<template>
  <QuickNav selected="Projects"></QuickNav>
  <!-- CONTENT -->
  <section id="Content" class="p-6 pb-24">
    <!-- 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>
        <!-- Context Menu -->
        <a
          href=""
          class="text-lg text-center px-2 py-1 absolute -right-2 -top-1"
          ><fa icon="ellipsis-vertical" class="fa-fw"></fa
        ></a>

        View Plan
      </h1>
    </div>

    <!-- Project Details -->
    <div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4">
      <div>
        <div class="block pb-4 flex gap-4">
          <div class="flex-none w-16 pt-1">
            <EntityIcon
              :entityId="projectId"
              :iconSize="64"
              class="block border border-slate-300 rounded-md"
            ></EntityIcon>
          </div>

          <div class="overflow-hidden">
            <h2 class="text-xl font-semibold">{{ name }}</h2>
            <div class="text-sm mb-3">
              <div class="truncate"
                ><fa icon="user" class="fa-fw text-slate-400"></fa>
                {{ issuer }}</div
              >
              <div
                ><fa icon="calendar" class="fa-fw text-slate-400"></fa
                >{{ timeSince }}
              </div>
            </div>
          </div>
        </div>

        <div class="text-sm text-slate-500">
          <div v-if="!expanded">
            {{ truncatedDesc }}
            <a v-if="description.length >= truncateLength" @click="expandText"
              >Read More</a
            >
          </div>
          <div v-else>
            {{ description }}
            <a
              @click="collapseText"
              class="uppercase text-xs font-semibold text-slate-700"
              >Read Less</a
            >
          </div>
        </div>
      </div>
      <button
        type="button"
        class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md"
        @click="onEditClick()"
      >
        Edit
      </button>
    </div>

    <div>
      <div v-if="activeDid">
        <button
          @click="openDialog({ name: 'you', did: activeDid })"
          class="text-center text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md"
        >
          I gave...
        </button>
        &horbar; or:
      </div>
      <!-- similar contact selection code is in multiple places -->
      Record a gift from
      <span v-for="contact in allContacts" :key="contact.did">
        <button @click="openDialog(contact)" class="text-blue-500">
          &nbsp;{{ contact.name }}</button
        >,
      </span>
      <span v-if="allContacts.length > 0">&nbsp;or&nbsp;</span>
      <button @click="openDialog()" class="text-blue-500">
        someone not specified
      </button>
    </div>

    <!-- Gifts to & from this -->
    <div class="mt-8 flex justify-around">
      <div>
        <h1 class="text-xl">Given to this Project</h1>
      </div>
      <div>
        <h1 class="text-xl">... and from this Project</h1>
      </div>
    </div>
    <div class="flex justify-around">
      <div class="w-1/2">
        <div v-for="give in givesToThis" :key="give.id">
          <div class="flex justify-between">
            <div class="flex gap-3">
              <div class="flex gap-2">
                <fa icon="user" class="fa-fw text-slate-400"></fa>
                <span>{{
                  didInfo(give.agentDid, activeDid, allMyDids, allContacts)
                }}</span>
              </div>
              <div class="flex gap-2" v-if="give.amount">
                <fa icon="coins" class="fa-fw text-slate-400"></fa>
                <span>{{ give.amount }}</span>
              </div>
              <div class="flex gap-2" v-if="give.description">
                <fa icon="comment" class="fa-fw text-slate-400"></fa>
                <span>{{ give.description }}</span>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="w-1/2">
        <div v-for="give in givesByThis" :key="give.id">
          <div class="flex justify-between">
            <div class="flex gap-3">
              <div class="flex gap-2">
                <fa icon="user" class="fa-fw text-slate-400"></fa>
                <span>{{
                  didInfo(give.agentDid, activeDid, allMyDids, allContacts)
                }}</span>
              </div>
              <div class="flex gap-2" v-if="give.amount">
                <fa icon="coins" class="fa-fw text-slate-400"></fa>
                <span>{{ give.amount }}</span>
              </div>
              <div class="flex gap-2">
                <fa icon="comment" class="fa-fw text-slate-400"></fa>
                <span>{{ give.description }}</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <GiftedDialog
      ref="customDialog"
      @dialog-result="handleDialogResult"
      message="Received from"
    >
    </GiftedDialog>
    <AlertMessage
      :alertTitle="alertTitle"
      :alertMessage="alertMessage"
    ></AlertMessage>
  </section>
</template>

<script lang="ts">
import { AxiosError } from "axios";
import * as moment from "moment";
import { IIdentifier } from "@veramo/core";
import { Component, Vue } from "vue-facing-decorator";

import GiftedDialog from "@/components/GiftedDialog.vue";
import { accountsDB, db } from "@/db";
import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto";
import {
  createAndSubmitGive,
  didInfo,
  GiveServerRecord,
} from "@/libs/endorserServer";
import AlertMessage from "@/components/AlertMessage";
import QuickNav from "@/components/QuickNav";
import EntityIcon from "@/components/EntityIcon";

@Component({
  components: { GiftedDialog, AlertMessage, QuickNav, EntityIcon },
})
export default class ProjectViewView extends Vue {
  activeDid = "";
  alertMessage = "";
  alertTitle = "";
  allMyDids: Array<string> = [];
  allContacts: Array<Contact> = [];
  apiServer = "";
  description = "";
  expanded = false;
  givesToThis: Array<GiveServerRecord> = [];
  givesByThis: Array<GiveServerRecord> = [];
  name = "";
  issuer = "";
  projectId = localStorage.getItem("projectId") || ""; // handle ID
  timeSince = "";
  truncatedDesc = "";
  truncateLength = 40;

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

    await accountsDB.open();
    const accounts = accountsDB.accounts;
    const accountsArr = await accounts?.toArray();
    this.allMyDids = accountsArr.map((acc) => acc.did);
    const account = accountsArr?.find((acc) => acc.did === this.activeDid);
    const identity = JSON.parse(account?.identity || "null");
    this.LoadProject(identity);
  }

  public async getIdentity(activeDid) {
    await accountsDB.open();
    const account = await accountsDB.accounts
      .where("did")
      .equals(activeDid)
      .first();
    const identity = JSON.parse(account?.identity || "null");

    if (!identity) {
      throw new Error(
        "Attempted to load project records with no identity available.",
      );
    }
    return identity;
  }

  public async getHeaders(identity) {
    const token = await accessToken(identity);
    const headers = {
      "Content-Type": "application/json",
      Authorization: "Bearer " + token,
    };
    return headers;
  }

  onEditClick() {
    localStorage.setItem("projectId", this.projectId as string);
    const route = {
      name: "new-edit-project",
    };
    this.$router.push(route);
  }

  // Isn't there a better way to make this available to the template?
  didInfo(did, activeDid, dids, contacts) {
    return didInfo(did, activeDid, dids, contacts);
  }

  expandText() {
    this.expanded = true;
  }

  collapseText() {
    this.expanded = false;
  }

  async LoadProject(identity: IIdentifier) {
    const url =
      this.apiServer +
      "/api/claim/byHandle/" +
      encodeURIComponent(this.projectId);
    const headers = {
      "Content-Type": "application/json",
    };
    if (identity) {
      const token = await accessToken(identity);
      headers["Authorization"] = "Bearer " + token;
    }

    try {
      const resp = await this.axios.get(url, { headers });
      if (resp.status === 200) {
        const startTime = resp.data.startTime;
        if (startTime != null) {
          const eventDate = new Date(startTime);
          const now = moment.now();
          this.timeSince = moment.utc(now).to(eventDate);
        }
        this.issuer = resp.data.issuer;
        this.name = resp.data.claim?.name || "(no name)";
        this.description = resp.data.claim?.description || "(no description)";
        this.truncatedDesc = this.description.slice(0, this.truncateLength);
      } else if (resp.status === 404) {
        // actually, axios throws an error so we never get here
        this.alertMessage = "That project does not exist.";
      }
    } catch (error: unknown) {
      const serverError = error as AxiosError;
      if (serverError.response?.status === 404) {
        this.alertMessage = "That project does not exist.";
      } else {
        this.alertMessage =
          "Something went wrong retrieving that project." +
          " See logs for more info.";
        console.error("Error retrieving project:", serverError.message);
      }
    }

    const givesInUrl =
      this.apiServer +
      "/api/v2/report/givesForPlans?planIds=" +
      encodeURIComponent(JSON.stringify([this.projectId]));
    try {
      const resp = await this.axios.get(givesInUrl, { headers });
      if (resp.status === 200 && resp.data.data) {
        this.givesToThis = resp.data.data;
      } else {
        this.alertMessage = "Failed to retrieve gives to this project.";
      }
    } catch (error: unknown) {
      const serverError = error as AxiosError;
      this.alertMessage =
        "Something went wrong retrieving gives to this project.";
      console.error(
        "Error retrieving gives to this project:",
        serverError.message,
      );
    }

    const givesOutUrl =
      this.apiServer +
      "/api/v2/report/givesProvidedBy?providerId=" +
      encodeURIComponent(this.projectId);
    try {
      const resp = await this.axios.get(givesOutUrl, { headers });
      if (resp.status === 200 && resp.data.data) {
        this.givesByThis = resp.data.data;
      } else {
        this.alertMessage = "Failed to retrieve gives by this project.";
      }
    } catch (error: unknown) {
      const serverError = error as AxiosError;
      this.alertMessage = "Something went wrong retrieving gives by project.";
      console.error(
        "Error retrieving gives by this project:",
        serverError.message,
      );
    }
  }

  openDialog(contact) {
    this.$refs.customDialog.open(contact);
  }

  handleDialogResult(result) {
    if (result.action === "confirm") {
      return new Promise((resolve) => {
        this.recordGive(result.contact?.did, result.description, result.hours);
        resolve();
      });
    } else {
      // action was not "confirm" so do nothing
    }
  }

  /**
   *
   * @param giverDid may be null
   * @param description may be an empty string
   * @param hours may be 0
   */
  async recordGive(giverDid, description, hours) {
    if (!this.activeDid) {
      this.alertTitle = "Error";
      this.alertMessage =
        "You must select an identity before you can record a give.";
      return;
    }

    if (!description && !hours) {
      this.alertTitle = "Error";
      this.alertMessage =
        "You must enter a description or some number of hours.";
      return;
    }

    try {
      const identity = await this.getIdentity(this.activeDid);
      const result = await createAndSubmitGive(
        this.axios,
        this.apiServer,
        identity,
        giverDid,
        this.activeDid,
        description,
        hours,
        this.projectId,
      );

      if (result.status !== 201 || result.data?.error) {
        console.log("Error with give result:", result);
        this.alertTitle = "Error";
        this.alertMessage =
          result.data?.error?.message ||
          "There was an error recording the give.";
      } else {
        this.alertTitle = "Success";
        this.alertMessage = "That gift was recorded.";
      }
    } catch (e) {
      console.log("Error with give caught:", e);
      this.alertTitle = "Error";
      this.alertMessage =
        e.userMessage ||
        e.response?.data?.error?.message ||
        "There was an error recording the give.";
    }
  }
}
</script>