// Mock-HTTP regression for the body-before-title write order (#159 finding #10,
// PR #185 review pt 3). `updatePage` / `updatePageJson` must write the page BODY
// (collab) BEFORE the title (REST POST /pages/update), so a failed body write
// never leaves a NEW title over the OLD body (split-brain). We point the client
// at a mock server that serves auth + collab-token but has NO WebSocket upgrade
// handler, so the collab body write fails fast; we then assert the title was
// never POSTed. With the pre-fix (title-first) order, /pages/update WOULD be hit
// before the body failed.
import { test, after } from "node:test";
import assert from "node:assert/strict";
import http from "node:http";
import { DocmostClient } from "../../build/client.js";

function readBody(req) {
  return new Promise((resolve) => {
    let raw = "";
    req.on("data", (c) => (raw += c));
    req.on("end", () => resolve(raw));
  });
}
function startServer(handler) {
  return new Promise((resolve) => {
    const server = http.createServer(handler);
    server.listen(0, "127.0.0.1", () => {
      const { port } = server.address();
      resolve({ server, baseURL: `http://127.0.0.1:${port}/api` });
    });
  });
}
function sendJson(res, status, obj, extraHeaders = {}) {
  res.writeHead(status, {
    "Content-Type": "application/json",
    ...extraHeaders,
  });
  res.end(JSON.stringify(obj));
}

const openServers = [];
async function spawn(handler) {
  const { server, baseURL } = await startServer(handler);
  openServers.push(server);
  return { server, baseURL };
}
after(async () => {
  await Promise.all(openServers.map((s) => new Promise((r) => s.close(r))));
});

// A mock server that authenticates and hands out a collab token, tracks whether
// the title endpoint was hit, but has NO WS upgrade handler -> collab fails fast.
function makeServer() {
  const state = { titlePosted: false };
  const handler = async (req, res) => {
    await readBody(req);
    if (req.url === "/api/auth/login") {
      sendJson(
        res,
        200,
        { success: true },
        {
          "Set-Cookie": "authToken=t; Path=/; HttpOnly",
        },
      );
      return;
    }
    if (req.url === "/api/auth/collab-token") {
      sendJson(res, 200, { data: { token: "collab-jwt" } });
      return;
    }
    if (req.url === "/api/pages/update") {
      state.titlePosted = true;
      sendJson(res, 200, { data: {} });
      return;
    }
    sendJson(res, 404, { message: "not found" });
  };
  return { state, handler };
}

test("updatePage does NOT POST the title when the body (collab) write fails (#159)", async () => {
  const { state, handler } = makeServer();
  const { baseURL } = await spawn(handler);
  const client = new DocmostClient(baseURL, "u@e.com", "pw");

  await assert.rejects(() =>
    client.updatePage("page-1", "# Heading\n\nsome body", "New Title"),
  );
  assert.equal(
    state.titlePosted,
    false,
    "title must NOT be posted when the body write failed (body-first order)",
  );
});

test("updatePageJson does NOT POST the title when the body (collab) write fails (#159)", async () => {
  const { state, handler } = makeServer();
  const { baseURL } = await spawn(handler);
  const client = new DocmostClient(baseURL, "u@e.com", "pw");

  const doc = { type: "doc", content: [{ type: "paragraph" }] };
  await assert.rejects(() => client.updatePageJson("page-1", doc, "New Title"));
  assert.equal(
    state.titlePosted,
    false,
    "title must NOT be posted when the body write failed (body-first order)",
  );
});
