<template>
  <QuickNav />

  <!-- 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">Test</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 v-if="isNotProdServer">
      <h2 class="text-xl font-bold mb-4">User Registration</h2>
      <button :class="primaryButtonClasses" @click="registerMe()">
        Register Yourself
      </button>
      <button :class="primaryButtonClasses" @click="becomeUser0()">
        Become User 0 (who can register others)
      </button>
    </div>

    <div class="mt-8">
      <h2 class="text-xl font-bold mb-4">Notiwind Alerts</h2>

      <!-- Notification test buttons using computed configuration -->
      <button
        v-for="config in notificationTestButtons"
        :key="config.label"
        :class="config.classes"
        @click="triggerTestNotification(config)"
      >
        {{ config.label }}
      </button>
    </div>

    <div class="mt-8">
      <h2 class="text-xl font-bold mb-4">SQL Operations</h2>
      <div class="flex gap-2 mt-2">
        <button :class="sqlLinkClasses" @click="setAllTablesQuery">
          All Tables
        </button>
        <button :class="sqlLinkClasses" @click="setAccountsQuery">
          Accounts
        </button>
        <button :class="sqlLinkClasses" @click="setActiveIdentityQuery">
          Active DID
        </button>
        <button :class="sqlLinkClasses" @click="setContactsQuery">
          Contacts
        </button>
        <button :class="sqlLinkClasses" @click="setSettingsQuery">
          Settings
        </button>
      </div>
      <div>
        <textarea
          v-model="sqlQuery"
          class="w-full h-32 p-2 border border-gray-300 rounded-md font-mono"
          placeholder="Enter your SQL query here..."
        ></textarea>
      </div>
      <div class="mt-4 flex items-center gap-4">
        <button :class="primaryButtonClasses" @click="executeSql">
          Execute
        </button>
        <label class="flex items-center gap-2">
          <input
            v-model="returnRawResults"
            type="checkbox"
            class="rounded border-gray-300"
          />
          <span class="text-sm">Return Raw Results (only raw for queries)</span>
        </label>
      </div>
      <div v-if="sqlResult" class="mt-4">
        <h3 class="text-lg font-semibold mb-2">Result:</h3>
        <pre class="bg-gray-100 p-4 rounded-md overflow-x-auto">{{
          JSON.stringify(sqlResult, null, 2)
        }}</pre>
      </div>
    </div>

    <div class="mt-8">
      <h2 class="text-xl font-bold mb-4">Image Sharing</h2>
      Populates the "shared-photo" view as if they used "share_target".
      <input type="file" data-testId="fileInput" @change="uploadFile" />
      <router-link
        v-if="showFileNextStep()"
        :to="{
          name: 'shared-photo',
          query: { fileName },
        }"
        class="block w-full text-center text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-2 mt-2"
        data-testId="fileUploadButton"
      >
        Go to Shared Page
      </router-link>
    </div>

    <!-- URL Flow Testing Section -->
    <div class="mt-8">
      <h2 class="text-xl font-bold mb-4">URL Flow Testing</h2>
      <p class="text-sm text-gray-600 mb-3">
        Test claim and partner server URL flow from initialization to change
        propagation.
      </p>

      <div class="space-y-4">
        <div class="p-4 border border-gray-300 rounded-md bg-gray-50">
          <h3 class="font-semibold mb-2">Current URL State</h3>
          <div class="space-y-2 text-sm">
            <div>
              <strong>API Server:</strong>
              <span class="font-mono">{{ apiServer || "Not Set" }}</span>
            </div>
            <div>
              <strong>Partner API Server:</strong>
              <span class="font-mono">{{ partnerApiServer || "Not Set" }}</span>
            </div>
            <div>
              <strong>Active DID:</strong>
              <span class="font-mono">{{ activeDid || "Not Set" }}</span>
            </div>
            <div>
              <strong>Platform:</strong>
              <span class="font-mono">{{ getCurrentPlatform() }}</span>
            </div>
          </div>
        </div>

        <div class="space-y-2">
          <button
            :class="primaryButtonClasses"
            :disabled="isUrlTestRunning"
            @click="testUrlFlow()"
          >
            {{ isUrlTestRunning ? "Testing..." : "Test URL Flow" }}
          </button>

          <button :class="secondaryButtonClasses" @click="changeApiServer()">
            Change API Server (Test → Prod)
          </button>

          <button
            :class="secondaryButtonClasses"
            @click="changePartnerApiServer()"
          >
            Change Partner API Server (Test → Prod)
          </button>

          <button :class="warningButtonClasses" @click="resetToDefaults()">
            Reset to Defaults
          </button>

          <button :class="secondaryButtonClasses" @click="refreshSettings()">
            Refresh Settings
          </button>

          <button
            :class="secondaryButtonClasses"
            @click="logEnvironmentState()"
          >
            Log Environment State
          </button>
        </div>

        <div class="p-4 border border-gray-300 rounded-md bg-gray-50">
          <h3 class="font-semibold mb-2">URL Flow Test Results</h3>
          <div class="max-h-64 overflow-y-auto space-y-2">
            <div
              v-for="(result, index) in urlTestResults"
              :key="index"
              class="p-2 border border-gray-200 rounded text-xs font-mono bg-white"
            >
              {{ result }}
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="mt-8">
      <h2 class="text-xl font-bold mb-4">Passkeys</h2>
      See console for results.
      <br />
      See existing passkeys in Chrome at: chrome://settings/passkeys
      <br />
      Active DID: {{ activeDIDDisplay }}
      {{ passkeyStatusDisplay }}

      <div>
        Register Passkey
        <button :class="primaryButtonClasses" @click="registerPasskey()">
          Simplewebauthn
        </button>
      </div>

      <div>
        Create JWT
        <button
          :class="primaryButtonClasses"
          @click="createJwtSimplewebauthn()"
        >
          Simplewebauthn
        </button>
        <button :class="primaryButtonClasses" @click="createJwtNavigator()">
          Navigator
        </button>
      </div>

      <div v-if="jwt">
        Verify New JWT
        <button :class="primaryButtonClasses" @click="verifySimplewebauthn()">
          Simplewebauthn
        </button>
        <button :class="primaryButtonClasses" @click="verifyWebCrypto()">
          WebCrypto
        </button>
        <button :class="primaryButtonClasses" @click="verifyP256()">
          p256 - broken
        </button>
      </div>
      <div v-else>Verify New JWT -- requires creation first</div>
      <button :class="primaryButtonClasses" @click="verifyMyJwt()">
        Verify Hard-Coded JWT
      </button>
    </div>

    <div class="mt-8">
      <h2 class="text-xl font-bold mb-4">Encryption & Decryption</h2>
      See console for more output.
      <div>
        <button
          :class="primaryButtonClasses"
          @click="testMessageEncryptionDecryption()"
        >
          Run Test for Message Encryption/Decryption
        </button>
        {{ encryptionTestResultDisplay }}
      </div>
      <div>
        <button
          :class="primaryButtonClasses"
          @click="testSimpleEncryptionDecryption()"
        >
          Run Test for Simple Encryption/Decryption
        </button>
        {{ simpleEncryptionTestResultDisplay }}
      </div>
    </div>

    <div class="mt-8">
      <h2 class="text-xl font-bold mb-4">Component Tests</h2>
      Interactive tests for Vue components and their functionality.

      <div class="mt-4">
        <h3 class="text-lg font-semibold mb-2">EntityGrid Function Props</h3>
        <p class="text-sm text-gray-600 mb-3">
          Test the new function prop functionality in EntityGrid component.
        </p>
        <button
          :class="primaryButtonClasses"
          @click="showEntityGridTest = !showEntityGridTest"
        >
          {{ showEntityGridTest ? "Hide" : "Show" }} EntityGrid Function Prop
          Test
        </button>

        <div
          v-if="showEntityGridTest"
          class="mt-4 p-4 border border-gray-300 rounded-md bg-gray-50"
        >
          <EntityGridFunctionPropTest />
        </div>
      </div>

      <div class="mt-4">
        <h3 class="text-lg font-semibold mb-2">Platform Service Mixin</h3>
        <p class="text-sm text-gray-600 mb-3">
          Test database operations through PlatformServiceMixin.
        </p>
        <button
          :class="primaryButtonClasses"
          @click="showPlatformServiceTest = !showPlatformServiceTest"
        >
          {{ showPlatformServiceTest ? "Hide" : "Show" }} Platform Service Test
        </button>

        <div
          v-if="showPlatformServiceTest"
          class="mt-4 p-4 border border-gray-300 rounded-md bg-gray-50"
        >
          <PlatformServiceMixinTest />
        </div>
      </div>
    </div>
  </section>
