// SPEC: pikasTech/HWLAB#2351 Workbench JSON parse/projection merge cost reduction.
// Responsibility: Regression tests for bounded Workbench message projection refresh planning.

import assert from "node:assert/strict";
import test from "node:test";

import type { ChatMessage } from "../src/types/index.ts";
import { boundedProjectionMessageLimit, mergeBoundedProjectionMessages, selectProjectionMessageWindow, traceProjectionIsTerminalSealed } from "../src/stores/workbench-message-projection-budget.ts";

test("projection window keeps only bounded tail for automatic session refresh", () => {
  const messages = Array.from({ length: 8 }, (_, index) => message(`msg_${index}`, `trc_${index}`));
  const selected = selectProjectionMessageWindow(messages, { limit: 3 });

  assert.deepEqual(selected.map((item) => item.id), ["msg_5", "msg_6", "msg_7"]);
});

test("projection window keeps active trace outside the bounded tail", () => {
  const messages = Array.from({ length: 8 }, (_, index) => message(`msg_${index}`, `trc_${index}`));
  const selected = selectProjectionMessageWindow(messages, { traceId: "trc_2", limit: 3 });

  assert.deepEqual(selected.map((item) => item.id), ["msg_2", "msg_5", "msg_6", "msg_7"]);
});

test("bounded projection merge updates window messages without dropping history", () => {
  const existing = [
    message("msg_1", "trc_1", { text: "old one" }),
    message("msg_2", "trc_2", { text: "old two" }),
    message("msg_3", "trc_3", { text: "old three" })
  ];
  const incoming = [
    message("msg_2", "trc_2", { text: "new two" }),
    message("msg_4", "trc_4", { text: "new four" })
  ];

  const merged = mergeBoundedProjectionMessages(existing, incoming);

  assert.deepEqual(merged.map((item) => item.id), ["msg_1", "msg_2", "msg_3", "msg_4"]);
  assert.equal(merged[0]?.text, "old one");
  assert.equal(merged[1]?.text, "new two");
  assert.equal(merged[3]?.text, "new four");
});

test("bounded projection merge replaces optimistic agent row by trace when message ids differ", () => {
  const existing = [message("msg_optimistic", "trc_same", { text: "optimistic" })];
  const incoming = [message("msg_canonical", "trc_same", { text: "canonical" })];

  const merged = mergeBoundedProjectionMessages(existing, incoming);

  assert.equal(merged.length, 1);
  assert.equal(merged[0]?.id, "msg_canonical");
  assert.equal(merged[0]?.text, "canonical");
});

test("terminal sealed trace skips redundant message projection refresh", () => {
  const sealed = message("msg_terminal", "trc_terminal", {
    status: "completed",
    text: "final answer",
    finalResponse: { text: "final answer" }
  });
  const unsealed = message("msg_unsealed", "trc_unsealed", { status: "completed", text: "" });

  assert.equal(traceProjectionIsTerminalSealed("trc_terminal", [sealed, unsealed]), true);
  assert.equal(traceProjectionIsTerminalSealed("trc_unsealed", [sealed, unsealed]), false);
  assert.equal(boundedProjectionMessageLimit(0, 5), 5);
});

function message(id: string, traceId: string, extra: Partial<ChatMessage> = {}): ChatMessage {
  return {
    id,
    messageId: id,
    role: "agent",
    title: "Code Agent",
    text: "",
    status: "running",
    traceId,
    createdAt: "2026-07-02T00:00:00.000Z",
    ...extra
  };
}
