const assert = require("node:assert/strict");
const { readFileSync } = require("node:fs");
const { join } = require("node:path");
const {
  applyIntent,
  applyPatch,
  createPatch,
  parse,
  renderHtml,
  validate,
} = require("../pkg-node/hmd_wasm.js");

const source = readFileSync(
  join(__dirname, "../../../fixtures/valid/todo-basic.hmd"),
  "utf8",
);

const document = JSON.parse(parse(source));
assert.equal(document.profile, "todo@0.1");
assert.equal(document.children[1].kind, "hmd_block");
assert.equal(document.children[1].blockType, "task");

const validation = JSON.parse(validate(source));
assert.equal(validation.valid, true);
assert.equal(validation.document.diagnostics.length, 0);

const html = renderHtml(source, JSON.stringify({ roundtrip: "semantic" }));
assert.match(html, /data-hmd-type="task"/);

const decisionSource = readFileSync(
  join(__dirname, "../../../fixtures/valid/decision-basic.hmd"),
  "utf8",
);
const decisionHtml = renderHtml(
  decisionSource,
  JSON.stringify({ roundtrip: "semantic" }),
);
const sourceHash = JSON.parse(
  decisionHtml.match(
    /<script type="application\/hmd\+json" id="hmd-manifest">\n([\s\S]*?)\n<\/script>/,
  )[1],
).sourceHash;
const intent = JSON.stringify({
  intentVersion: "0.1",
  action: "decision.select_option",
  target: "/blocks/rust",
  context: {
    documentProfile: "decision@0.1",
    sourceHash,
    decisionTarget: "/blocks/D-runtime",
  },
  params: {
    choiceId: "CH-D-runtime-rust",
    choiceStatus: "selected",
    markdown: "Selected Rust.",
  },
});
const patchJson = createPatch(decisionSource, intent);
assert.match(patchJson, /"op": "append_block"/);
assert.match(patchJson, /"targetHash": "sha256-/);

const patchedFromPatch = applyPatch(decisionSource, patchJson);
const patchedFromIntent = applyIntent(decisionSource, intent);
assert.equal(patchedFromPatch, patchedFromIntent);
assert.match(patchedFromIntent, /::: choice/);
assert.match(patchedFromIntent, /id = "CH-D-runtime-rust"/);
assert.doesNotMatch(decisionSource, /CH-D-runtime-rust/);

const stalePatch = patchJson.replace(sourceHash, "sha256-stale");
assert.throws(() => applyPatch(decisionSource, stalePatch), /target hash mismatch/);

const staleIntent = JSON.parse(intent);
staleIntent.context.sourceHash = "sha256-stale";
assert.throws(
  () => createPatch(decisionSource, JSON.stringify(staleIntent)),
  /action: decision\.select_option, target: \/blocks\/rust/,
);