</template>

<script lang="ts">
import { Buffer } from "buffer/";
import { Base64URLString } from "@simplewebauthn/types";
import { ref } from "vue";
import { Component, Vue } from "vue-facing-decorator";
import { Router } from "vue-router";

import QuickNav from "../components/QuickNav.vue";
import { AppString, NotificationIface } from "../constants/app";
import {
  NOTIFY_SQL_ERROR,
  createSqlErrorMessage,
  createPasskeyNameModal,
} from "../constants/notifications";
import * as vcLib from "../libs/crypto/vc";
import * as cryptoLib from "../libs/crypto";

import {
  PeerSetup,
  verifyJwtP256,
  verifyJwtSimplewebauthn,
  verifyJwtWebCrypto,
} from "../libs/crypto/vc/passkeyDidPeer";
import {
  blobToBase64,
  retrieveAccountMetadata,
  registerAndSavePasskey,
  SHARED_PHOTO_BASE64_KEY,
} from "../libs/util";
import { testBecomeUser0, testServerRegisterUser } from "@/test";
import { logger } from "../utils/logger";
import { Account } from "../db/tables/accounts";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import EntityGridFunctionPropTest from "../test/EntityGridFunctionPropTest.vue";
import PlatformServiceMixinTest from "../test/PlatformServiceMixinTest.vue";

const inputFileNameRef = ref<Blob>();

const TEST_PAYLOAD = {
  vc: {
    credentialSubject: {
      "@context": "https://schema.org",
      "@type": "GiveAction",
      description: "pizza",
    },
  },
};

