import assert from "node:assert/strict";
import test from "node:test";
import { formatFailure, startCraftos, startServer, waitFor } from "./harness.js";

// Two real computers with the same traposId (id:label): newest-wins. After both
// complete hello, exactly one registration exists; aborting the displaced first
// computer does not affect the live registration, and a gateway->computer ping is
// still answered by the newest computer.
test("duplicate traposId is resolved newest-wins", async () => {
  const server = await startServer();
  const TRAPOS_ID = "9:dup";

  // Newest-wins is decided by the order hello frames reach the gateway, which is
  // independent of the client-side READY print order. Spawn the two computers
  // sequentially — only start `second` once `first` is registered server-side —
  // so `second` is unambiguously the newer registration.
  const first = startCraftos("gateway-client.lua", {
    computerId: 9,
    computerLabel: "dup",
    shellArgs: [server.baseUrl, "-", "idle", "60"],
  });

  let second: ReturnType<typeof startCraftos> | undefined;
  try {
    await waitFor(() => first.snapshot().includes("__CLOUD_READY__"), 12_000, "first connected");
    await waitFor(() => server.registry.has("global", TRAPOS_ID), 2_000, "first registered server-side");

    const secondHandle = startCraftos("gateway-client.lua", {
      computerId: 9,
      computerLabel: "dup",
      shellArgs: [server.baseUrl, "-", "idle"],
    });
    second = secondHandle;
    await waitFor(() => secondHandle.snapshot().includes("__CLOUD_READY__"), 12_000, "second connected");
    // Newest-wins: still exactly one registration for the shared id.
    assert.equal(server.registry.count(), 1, "exactly one registration after the duplicate");
    assert.ok(server.registry.has("global", TRAPOS_ID));

    first.abort();
    await first.done.catch(() => undefined);
    const payload = await server.registry.request("global", TRAPOS_ID, "ping", {}, 2_000);
    assert.deepEqual(payload, { traposId: TRAPOS_ID }, "newest stayed registered after first exited");
  } catch (error) {
    throw new Error(
      formatFailure(
        error instanceof Error ? error.message : String(error),
        `first:\n${first.snapshot()}\nsecond:\n${second?.snapshot() ?? "(not started)"}`,
      ),
      { cause: error },
    );
  } finally {
    first.abort();
    second?.abort();
    await Promise.all([first.done.catch(() => undefined), second?.done.catch(() => undefined)]);
    await server.close();
  }
});
