import assert from "node:assert/strict";
import { after, before, test } from "node:test";

import { createServer } from "vite";

let server;
let decodePolygonRunCatalog;
let decodePolygonRunDetail;
let fetchPolygonRunCatalog;
let fetchPolygonRunDetail;
let resolvePolygonRunRoute;
let PolygonRunContractError;
let workspaceById;
let workspacesForRoot;

before(async () => {
  server = await createServer({
    appType: "custom",
    logLevel: "silent",
    server: { middlewareMode: true },
  });
  ({
    decodePolygonRunCatalog,
    decodePolygonRunDetail,
    fetchPolygonRunCatalog,
    fetchPolygonRunDetail,
    resolvePolygonRunRoute,
    PolygonRunContractError,
  } = await server.ssrLoadModule("/src/core/polygon/runArchive.ts"));
  ({ workspaceById, workspacesForRoot } = await server.ssrLoadModule("/src/productModel.ts"));
});

after(async () => {
  await server?.close();
});

function summary(overrides = {}) {
  return {
    run_id: "s1b-6cb1495-20260724t1535z",
    episode_id: "episode-s1b-6cb1495-20260724t1535z",
    kind: "simulation_closed_loop",
    state: "completed",
    created_at_utc: "2026-07-24T15:35:00Z",
    started_at_utc: "2026-07-24T15:35:02Z",
    ended_at_utc: "2026-07-24T15:35:05Z",
    terminal_reason: "operator-stop-clean",
    scenario_generation: "px4-v1.17.0-stock-rover-ackermann",
    profile_generation: "stock-rover-lifecycle-v1",
    mission_core_commit: "6cb1495a1234567890abcdef1234567890abcdef",
    host_profile_id: "mission-gpu-s0",
    reproducibility_tier: "R1",
    clock_domain: "gazebo:/clock",
    revision: 5,
    provider_ids: ["px4-autopilot", "gazebo"],
    artifact_count: 1,
    ...overrides,
  };
}

function catalog(overrides = {}) {
  return {
    schema_version: "missioncore.polygon-run-catalog/v1",
    access: "read-only",
    items: [summary()],
    total: 1,
    limitations: ["Qualification evidence only."],
    ...overrides,
  };
}

function detail(overrides = {}) {
  return {
    schema_version: "missioncore.polygon-run-detail/v1",
    access: "read-only",
    run: {
      ...summary(),
      scenario_sha256: "a".repeat(64),
      profile_sha256: "b".repeat(64),
      host_profile_sha256: "c".repeat(64),
      seed: 42,
      parent_run_id: null,
      providers: [
        {
          identifier: "px4-autopilot",
          version: "v1.17.0",
          revision: "v1.17.0",
          digest: null,
        },
        {
          identifier: "gazebo",
          version: "harmonic",
          revision: "8.9.0",
          digest: null,
        },
      ],
      authority: {
        generation: 1,
        command_ttl_max_ns: 250_000_000,
        heartbeat_timeout_monotonic_ns: 500_000_000,
        simulation_or_shadow_only: true,
        actuator_authority: false,
        navigation_or_safety_accepted: false,
        direct_actuator_setpoints_allowed: false,
      },
    },
    events: [
      {
        schema_version: "missioncore.qualification-event/v1",
        run_id: "s1b-6cb1495-20260724t1535z",
        sequence: 5,
        event_type: "lifecycle.state-changed",
        observed_at_utc: "2026-07-24T15:35:05Z",
        host_monotonic_ns: 5,
        sim_time_ns: 2_000_000,
        payload: {
          from: "stopping",
          to: "completed",
          reason: "operator-stop-clean",
        },
      },
    ],
    events_total: 1,
    events_truncated: false,
    commands: {
      count: 0,
      content_exposed: false,
    },
    artifacts: [
      {
        artifact_id: "provider-log-index",
        kind: "log-index",
        relative_path: "provider-runtime/processes.json",
        sha256: "a".repeat(64),
        byte_length: 512,
        source_of_record: true,
        sequence: 1,
      },
    ],
    limitations: ["Qualification evidence only."],
    ...overrides,
  };
}

function jsonResponse(payload, status = 200) {
  return new Response(JSON.stringify(payload), {
    status,
    headers: { "content-type": "application/json" },
  });
}

test("UI-0 route is direct-only and does not add Polygon to system navigation", () => {
  assert.deepEqual(resolvePolygonRunRoute("?workspace=polygon-run"), {
    active: true,
    runId: null,
    error: null,
  });
  assert.deepEqual(
    resolvePolygonRunRoute("?workspace=polygon-run&run=s1b-6cb1495-20260724t1535z"),
    {
      active: true,
      runId: "s1b-6cb1495-20260724t1535z",
      error: null,
    },
  );
  assert.equal(resolvePolygonRunRoute("?workspace=missions").active, false);
  assert.match(
    resolvePolygonRunRoute("?workspace=polygon-run&run=../../etc").error,
    /некорректный/,
  );
  assert.equal(workspaceById("polygon-run-internal").internalOnly, true);
  assert.equal(
    workspacesForRoot("system").some(({ id }) => id === "polygon-run-internal"),
    false,
  );
});

test("Polygon contracts decode path-free evidence and preserve the safety boundary", () => {
  const decodedCatalog = decodePolygonRunCatalog(catalog());
  const decodedDetail = decodePolygonRunDetail(detail());

  assert.equal(decodedCatalog.items[0].state, "completed");
  assert.equal(decodedDetail.run.authority.actuatorAuthority, false);
  assert.equal(decodedDetail.run.authority.navigationOrSafetyAccepted, false);
  assert.equal(decodedDetail.commandCount, 0);
  assert.equal(decodedDetail.artifacts[0].relativePath, "provider-runtime/processes.json");
  assert.equal("content" in decodedDetail, false);
});

test("Polygon contracts fail closed on command content, paths and unknown fields", () => {
  assert.throws(
    () => decodePolygonRunDetail(detail({
      commands: { count: 1, content_exposed: true },
    })),
    PolygonRunContractError,
  );
  assert.throws(
    () => decodePolygonRunDetail(detail({
      artifacts: [{
        ...detail().artifacts[0],
        relative_path: "/mnt/d/private/processes.json",
      }],
    })),
    PolygonRunContractError,
  );
  assert.throws(
    () => decodePolygonRunCatalog(catalog({ unexpected: true })),
    PolygonRunContractError,
  );
});

test("Polygon fetchers use bounded same-origin GET endpoints", async () => {
  const calls = [];
  const fetcher = async (url, init) => {
    calls.push({ url, init });
    return String(url).includes("event_limit") ? jsonResponse(detail()) : jsonResponse(catalog());
  };

  await fetchPolygonRunCatalog({ limit: 20, fetcher });
  await fetchPolygonRunDetail("s1b-6cb1495-20260724t1535z", {
    eventLimit: 200,
    fetcher,
  });

  assert.deepEqual(calls.map(({ url }) => url), [
    "/api/v1/polygon/runs?limit=20",
    "/api/v1/polygon/runs/s1b-6cb1495-20260724t1535z?event_limit=200",
  ]);
  assert.ok(calls.every(({ init }) => init.method === "GET"));
  assert.ok(calls.every(({ init }) => init.headers.Accept === "application/json"));
});