/**
 * TestView Component
 *
 * Development/testing interface providing comprehensive testing tools for:
 * - Notification system testing (8 different types)
 * - Interactive SQL operations and database queries
 * - File upload and image sharing functionality
 * - Passkey registration and JWT verification
 * - Encryption/decryption testing
 * - Various crypto operations
 *
 * Features:
 * - Raw SQL query execution interface for database testing
 * - Notification type demonstrations
 * - Passkey and JWT verification workflows
 * - File upload with temporary storage
 * - Crypto library testing utilities
 *
 * Security Considerations:
 * - Test environment only - not for production use
 * - SQL operations are intentionally raw for testing purposes
 * - File uploads stored temporarily for testing workflows
 *
 * @author Matthew Raymer
 */
@Component({
  components: {
    QuickNav,
    EntityGridFunctionPropTest,
    PlatformServiceMixinTest,
  },
  mixins: [PlatformServiceMixin],
})
export default class Help extends Vue {
  $notify!: (notification: NotificationIface, timeout?: number) => void;
  $router!: Router;

  // for encryption/decryption
  messageEncryptionTestResult?: boolean;
  simpleEncryptionTestResult?: boolean;

  // for file import
  fileName?: string;

  // for passkeys
  credIdHex?: string;
  activeDid?: string;
  apiServer?: string;
  jwt?: string;
  peerSetup?: PeerSetup;
  userName?: string;

  // for SQL operations
  sqlQuery = "";
  sqlResult: unknown = null;
  returnRawResults = false;

  cryptoLib = cryptoLib;

  // for component tests
  showEntityGridTest = false;
  showPlatformServiceTest = false;

  // for URL flow testing
  isUrlTestRunning = false;
  urlTestResults: string[] = [];
  partnerApiServer: string | undefined;

  /**
   * Computed properties for template streamlining
   * Eliminates repeated classes and logic in template
   */

  /**
   * Standard button class for primary actions
   */
  get primaryButtonClasses(): string {
    return "font-bold capitalize bg-slate-500 text-white px-3 py-2 rounded-md mr-2";
  }

  /**
   * Dark button class for primary test actions
   */
  get darkButtonClasses(): string {
    return "font-bold capitalize bg-slate-900 text-white px-3 py-2 rounded-md mr-2";
  }

  /**
   * Secondary button class for secondary test actions
   */
  get secondaryButtonClasses(): string {
    return "font-bold capitalize bg-slate-600 text-white px-3 py-2 rounded-md mr-2";
  }

  /**
   * Success button class for success notifications
   */
  get successButtonClasses(): string {
    return "font-bold capitalize bg-emerald-600 text-white px-3 py-2 rounded-md mr-2";
  }

  /**
   * Warning button class for warning notifications
   */
  get warningButtonClasses(): string {
    return "font-bold capitalize bg-amber-600 text-white px-3 py-2 rounded-md mr-2";
  }

  /**
   * Danger button class for danger notifications
   */
  get dangerButtonClasses(): string {
    return "font-bold capitalize bg-rose-600 text-white px-3 py-2 rounded-md mr-2";
  }

  /**
   * SQL link button class for inline SQL query buttons
   */
  get sqlLinkClasses(): string {
    return "text-sm text-blue-600 hover:text-blue-800 underline";
  }

  /**
   * Formatted display of active DID status
   */
  get activeDIDDisplay(): string {
    return this.activeDid || "nothing, which";
  }

  /**
   * Formatted display of passkey status
   */
  get passkeyStatusDisplay(): string {
    return this.credIdHex ? "has a passkey ID" : "has no passkey ID";
  }

  /**
   * Formatted display of encryption test result
   */
  get encryptionTestResultDisplay(): string {
    return this.messageEncryptionTestResult !== undefined
      ? `Result: ${this.messageEncryptionTestResult}`
      : "Result: Not tested";
  }

  /**
   * Formatted display of simple encryption test result
   */
  get simpleEncryptionTestResultDisplay(): string {
    return this.simpleEncryptionTestResult !== undefined
      ? `Result: ${this.simpleEncryptionTestResult}`
      : "Result: Not tested";
  }

  /**
   * SQL query presets for template buttons
   * Extracts inline SQL assignments from template for better organization
   */
  setAllTablesQuery() {
    this.sqlQuery = "SELECT * FROM sqlite_master WHERE type='table';";
    this.executeSql();
  }

  setAccountsQuery() {
    this.sqlQuery = "SELECT * FROM accounts;";
    this.executeSql();
  }

  setActiveIdentityQuery() {
    this.sqlQuery = "SELECT * FROM active_identity;";
    this.executeSql();
  }

  setContactsQuery() {
    this.sqlQuery = "SELECT * FROM contacts;";
    this.executeSql();
  }

  setSettingsQuery() {
    this.sqlQuery = "SELECT * FROM settings;";
    this.executeSql();
  }

