// Unit tests for the widget's desktop deep-link builder (btxqid:// direct-connect).
//
// buildBtxqidSignUrl(request) is the only widget-side security-relevant encoding surface:
// it packs the qID sign-in request the widget already fetches into the URL the installed
// PQ Wallet for BTX handles, btxqid://sign?req=<base64url(JSON)>. The wallet decodes it,
// re-validates via its own challenge parser, origin-binds proof_url, and POSTs the proof
// back — none of which is exercised here (that is the wallet's own test suite). Here we
// prove the encoding is a clean, lossless, URL-safe round trip and that a realistic
// request fits comfortably inside a URL (the whole reason the proof returns by POST).
//
// Importing the widget module is bun-safe: nothing at its top level touches the DOM
// (document/window/navigator are referenced only inside function bodies), and
// btoa/TextEncoder are native in bun.

import { describe, expect, test } from "bun:test";
import { buildBtxqidSignUrl } from "../src/qid-connect-widget.js";

// A realistic request, byte-for-byte the shape core.js `challenge()` returns as `request`
// ({ v, type, challenge:{ nonce, rp_origin, ts }, proof_url }).
function realisticRequest() {
  return {
    v: 1,
    type: "signin",
    challenge: {
      nonce: "a".repeat(64), // 32 random bytes, hex — the widest realistic nonce
      rp_origin: "https://demo.qid.example",
      ts: 1752537600000,
    },
    proof_url: "https://demo.qid.example/qid/proof",
  };
}

// Decode the `req` param the way the wallet does: base64url -> bytes -> UTF-8 JSON.
function decodeReqParam(url) {
  const prefix = "btxqid://sign?req=";
  expect(url.startsWith(prefix)).toBe(true);
  const b64url = url.slice(prefix.length);
  const json = Buffer.from(b64url, "base64url").toString("utf8");
  return JSON.parse(json);
}

describe("buildBtxqidSignUrl", () => {
  test("produces btxqid://sign?req=… and round-trips losslessly", () => {
    const request = realisticRequest();
    const url = buildBtxqidSignUrl(request);
    expect(url.startsWith("btxqid://sign?req=")).toBe(true);
    expect(decodeReqParam(url)).toEqual(request);
  });

  test("the req param is pure base64url (no +, /, or = padding)", () => {
    const url = buildBtxqidSignUrl(realisticRequest());
    const req = url.slice("btxqid://sign?req=".length);
    expect(req.length).toBeGreaterThan(0);
    expect(/^[A-Za-z0-9_-]+$/.test(req)).toBe(true);
  });

  test("a realistic request fits comfortably inside a URL (req travels in the URL, proof does not)", () => {
    // Documents the core asymmetry: the ~300 B request fits well under any URL ceiling,
    // while the ~7.5 KiB proof cannot — which is why the proof returns via POST.
    const url = buildBtxqidSignUrl(realisticRequest());
    expect(url.length).toBeLessThan(512);
  });

  test("round-trips unicode content without corruption", () => {
    // TextEncoder -> base64 -> base64url handles multi-byte UTF-8 (guards a naive charCode path).
    const request = { ...realisticRequest(), note: "sign in ✓ — café" };
    const url = buildBtxqidSignUrl(request);
    expect(decodeReqParam(url)).toEqual(request);
  });
});
