/*
 * The self-edit result envelope: what parseEditResult will and won't accept.
 *
 * Same reasoning as run-langs.test.js: this parses text a model chose to
 * paste, so the malformed cases matter as much as the well-formed ones. A bad
 * envelope must return null so the caller falls back to plain code, not a
 * half-built object that renders a change that never happened.
 */
import { test } from "node:test";
import assert from "node:assert/strict";

import { EDIT_FENCE_LANG, parseEditResult } from "./self-edit-langs.js";

test("the fence tag is the one the backend emits", () => {
  assert.equal(EDIT_FENCE_LANG, "nexus-edit");
});

test("a well-formed source envelope parses into display fields", () => {
  const edit = parseEditResult(JSON.stringify({
    kind: "source", ok: true, path: "synapse/tools.py", diff: "--- a\n+++ b\n",
    commit: "abc1234", instruction: "restart needed",
  }));
  assert.equal(edit.kind, "source");
  assert.equal(edit.path, "synapse/tools.py");
  assert.equal(edit.commit, "abc1234");
  assert.equal(edit.instruction, "restart needed");
});

test("a source envelope with no commit reads as null, not undefined", () => {
  const edit = parseEditResult(JSON.stringify({
    kind: "source", path: "x.py", diff: "", commit: null,
  }));
  assert.equal(edit.commit, null);
});

test("a source envelope missing path or diff is rejected", () => {
  assert.equal(parseEditResult(JSON.stringify({ kind: "source", diff: "x" })), null);
  assert.equal(parseEditResult(JSON.stringify({ kind: "source", path: "x.py" })), null);
});

test("a well-formed playbook envelope parses into display fields", () => {
  const edit = parseEditResult(JSON.stringify({
    kind: "playbook", id: "p1", title: "T", goal: "G", instructions: "I",
    is_main_playbook: true,
  }));
  assert.equal(edit.kind, "playbook");
  assert.equal(edit.id, "p1");
  assert.equal(edit.isMainPlaybook, true);
});

test("a playbook envelope missing id is rejected", () => {
  assert.equal(parseEditResult(JSON.stringify({ kind: "playbook", title: "T" })), null);
});

test("a well-formed settings envelope parses into display fields", () => {
  const edit = parseEditResult(JSON.stringify({
    kind: "settings",
    applied: { model: { before: "a", after: "b" } },
    ignored_unknown: ["nope"],
    policy_change: true,
    system_prompt_change: false,
  }));
  assert.equal(edit.kind, "settings");
  assert.deepEqual(edit.applied, { model: { before: "a", after: "b" } });
  assert.deepEqual(edit.ignoredUnknown, ["nope"]);
  assert.equal(edit.policyChange, true);
  assert.equal(edit.systemPromptChange, false);
});

test("a settings envelope missing applied is rejected", () => {
  assert.equal(parseEditResult(JSON.stringify({ kind: "settings" })), null);
});

test("malformed or foreign envelopes are rejected", () => {
  assert.equal(parseEditResult("not json"), null);
  assert.equal(parseEditResult("null"), null);
  assert.equal(parseEditResult("[1,2,3]"), null);
  assert.equal(parseEditResult(JSON.stringify({ kind: "unknown_kind" })), null);
  assert.equal(parseEditResult(JSON.stringify({ path: "x.py", diff: "" })), null);
});