  /**
   * Configuration for notification test buttons
   * Eliminates repetitive notification button definitions in template
   */
  get notificationTestButtons() {
    return [
      {
        label: "Toast",
        classes: this.darkButtonClasses,
        notification: {
          group: "alert",
          type: "toast",
          title: "Toast",
          text: "I'm a toast. Without a timeout, I'm stuck.",
        },
        timeout: 5000,
      },
      {
        label: "Info",
        classes: this.secondaryButtonClasses,
        notification: {
          group: "alert",
          type: "info",
          title: "Information Alert",
          text: "Just wanted you to know.",
        },
        timeout: 5000,
      },
      {
        label: "Success",
        classes: this.successButtonClasses,
        notification: {
          group: "alert",
          type: "success",
          title: "Success Alert",
          text: "Congratulations!",
        },
        timeout: 5000,
      },
      {
        label: "Warning",
        classes: this.warningButtonClasses,
        notification: {
          group: "alert",
          type: "warning",
          title: "Warning Alert",
          text: "You might wanna look at this.",
        },
        timeout: 5000,
      },
      {
        label: "Danger",
        classes: this.dangerButtonClasses,
        notification: {
          group: "alert",
          type: "danger",
          title: "Danger Alert",
          text: "Something terrible has happened!",
        },
        timeout: 5000,
      },
      {
        label: "Notif ON",
        classes: this.secondaryButtonClasses,
        notification: {
          group: "modal",
          type: "notification-permission",
          title: "Notification Permission",
          text: "Enable notifications?",
        },
        timeout: -1,
      },
      {
        label: "Notif MUTE",
        classes: this.secondaryButtonClasses,
        notification: {
          group: "modal",
          type: "notification-mute",
          title: "Notification Settings",
          text: "Notifications muted",
        },
        timeout: -1,
      },
      {
        label: "Notif OFF",
        classes: this.secondaryButtonClasses,
        notification: {
          group: "modal",
          type: "notification-off",
          title: "Notifications",
          text: "Notifications turned off",
        },
        timeout: -1,
      },
    ];
  }

  /**
   * Loads user settings and account information for testing interface
   * Uses PlatformServiceMixin for database access
   */
  async mounted() {
    logger.debug(
      "[TestView] 🚀 Component mounting - starting URL flow tracking",
    );

    // Boot-time logging for initial configuration
    logger.debug("[TestView] 🌍 Boot-time configuration detected:", {
      platform: process.env.VITE_PLATFORM,
      defaultEndorserApiServer: process.env.VITE_DEFAULT_ENDORSER_API_SERVER,
      defaultPartnerApiServer: process.env.VITE_DEFAULT_PARTNER_API_SERVER,
      nodeEnv: process.env.NODE_ENV,
      timestamp: new Date().toISOString(),
    });

    try {
      // Track settings loading
      logger.info("[TestView] 📥 Loading account settings...");
      const settings = await this.$accountSettings();

      // Get activeDid from new active_identity table (ActiveDid migration)
      const activeIdentity = await this.$getActiveIdentity();

      logger.info("[TestView] 📊 Settings loaded:", {
        activeDid: activeIdentity.activeDid,
        apiServer: settings.apiServer,
        partnerApiServer: settings.partnerApiServer,
        isRegistered: settings.isRegistered,
        firstName: settings.firstName,
      });

      // Update component state
      this.activeDid = activeIdentity.activeDid || "";

      this.apiServer = settings.apiServer || "";
      this.partnerApiServer = settings.partnerApiServer || "";
      this.userName = settings.firstName;

      logger.info("[TestView] ✅ Component state updated:", {
        activeDid: this.activeDid,
        apiServer: this.apiServer,
        partnerApiServer: this.partnerApiServer,
      });

      // Load account metadata
      if (this.activeDid) {
        logger.info(
          "[TestView] 🔍 Loading account metadata for DID:",
          this.activeDid,
        );
        const account = await retrieveAccountMetadata(this.activeDid);

        if (account) {
          this.credIdHex = account.passkeyCredIdHex as string;
          logger.info("[TestView] ✅ Account metadata loaded:", {
            did: account.did,
            hasPasskey: !!account.passkeyCredIdHex,
            passkeyId: account.passkeyCredIdHex,
          });
        } else {
          logger.warn(
            "[TestView] ⚠️ No account found for DID:",
            this.activeDid,
          );
          alert("No account found for DID " + this.activeDid);
        }
      }

      logger.info("[TestView] 🎯 Component initialization complete:", {
        activeDid: this.activeDid,
        apiServer: this.apiServer,
        partnerApiServer: this.partnerApiServer,
        hasPasskey: !!this.credIdHex,
        platform: this.getCurrentPlatform(),
      });
    } catch (error) {
      logger.error(
        "[TestView] ❌ Error during component initialization:",
        error,
      );
      this.$notify(
        {
          group: "error",
          type: "error",
          title: "Initialization Error",
          text: `Failed to initialize component: ${error instanceof Error ? error.message : String(error)}`,
        },
        5000,
      );
    }
  }

  /**
   * Checks if running on production server
   *
   * @returns True if not on production server (enables test utilities)
   */
  public isNotProdServer() {
    return this.apiServer !== AppString.PROD_ENDORSER_API_SERVER;
  }

  async registerMe() {
    const response = await testServerRegisterUser();
    if (response.status === 201) {
      alert("Registration successful.");
      this.$router.push({ name: "home" }); // because this page checks for registered status and sets things if it detects a change
    } else {
      logger.error("Registration failure response:", response);
      alert("Registration failed: " + (response.data.error || response.data));
    }
  }

