import assert from "node:assert/strict";
import { test } from "bun:test";

import type { CaseRunRecord } from "../../internal/harnessrl/contracts.ts";
import { CaseRunTransportError, createApiCaseRunTransport, createLocalCaseRunTransport } from "../../internal/harnessrl/transport.ts";
import { runHwlabCli } from "../src/hwlab-cli-lib.ts";

const record: CaseRunRecord = {
  runId: "run-2617", caseId: "case-2617", workflowId: "harnessrl-caserun-run-2617", workflowRunId: "workflow-run-2617",
  status: "queued", stage: "queued", terminal: false, caseRepo: "/cases", runDir: "/state/run-2617", runtimeApiUrl: "local://harnessrl",
  result: null, error: null, blocker: null, createdAt: "2026-07-17T00:00:00.000Z", updatedAt: "2026-07-17T00:00:00.000Z"
};

test("L0 local adapter executes the shared CaseRun command contract without HTTP", async () => {
  const calls: string[] = [];
  const transport = createLocalCaseRunTransport({ service: {
    async submit() { calls.push("start"); return record; },
    async getRun() { calls.push("status"); return record; },
    async events() { calls.push("events"); return { ...record, events: [] }; },
    async aggregate() { calls.push("aggregate"); return { ok: true, runId: record.runId, status: record.status }; },
    async cancel() { calls.push("cancel"); return { ...record, status: "cancel_requested", stage: "cancel_requested" }; }
  }});

  const started = await transport.execute({ kind: "start", caseId: record.caseId, runId: record.runId });
  assert.equal(started.runId, record.runId);
  assert.equal(started.workflowId, record.workflowId);
  await transport.execute({ kind: "status", runId: record.runId });
  await transport.execute({ kind: "events", runId: record.runId });
  await transport.execute({ kind: "aggregate", runId: record.runId });
  await transport.execute({ kind: "cancel", runId: record.runId });
  assert.deepEqual(calls, ["start", "status", "events", "aggregate", "cancel"]);
});

test("CLI defaults to local and requires explicit over-api for base-url", async () => {
  const local = createLocalCaseRunTransport({ service: {
    async submit() { return record; }, async getRun() { return record; }, async events() { return { ...record, events: [] }; },
    async aggregate() { return { ok: true, runId: record.runId }; }, async cancel() { return record; }
  }});
  const result = await runHwlabCli(["case", "run", "start", record.caseId, "--run-id", record.runId], { caseRunTransportFactory: () => local });
  assert.equal(result.exitCode, 0);
  assert.equal(result.payload.transport, "local");
  assert.equal(result.payload.service, "native-harnessrl-application-service");
  assert.equal(result.payload.baseUrl, null);
  assert.equal(result.payload.route, null);
  assert.equal(result.payload.method, null);
  assert.equal(result.payload.workflowRunId, record.workflowRunId);

  const rejected = await runHwlabCli(["case", "run", "status", record.runId, "--base-url", "http://api.test"]);
  assert.equal(rejected.exitCode, 1);
  assert.equal(rejected.payload.error.code, "caserun_over_api_required");
});

test("API adapter uses only the explicit CaseRun origin and preserves typed errors", async () => {
  const requests: Array<{ url: string; method: string; authorization: string | null }> = [];
  const transport = createApiCaseRunTransport({ baseUrl: "http://api.test", apiKey: "hwl_live_test", fetchImpl: async (input, init) => {
    requests.push({ url: String(input), method: String(init?.method), authorization: new Headers(init?.headers).get("authorization") });
    return Response.json({ ok: true, ...record });
  }});
  const response = await transport.execute({ kind: "events", runId: record.runId });
  assert.equal(response.workflowId, record.workflowId);
  assert.deepEqual(requests, [{ url: `http://api.test/v1/caserun/runs/${record.runId}/events`, method: "GET", authorization: "Bearer hwl_live_test" }]);

  const failed = createApiCaseRunTransport({ baseUrl: "http://api.test", fetchImpl: async () => Response.json({ ok: false, error: { code: "caserun_run_not_found", message: "missing", details: { runId: record.runId } } }, { status: 404 }) });
  await assert.rejects(failed.execute({ kind: "status", runId: record.runId }), (error: any) => error instanceof CaseRunTransportError && error.code === "caserun_run_not_found");
});

test("API adapter times out through its real AbortSignal path with typed route details", async () => {
  const transport = createApiCaseRunTransport({ baseUrl: "http://api.test", timeoutMs: 5, fetchImpl: async (_input, init) => {
    await new Promise((_resolve, reject) => init?.signal?.addEventListener("abort", () => reject(new DOMException("aborted", "AbortError")), { once: true }));
    throw new Error("unreachable");
  }});
  await assert.rejects(transport.execute({ kind: "status", runId: record.runId }), (error: any) => {
    assert.equal(error instanceof CaseRunTransportError, true);
    assert.equal(error.code, "caserun_api_timeout");
    assert.deepEqual(error.details, { timeoutMs: 5, baseUrl: "http://api.test", route: `/v1/caserun/runs/${record.runId}`, method: "GET" });
    return true;
  });
});

test("over-api CLI discloses bounded origin route and method without credentials", async () => {
  const result = await runHwlabCli(["case", "run", "events", record.runId, "--over-api", "--base-url", "http://api.test", "--timeout-ms", "25"], {
    env: { HWLAB_API_KEY: "hwl_live_secret" },
    fetchImpl: async () => Response.json({ ok: true, ...record, events: [] })
  });
  assert.equal(result.exitCode, 0);
  assert.equal(result.payload.transport, "api");
  assert.equal(result.payload.baseUrl, "http://api.test");
  assert.equal(result.payload.route, `/v1/caserun/runs/${record.runId}/events`);
  assert.equal(result.payload.method, "GET");
  assert.equal(JSON.stringify(result.payload).includes("hwl_live_secret"), false);
});
