<script lang="ts">
  import { push } from "svelte-spa-router";
  import { hexToBytes } from "@noble/hashes/utils";
  import { identityFromSeed, signRegistration } from "../lib/kez.js";
  import {
    seedFromMnemonic,
    isValidMnemonic,
  } from "../lib/mnemonic.js";
  import { healthz, lookupByPrimary, ApiError } from "../lib/api.js";
  import { saveIdentity } from "../lib/identity-store.js";
  import { session } from "../lib/store.svelte.js";
  import { onMount } from "svelte";

  /** User pastes either a 12-word phrase OR a 64-char hex seed. */
  let secretInput = $state("");
  let passphrase = $state("");
  let passphrase2 = $state("");
  let serverDomain = $state<string | null>(null);
  let error = $state<string | null>(null);
  let working = $state(false);

  onMount(async () => {
    try {
      const h = await healthz();
      serverDomain = h.server;
    } catch {
      /* will surface below */
    }
  });

  /** Auto-detect: hex-seed if 64 hex chars, otherwise treat as mnemonic. */
  function parseSecret(raw: string): { seed: Uint8Array; phrase?: string } {
    const trimmed = raw.trim();
    const hexShape = trimmed.replace(/\s+/g, "").toLowerCase();
    if (/^[0-9a-f]{64}$/.test(hexShape)) {
      return { seed: hexToBytes(hexShape) };
    }
    if (isValidMnemonic(trimmed)) {
      return { seed: seedFromMnemonic(trimmed), phrase: trimmed.replace(/\s+/g, " ") };
    }
    throw new Error(
      "Couldn't read that as either a 12/24-word recovery phrase or a 64-character hex seed.",
    );
  }

  async function submit() {
    error = null;
    working = true;
    try {
      if (passphrase.length < 8) {
        throw new Error("Passphrase must be at least 8 characters.");
      }
      if (passphrase !== passphrase2) {
        throw new Error("Passphrases don't match.");
      }
      if (!serverDomain) {
        throw new Error("Server unreachable; refresh and try again.");
      }

      const { seed, phrase } = parseSecret(secretInput);
      const id = identityFromSeed(seed);

      // Look up the handle this primary is registered to.
      let record;
      try {
        record = await lookupByPrimary(id.identity);
      } catch (e) {
        if (e instanceof ApiError && e.status === 404) {
          throw new Error(
            "No account registered with this recovery phrase on " +
              `${serverDomain}. Did you mean to create a new one?`,
          );
        }
        throw e;
      }

      // Re-sign a registration so it's on file fresh (idempotent on the
      // server — same primary always matches the same handle).
      // (We don't strictly need to re-register; storing locally is enough.)
      void signRegistration;

      await saveIdentity({
        handle: record.handle,
        server: serverDomain,
        primary: id.identity,
        seed: id.seed,
        passphrase,
        phrase,
      });

      session.setUnlocked({
        handle: record.handle,
        server: serverDomain,
        primary: id.identity,
        seed: id.seed,
        phrase,
      });

      push("/welcome");
    } catch (e) {
      error =
        e instanceof ApiError ? `${e.code ?? "error"}: ${e.message}` : (e as Error).message;
    } finally {
      working = false;
    }
  }
</script>

<div class="space-y-6">
  <h1 class="text-2xl font-bold text-text">Restore account</h1>

  <p class="text-sm text-text-secondary">
    Paste your 12-word recovery phrase. (If you wrote down a 64-character
    hex seed from an older version of kez-chat, that works too.) We'll
    look up your handle on <span class="font-mono">{serverDomain ?? "the server"}</span>
    and unlock the account on this device.
  </p>

  <form
    class="space-y-4"
    onsubmit={(e) => { e.preventDefault(); submit(); }}
  >
    <div>
      <label class="block text-sm font-medium text-text-secondary" for="secret">
        Recovery phrase or hex seed
      </label>
      <textarea
        id="secret"
        bind:value={secretInput}
        rows="3"
        placeholder="abandon ability able about above absent academy accident account accuse achieve acid"
        class="mt-1 w-full px-3 py-2 border border-border rounded-md font-mono text-sm"
        autocomplete="off"
        spellcheck="false"
      ></textarea>
    </div>

    <div>
      <label class="block text-sm font-medium text-text-secondary" for="pw">
        New passphrase for this device
      </label>
      <input
        id="pw"
        type="password"
        bind:value={passphrase}
        class="mt-1 w-full px-3 py-2 border border-border rounded-md"
      />
      <input
        type="password"
        bind:value={passphrase2}
        placeholder="confirm"
        class="mt-2 w-full px-3 py-2 border border-border rounded-md"
      />
    </div>

    {#if error}
      <p class="text-sm text-danger bg-danger/10 border border-danger/40 rounded p-3">
        {error}
      </p>
    {/if}

    <div class="flex gap-2">
      <button
        type="button"
        class="px-4 py-2 border border-border rounded-md text-text-secondary hover:bg-elevated"
        onclick={() => push("/")}
      >
        Cancel
      </button>
      <button
        type="submit"
        class="px-4 py-2 bg-accent text-accent-contrast rounded-md hover:bg-accent-dim disabled:opacity-50"
        disabled={working}
      >
        {working ? "Restoring…" : "Restore"}
      </button>
    </div>
  </form>
</div>