  async becomeUser0() {
    await testBecomeUser0();
    alert("You are now User 0.");
    this.$router.push({ name: "home" }); // because this page checks for registered status and sets things if it detects a change
  }

  /**
   * Method to trigger notification test
   * Centralizes notification testing logic
   */
  triggerTestNotification(config: {
    notification: NotificationIface;
    timeout?: number;
  }) {
    this.$notify(config.notification, config.timeout);
  }

  /**
   * Handles file upload for image sharing tests
   *
   * Processes uploaded files and stores them in temp table for shared photo testing
   * Uses PlatformServiceMixin service methods for temp table operations
   */
  async uploadFile(event: Event) {
    const target = event.target as HTMLInputElement;
    inputFileNameRef.value = target.files?.[0];
    // https://developer.mozilla.org/en-US/docs/Web/API/File
    // ... plus it has a `type` property from my testing
    const file = inputFileNameRef.value;
    if (file != null) {
      const reader = new FileReader();
      reader.onload = async (e) => {
        const data = e.target?.result as ArrayBuffer;
        if (data) {
          const blob = new Blob([new Uint8Array(data)], {
            type: file.type,
          });
          const blobB64 = await blobToBase64(blob);
          this.fileName = (file as File).name;

          // Use service methods for temp table operations
          const temp = await this.$getTemp(SHARED_PHOTO_BASE64_KEY);
          if (temp) {
            await this.$updateEntity("temp", { blobB64 }, "id = ?", [
              SHARED_PHOTO_BASE64_KEY,
            ]);
          } else {
            await this.$insertEntity(
              "temp",
              { id: SHARED_PHOTO_BASE64_KEY, blobB64 },
              ["id", "blobB64"],
            );
          }
        }
      };
      reader.readAsArrayBuffer(file as Blob);
    }
  }

  /**
   * Checks if file upload next step should be shown
   */
  showFileNextStep() {
    return !!inputFileNameRef.value;
  }

  /**
   * Handles passkey registration for testing
   *
   * Creates new passkey with user name or default test name
   * Includes validation and user confirmation workflow
   * Uses notification helpers for consistent messaging
   */
  public async registerPasskey() {
    const DEFAULT_USERNAME = AppString.APP_NAME + " Tester";
    if (!this.userName) {
      const modalConfig = createPasskeyNameModal(
        DEFAULT_USERNAME,
        async () => {
          this.userName = DEFAULT_USERNAME;
        },
        async () => {
          this.$router.push({ name: "new-edit-account" });
        },
      );

      this.$notify(modalConfig, -1);
      return;
    }
    const account = await registerAndSavePasskey(
      AppString.APP_NAME + " - " + this.userName,
    );
    this.activeDid = account.did;
    this.credIdHex = account.passkeyCredIdHex;
  }

  /**
   * Tests message encryption/decryption functionality
   */
  public async testMessageEncryptionDecryption() {
    this.messageEncryptionTestResult =
      await cryptoLib.testMessageEncryptionDecryption();
  }

  /**
   * Tests simple encryption/decryption functionality
   */
  public async testSimpleEncryptionDecryption() {
    this.simpleEncryptionTestResult =
      await cryptoLib.testSimpleEncryptionDecryption();
  }

  /**
   * Creates JWT using SimpleWebAuthn for testing
   */
  public async createJwtSimplewebauthn() {
    const account: Account | undefined = await retrieveAccountMetadata(
      this.activeDid || "",
    );
    if (!vcLib.isFromPasskey(account)) {
      alert(`The DID ${this.activeDid} is not passkey-enabled.`);
      return;
    }
    this.peerSetup = new PeerSetup();
    this.jwt = await this.peerSetup.createJwtSimplewebauthn(
      this.activeDid as string,
      TEST_PAYLOAD,
      this.credIdHex as string,
    );
    logger.log("simple jwt4url", this.jwt);
  }

  /**
   * Creates JWT using Navigator API for testing
   */
  public async createJwtNavigator() {
    const account: Account | undefined = await retrieveAccountMetadata(
      this.activeDid || "",
    );
    if (!vcLib.isFromPasskey(account)) {
      alert(`The DID ${this.activeDid} is not passkey-enabled.`);
      return;
    }
    this.peerSetup = new PeerSetup();
    this.jwt = await this.peerSetup.createJwtNavigator(
      this.activeDid as string,
      TEST_PAYLOAD,
      this.credIdHex as string,
    );
    logger.log("lower jwt4url", this.jwt);
  }

  /**
   * Verifies JWT using P256 algorithm for testing
   */
  public async verifyP256() {
    const decoded = await verifyJwtP256(
      this.activeDid as string,
      this.peerSetup?.authenticatorData as ArrayBuffer,
      this.peerSetup?.challenge as Uint8Array,
      this.peerSetup?.signature as Base64URLString,
    );
    logger.log("decoded", decoded);
  }

  /**
   * Verifies JWT using SimpleWebAuthn for testing
   */
  public async verifySimplewebauthn() {
    const decoded = await verifyJwtSimplewebauthn(
      this.credIdHex as string,
      this.activeDid as string,
      this.peerSetup?.authenticatorData as ArrayBuffer,
      this.peerSetup?.challenge as Uint8Array,
      this.peerSetup?.clientDataJsonBase64Url as Base64URLString,
      this.peerSetup?.signature as Base64URLString,
    );
    logger.log("decoded", decoded);
  }

