import { describe, expect, test } from "bun:test";
import { RPC_ERROR_CODES, success } from "../src/errors.ts";
import { inProcessTransport } from "../src/transport.ts";

describe("inProcessTransport", () => {
  test("routes to the right handler and passes identity through", async () => {
    let seenIdentity: string | undefined;
    const transport = inProcessTransport({
      "billing/createInvoice": (payload, identity) => {
        seenIdentity = identity;
        return success({ echoed: payload });
      },
    });
    const result = await transport.call(
      { app: "billing", service: "billing", procedure: "createInvoice" },
      { amountCents: 1 },
      { identity: "tok-123" },
    );
    expect(result).toEqual({ ok: true, value: { echoed: { amountCents: 1 } } });
    expect(seenIdentity).toBe("tok-123");
  });

  test("an unregistered procedure yields non-retryable RPC_UNKNOWN", async () => {
    const transport = inProcessTransport({});
    const result = await transport.call(
      { app: "billing", service: "billing", procedure: "nope" },
      {},
      {},
    );
    expect(result).toEqual({
      ok: false,
      code: RPC_ERROR_CODES.unknown,
      message: "Unknown procedure",
      retryable: false,
    });
  });

  test("an already-aborted signal fails without invoking the handler", async () => {
    let called = false;
    const transport = inProcessTransport({
      "billing/createInvoice": () => {
        called = true;
        return success({});
      },
    });
    const controller = new AbortController();
    controller.abort();
    const result = await transport.call(
      { app: "billing", service: "billing", procedure: "createInvoice" },
      {},
      { signal: controller.signal },
    );
    expect(called).toBe(false);
    expect(result.ok).toBe(false);
    expect(result).toMatchObject({ code: RPC_ERROR_CODES.transport });
  });

  test("a handler that throws becomes an opaque failure with no leaked message text", async () => {
    const secret = "sk-super-secret-database-password-xyz";
    const transport = inProcessTransport({
      "billing/createInvoice": () => {
        throw new Error(`connection failed with credential ${secret}`);
      },
    });
    const result = await transport.call(
      { app: "billing", service: "billing", procedure: "createInvoice" },
      {},
      {},
    );
    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.code).toBe(RPC_ERROR_CODES.handler);
      expect(result.message).not.toContain(secret);
      expect(result.message).not.toContain("connection failed");
    }
  });
});
