<template>
  <!-- CONTENT -->
  <section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
    <!-- Sub View Heading -->
    <div id="SubViewHeading" class="flex gap-4 items-start mb-8">
      <h1 class="grow text-xl text-center font-semibold leading-tight">
        Raw Claim
      </h1>

      <!-- Back -->
      <a
        class="order-first text-lg text-center leading-none p-1"
        @click="$router.go(-1)"
      >
        <font-awesome icon="chevron-left" class="block text-center w-[1em]" />
      </a>

      <!-- Help button -->
      <router-link
        :to="{ name: 'help' }"
        class="block ms-auto text-sm text-center text-white bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] p-1.5 rounded-full"
      >
        <font-awesome icon="question" class="block text-center w-[1em]" />
      </router-link>
    </div>

    <div class="flex">
      <textarea v-model="claimStr" rows="20" class="border-2 w-full"></textarea>
    </div>
    <button
      class="block w-full text-center text-lg font-bold uppercase 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-2 py-3 rounded-md"
      @click="submitClaim()"
    >
      Sign &amp; Send
    </button>
  </section>
</template>

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

import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import * as serverUtil from "../libs/endorserServer";
import * as libsUtil from "../libs/util";
import { errorStringForLog } from "../libs/endorserServer";
import { Router, RouteLocationNormalizedLoaded } from "vue-router";
import { logger } from "../utils/logger";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
import { showSeedPhraseReminder } from "@/utils/seedPhraseReminder";

// Type guard for API responses
function isApiResponse(response: unknown): response is AxiosResponse {
  return (
    typeof response === "object" &&
    response !== null &&
    "status" in response &&
    "data" in response
  );
}

// Priority: High | Migrated: 2025-07-06 | Author: Matthew Raymer
//
// MIGRATION DETAILS: Migrated from legacy database utilities + logging to PlatformServiceMixin
// - Replaced legacy logging calls with this.$logAndConsole()
// - Replaced legacy settings retrieval with this.$accountSettings()
// - Removed legacy database and logging imports
//
// TESTING NEEDED: Raw claim editor functionality
// 1. Test basic page load: /claim-add-raw (JSON editor displays)
// 2. Test with sample JSON: /claim-add-raw?claim={"type":"example","data":"test"}
// 3. Test JSON validation (valid/invalid JSON handling)
// 4. Test claim submission functionality
// 5. Test error scenarios: network failure, invalid JSON, server errors
// 6. Verify error logging appears in console and database
// 7. Cross-platform testing: web, mobile, desktop
//
// Test URLs:
// /claim-add-raw (basic editor)
// /claim-add-raw?claim={"type":"test","data":"sample"}

/**
 * View component for adding or editing raw claim data
 * Allows direct JSON editing of claim data with validation and submission
 */
@Component({
  components: { QuickNav },
  mixins: [PlatformServiceMixin],
})
export default class ClaimAddRawView extends Vue {
  $notify!: (notification: NotificationIface, timeout?: number) => void;
  $route!: RouteLocationNormalizedLoaded;
  $router!: Router;

  notify!: ReturnType<typeof createNotifyHelpers>;
  accountIdentityStr: string = "null";
  activeDid = "";
  apiServer = "";
  claimStr = "";

  /**
   * Lifecycle hook that initializes the view
   * Workflow:
   * 1. Retrieves active DID and API server from settings
   * 2. Checks for existing claim data from query params:
   *    - If "claim" param exists: Parses and formats JSON
   *    - If "claimJwtId" param exists: Fetches claim data from API
   * 3. Populates textarea with formatted claim data
   */
  async mounted() {
    this.notify = createNotifyHelpers(this.$notify);

    await this.initializeSettings();
    await this.loadClaimData();
  }

  /**
   * Initialize settings from active account
   */
  private async initializeSettings() {
    const settings = await this.$accountSettings();

    // Get activeDid from active_identity table (single source of truth)
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const activeIdentity = await (this as any).$getActiveIdentity();
    this.activeDid = activeIdentity.activeDid || "";

    this.apiServer = settings.apiServer || "";
  }

  /**
   * Load claim data from query parameters or API
   */
  private async loadClaimData() {
    // Try loading from direct claim parameter
    if (await this.loadClaimFromQueryParam()) return;

    // Try loading from claim JWT ID
    await this.loadClaimFromJwtId();
  }

  /**
   * Attempt to load claim from query parameter
   * @returns true if claim was loaded successfully
   */
  private async loadClaimFromQueryParam(): Promise<boolean> {
    this.claimStr = (this.$route.query["claim"] as string) || "";
    if (!this.claimStr) return false;

    try {
      const veriClaim = JSON.parse(this.claimStr);
      this.claimStr = JSON.stringify(veriClaim, null, 2);
      return true;
    } catch (e) {
      // ignore parse error
      return false;
    }
  }

  /**
   * Load claim data from JWT ID via API
   */
  private async loadClaimFromJwtId() {
    const claimJwtId = (this.$route.query["claimJwtId"] as string) || "";
    if (!claimJwtId) return;

    const urlPath = libsUtil.isGlobalUri(claimJwtId)
      ? "/api/claim/byHandle/"
      : "/api/claim/";
    const url = this.apiServer + urlPath + encodeURIComponent(claimJwtId);

    try {
      const response = await this.fetchClaimData(url);
      this.formatClaimResponse(response, claimJwtId);
    } catch (error: unknown) {
      this.handleClaimError(error);
    }
  }

  /**
   * Fetch claim data from API
   */
  private async fetchClaimData(url: string) {
    const headers = await serverUtil.getHeaders(this.activeDid);
    return await this.axios.get(url, { headers });
  }

  /**
   * Format successful claim response data
   */
  private formatClaimResponse(response: unknown, claimJwtId: string) {
    if (isApiResponse(response) && response.status === 200) {
      const claim = response.data?.claim;
      claim.lastClaimId = serverUtil.stripEndorserPrefix(claimJwtId);
      this.claimStr = JSON.stringify(claim, null, 2);
    } else {
      throw {
        message: "Got an error loading that claim.",
        response: isApiResponse(response)
          ? {
              status: response.status,
              statusText: response.statusText,
            }
          : { status: 0, statusText: "Unknown response type" },
      };
    }
  }

  /**
   * Handle error loading claim data
   */
  private handleClaimError(error: unknown) {
    this.$logAndConsole(
      "Error retrieving claim: " + errorStringForLog(error),
      true,
    );
    this.notify.error("Got an error retrieving claim data.", TIMEOUTS.STANDARD);
  }

  /**
   * Submits the edited claim data
   * Workflow:
   * 1. Parses JSON from textarea
   * 2. Sends to server via createAndSubmitClaim
   * 3. Shows success/error notification
   * @throws Will show error notification if submission fails
   */
  async submitClaim() {
    const fullClaim = JSON.parse(this.claimStr);
    const result = await serverUtil.createAndSubmitClaim(
      fullClaim,
      this.activeDid,
      this.apiServer,
      this.axios,
    );
    if (result.success) {
      this.notify.success("Claim submitted.", TIMEOUTS.LONG);

      // Show seed phrase backup reminder if needed
      try {
        const settings = await this.$accountSettings();
        showSeedPhraseReminder(!!settings.hasBackedUpSeed, this.$notify);
      } catch (error) {
        logger.error("Error checking seed backup status:", error);
      }
    } else {
      logger.error("Got error submitting the claim:", result);
      this.notify.error(
        "There was a problem submitting the claim.",
        TIMEOUTS.LONG,
      );
    }
  }
}
</script>