  /**
   * Verifies JWT using WebCrypto for testing
   */
  public async verifyWebCrypto() {
    const decoded = await verifyJwtWebCrypto(
      this.activeDid as string,
      this.peerSetup?.authenticatorData as ArrayBuffer,
      this.peerSetup?.challenge as Uint8Array,
      this.peerSetup?.signature as Base64URLString,
    );
    logger.log("decoded", decoded);
  }

  /**
   * Verifies hard-coded JWT for testing purposes
   */
  public async verifyMyJwt() {
    const did =
      "did:peer:0zKMFjvUgYrM1hXwDciYHiA9MxXtJPXnRLJvqoMNAKoDLX9pKMWLb3VDsgua1p2zW1xXRsjZSTNsfvMnNyMS7dB4k7NAhFwL3pXBrBXgyYJ9ri";
    const jwt =
      "eyJ0eXAiOiJKV0FOVCIsImFsZyI6IkVTMjU2In0.eyJBdXRoZW50aWNhdGlvbkRhdGFCNjRVUkwiOiJTWllONVlnT2pHaDBOQmNQWkhaZ1c0X2tycm1paGpMSG1Wenp1b01kbDJNRkFBQUFBQSIsIkNsaWVudERhdGFKU09OQjY0VVJMIjoiZXlKMGVYQmxJam9pZDJWaVlYVjBhRzR1WjJWMElpd2lZMmhoYkd4bGJtZGxJam9pWlhsS01sbDVTVFpsZVVwcVkyMVdhMXBYTlRCaFYwWnpWVE5XYVdGdFZtcGtRMGsyWlhsS1FWa3lPWFZrUjFZMFpFTkpOa2x0YURCa1NFSjZUMms0ZG1NeVRtOWFWekZvVEcwNWVWcDVTWE5KYTBJd1pWaENiRWxxYjJsU01td3lXbFZHYW1SSGJIWmlhVWx6U1cxU2JHTXlUbmxoV0VJd1lWYzVkVWxxYjJsalIydzJaVzFGYVdaWU1ITkpiV3hvWkVOSk5rMVVZM2hQUkZVMFRtcHJOVTFEZDJsaFdFNTZTV3B2YVZwSGJHdFBia0pzV2xoSk5rMUljRXhVVlZweFpHeFdibGRZU2s1TlYyaFpaREJTYW1GV2JFbGhWVVUxVkZob1dXUkZjRkZYUnpWVFZFVndNbU5YT1U1VWEwWk1ZakJTVFZkRWJIZFRNREZZVkVkSmVsWnJVbnBhTTFab1RWaEJlV1ZzWTNobFJtaFRZekp3WVZVeFVrOWpNbG95VkZjMVQyVlZNVlJPTWxKRFRrZHpNMVJyUm05U2JtUk5UVE5DV1ZGdVNrTlhSMlExVjFWdk5XTnRhMmxtVVNJc0ltOXlhV2RwYmlJNkltaDBkSEE2THk5c2IyTmhiR2h2YzNRNk9EQTRNQ0lzSW1OeWIzTnpUM0pwWjJsdUlqcG1ZV3h6WlgwIiwiaWF0IjoxNzE4NTg2OTkyLCJpc3MiOiJkaWQ6cGVlcjowektNRmp2VWdZck0xaFh3RGNpWUhpQTlNeFh0SlBYblJMSnZxb01OQUtvRExYOXBLTVdMYjNWRHNndWExcDJ6VzF4WFJzalpTVE5zZnZNbk55TVM3ZEI0azdOQWhGd0wzcFhCckJYZ3lZSjlyaSJ9.MEUCIQDJyCTbMPIFnuBoW3FYnlgtDEIHZ2OrkCEvqVnHU7kJDQIgVxjBjfW1TwQfcSOYwK8Z7AdCWGJlyxtLEsrnPif7caE";
    const pieces = jwt.split(".");
    const payload = JSON.parse(Buffer.from(pieces[1], "base64").toString());
    const authData = Buffer.from(payload["AuthenticationDataB64URL"], "base64");
    const clientJSON = Buffer.from(
      payload["ClientDataJSONB64URL"],
      "base64",
    ).toString();
    const clientData = JSON.parse(clientJSON);
    const challenge = clientData.challenge;
    const signatureB64URL = pieces[2];
    const decoded = await verifyJwtWebCrypto(
      did,
      authData,
      challenge,
      signatureB64URL,
    );
    logger.log("decoded", decoded);
  }

  /**
   * Executes SQL queries for testing database operations
   *
   * Supports both SELECT queries (dbQuery) and other SQL commands (dbExec)
   * Provides interface for testing raw SQL operations
   * Uses PlatformServiceMixin for database access and notification helpers for errors
   * When returnRawResults is true, uses direct platform service methods for unparsed results
   */
  async executeSql() {
    try {
      const isSelect = this.sqlQuery.trim().toLowerCase().startsWith("select");

      if (this.returnRawResults) {
        // Use direct platform service methods for raw, unparsed results
        if (isSelect) {
          this.sqlResult = await this.$dbRawQuery(this.sqlQuery);
        } else {
          this.sqlResult = await this.$exec(this.sqlQuery);
        }
      } else {
        // Use methods that normalize the result objects
        if (isSelect) {
          this.sqlResult = await this.$query(this.sqlQuery);
        } else {
          this.sqlResult = await this.$exec(this.sqlQuery);
        }
      }

      logger.log("Test SQL Result:", this.sqlResult);
    } catch (error) {
      logger.error("Test SQL Error:", error);
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: NOTIFY_SQL_ERROR.title,
          text: createSqlErrorMessage(error),
        },
        5000,
      );
    }
  }

  /**
   * Tests the URL flow from initialization to change propagation.
   * This simulates the flow where a user's DID is set, and then the
   * claim and partner server URLs are updated.
   */
  public async testUrlFlow() {
    this.isUrlTestRunning = true;
    this.urlTestResults = [];

    try {
      logger.debug("[TestView] 🔬 Starting comprehensive URL flow test");
      this.addUrlTestResult("🚀 Starting URL flow test...");

      // Test 1: Current state
      this.addUrlTestResult(`📊 Current State:`);
      this.addUrlTestResult(`  - API Server: ${this.apiServer || "Not Set"}`);
      this.addUrlTestResult(
        `  - Partner API Server: ${this.partnerApiServer || "Not Set"}`,
      );
      this.addUrlTestResult(`  - Active DID: ${this.activeDid || "Not Set"}`);
      this.addUrlTestResult(`  - Platform: ${this.getCurrentPlatform()}`);

      // Test 2: Load fresh settings
      this.addUrlTestResult(`\n📥 Testing Settings Loading:`);
      const startTime = Date.now();
      const settings = await this.$accountSettings();
      const loadTime = Date.now() - startTime;

      this.addUrlTestResult(`  - Settings loaded in ${loadTime}ms`);
      this.addUrlTestResult(
        `  - API Server from settings: ${settings.apiServer || "Not Set"}`,
      );
      this.addUrlTestResult(
        `  - Partner API Server from settings: ${settings.partnerApiServer || "Not Set"}`,
      );

      // Test 3: Database query
      this.addUrlTestResult(`\n💾 Testing Database Query:`);
      const dbStartTime = Date.now();
      const dbResult = await this.$dbQuery(
        "SELECT apiServer, partnerApiServer, activeDid FROM settings WHERE id = ? OR accountDid = ?",
        [1, this.activeDid || ""],
      );
      const dbTime = Date.now() - dbStartTime;

      if (dbResult?.values) {
        this.addUrlTestResult(`  - Database query completed in ${dbTime}ms`);
        this.addUrlTestResult(
          `  - Raw DB values: ${JSON.stringify(dbResult.values)}`,
        );
      } else {
        this.addUrlTestResult(
          `  - Database query failed or returned no results`,
        );
      }

      // Test 4: Environment variables
      this.addUrlTestResult(`\n🌍 Testing Environment Variables:`);
      this.addUrlTestResult(
        `  - VITE_PLATFORM: ${import.meta.env.VITE_PLATFORM || "Not Set"}`,
      );
      this.addUrlTestResult(
        `  - VITE_DEFAULT_ENDORSER_API_SERVER: ${import.meta.env.VITE_DEFAULT_ENDORSER_API_SERVER || "Not Set"}`,
      );
      this.addUrlTestResult(
        `  - VITE_DEFAULT_PARTNER_API_SERVER: ${import.meta.env.VITE_DEFAULT_PARTNER_API_SERVER || "Not Set"}`,
      );

      // Test 5: Constants
      this.addUrlTestResult(`\n📋 Testing App Constants:`);
      this.addUrlTestResult(
        `  - PROD_ENDORSER_API_SERVER: ${AppString.PROD_ENDORSER_API_SERVER}`,
      );
      this.addUrlTestResult(
        `  - PROD_PARTNER_API_SERVER: ${AppString.PROD_PARTNER_API_SERVER}`,
      );

      // Test 6: Change detection
      this.addUrlTestResult(`\n🔄 Testing Change Detection:`);
      const originalApiServer = this.apiServer;
      const originalPartnerServer = this.partnerApiServer;

      // Simulate a change
      this.addUrlTestResult(`  - Original API Server: ${originalApiServer}`);
      this.addUrlTestResult(
        `  - Original Partner Server: ${originalPartnerServer}`,
      );

      // Test 7: Settings update
      this.addUrlTestResult(`\n💾 Testing Settings Update:`);
      const testChanges = {
        apiServer:
          originalApiServer === "https://api.endorser.ch"
            ? "https://test-api.endorser.ch"
            : "https://api.endorser.ch",
      };

      this.addUrlTestResult(
        `  - Attempting to change API Server to: ${testChanges.apiServer}`,
      );
      const updateResult = await this.$saveSettings(testChanges);
      this.addUrlTestResult(
        `  - Update result: ${updateResult ? "Success" : "Failed"}`,
      );

      // Test 8: Verify change propagation
      this.addUrlTestResult(`\n✅ Testing Change Propagation:`);
      const newSettings = await this.$accountSettings();
      this.addUrlTestResult(
        `  - New API Server from settings: ${newSettings.apiServer || "Not Set"}`,
      );
      this.addUrlTestResult(
        `  - Component state API Server: ${this.apiServer || "Not Set"}`,
      );
      this.addUrlTestResult(
        `  - Change propagated: ${newSettings.apiServer === this.apiServer ? "Yes" : "No"}`,
      );

      // Test 9: Revert changes
      this.addUrlTestResult(`\n🔄 Reverting Changes:`);
      const revertResult = await this.$saveSettings({
        apiServer: originalApiServer,
      });
      this.addUrlTestResult(
        `  - Revert result: ${revertResult ? "Success" : "Failed"}`,
      );

      // Test 10: Final verification
      this.addUrlTestResult(`\n🎯 Final Verification:`);
      const finalSettings = await this.$accountSettings();
      this.addUrlTestResult(
        `  - Final API Server: ${finalSettings.apiServer || "Not Set"}`,
      );
      this.addUrlTestResult(
        `  - Matches original: ${finalSettings.apiServer === originalApiServer ? "Yes" : "No"}`,
      );

      this.addUrlTestResult(`\n✅ URL flow test completed successfully!`);
      logger.debug("[TestView] ✅ URL flow test completed successfully");
    } catch (error) {
      const errorMsg = `❌ URL flow test failed: ${error instanceof Error ? error.message : String(error)}`;
      this.addUrlTestResult(errorMsg);
      logger.error("[TestView] ❌ URL flow test failed:", error);
    } finally {
      this.isUrlTestRunning = false;
    }
  }

  /**
   * Adds a result to the URL test results array.
   */
  private addUrlTestResult(message: string) {
    this.urlTestResults.push(message);
  }

  /**
   * Changes the API server to the production URL.
   */
  public changeApiServer() {
    const currentServer = this.apiServer;
    const newServer =
      currentServer === "https://api.endorser.ch"
        ? "https://test-api.endorser.ch"
        : "https://api.endorser.ch";

    logger.info("[TestView] 🔄 Changing API server:", {
      from: currentServer,
      to: newServer,
    });

    this.apiServer = newServer;
    this.addUrlTestResult(
      `API Server changed from ${currentServer} to ${newServer}`,
    );
  }

  /**
   * Changes the partner API server to the production URL.
   */
  public changePartnerApiServer() {
    const currentServer = this.partnerApiServer;
    const newServer =
      currentServer === "https://partner-api.endorser.ch"
        ? "https://test-partner-api.endorser.ch"
        : "https://partner-api.endorser.ch";

    logger.info("[TestView] 🔄 Changing partner API server:", {
      from: currentServer,
      to: newServer,
    });

    this.partnerApiServer = newServer;
    this.addUrlTestResult(
      `Partner API Server changed from ${currentServer} to ${newServer}`,
    );
  }

  /**
   * Resets all URL-related settings to their initial values.
   */
  public resetToDefaults() {
    this.apiServer = AppString.TEST_ENDORSER_API_SERVER;
    this.partnerApiServer = AppString.TEST_PARTNER_API_SERVER;
    this.activeDid = "";
    this.addUrlTestResult("URL Flow Test Results Reset to Defaults.");
  }

  /**
   * Refreshes settings from the database to verify changes.
   */
  public async refreshSettings() {
    try {
      logger.info("[TestView] 🔄 Refreshing settings from database");
      const settings = await this.$accountSettings();

      // Update component state
      this.apiServer = settings.apiServer || "";
      this.partnerApiServer = settings.partnerApiServer || "";

      logger.info("[TestView] ✅ Settings refreshed:", {
        apiServer: this.apiServer,
        partnerApiServer: this.partnerApiServer,
      });

      this.addUrlTestResult(
        `Settings refreshed - API Server: ${this.apiServer}, Partner API Server: ${this.partnerApiServer}`,
      );
    } catch (error) {
      logger.error("[TestView] ❌ Error refreshing settings:", error);
      this.addUrlTestResult(
        `Error refreshing settings: ${error instanceof Error ? error.message : String(error)}`,
      );
    }
  }

  /**
   * Logs the current environment state to the console.
   */
  public logEnvironmentState() {
    logger.info("[TestView] 🌐 Current Environment State:", {
      VITE_PLATFORM: import.meta.env.VITE_PLATFORM,
      VITE_DEFAULT_ENDORSER_API_SERVER: import.meta.env
        .VITE_DEFAULT_ENDORSER_API_SERVER,
      VITE_DEFAULT_PARTNER_API_SERVER: import.meta.env
        .VITE_DEFAULT_PARTNER_API_SERVER,
      NODE_ENV: process.env.NODE_ENV,
      activeDid: this.activeDid,
      apiServer: this.apiServer,
      partnerApiServer: this.partnerApiServer,
    });
    this.$notify({
      group: "info",
      type: "info",
      title: "Environment State Logged",
      text: "Current environment state logged to console.",
    });
  }

  /**
   * Gets the current platform based on the API server.
   */
  public getCurrentPlatform(): string {
    if (this.apiServer?.includes(AppString.PROD_ENDORSER_API_SERVER)) {
      return "Production";
    } else if (this.apiServer?.includes(AppString.TEST_ENDORSER_API_SERVER)) {
      return "Test";
    } else {
      return "Unknown";
    }
  }
}
</script>
