import { readFileSync, rmSync } from "node:fs";
import { describe, expect, test } from "bun:test";
import { parseAgentRunClientConfigYaml, resolveAgentRunAuth, runAgentRunCommand, stripAgentRunResourceWrapperArgs } from "./agentrun";

const agentRunClientYaml = [
  "manager:",
  "  baseUrl: https://agentrun.127-0-0-1.nip.io/",
  "  timeoutMs: 15000",
  "publicExposure:",
  "  enabled: true",
  "  proxyName: agentrun-v01-frpc",
  "  remotePort: 22880",
  "  publicBaseUrl: https://agentrun.127-0-0-1.nip.io/",
  "  masterBaseUrl: http://127.0.0.1:22880",
  "  masterFrps:",
  "    configPath: /opt/hwlab-frp/frps.dev.toml",
  "    containerName: hwlab-frps-dev",
  "  masterCaddy:",
  "    enabled: true",
  "    domain: agentrun.127-0-0-1.nip.io",
  "    configPath: /etc/caddy/Caddyfile",
  "    serviceName: caddy",
  "    upstreamBaseUrl: http://127.0.0.1:22880",
  "    responseHeaderTimeoutSeconds: 60",
  "auth:",
  "  env: HWLAB_API_KEY",
  "  file: /tmp/hwlab-api-key.env",
  "  header: Authorization",
  "  scheme: Bearer",
  "client:",
  "  role: render-only",
  "  transport: direct-http",
].join("\n");

const agentRunMinimalClientYaml = [
  "manager:",
  "  baseUrl: http://agentrun.example.local:8080",
  "  timeoutMs: 15000",
  "auth:",
  "  env: HWLAB_API_KEY",
  "  file: /tmp/hwlab-api-key.env",
  "  header: Authorization",
  "  scheme: Bearer",
  "client:",
  "  role: render-only",
  "  transport: direct-http",
].join("\n");

describe("AgentRun resource bridge argv", () => {
  test("does not forward UniDesk output flags to create task prompt argv", () => {
    expect(stripAgentRunResourceWrapperArgs([
      "--aipod",
      "Artificer",
      "--prompt-stdin",
      "-o",
      "json",
      "--idempotency-key",
      "case-262",
      "--dry-run",
    ])).toEqual([
      "--aipod",
      "Artificer",
      "--prompt-stdin",
      "--idempotency-key",
      "case-262",
      "--dry-run",
    ]);
  });

  test("strips wrapper display flags while preserving official apply arguments", () => {
    expect(stripAgentRunResourceWrapperArgs([
      "-f",
      "-",
      "--output=yaml",
      "--raw",
      "--full",
      "--full-text",
      "--dry-run",
    ])).toEqual([
      "-f",
      "-",
      "--dry-run",
    ]);
  });
});

describe("AgentRun render-only REST client config", () => {
  test("parses explicit YAML config for direct REST render-only client", () => {
    const config = parseAgentRunClientConfigYaml(agentRunClientYaml, "config/agentrun.yaml");
    expect(config.manager.baseUrl).toBe("https://agentrun.127-0-0-1.nip.io/");
    expect(config.publicExposure?.publicBaseUrl).toBe("https://agentrun.127-0-0-1.nip.io/");
    expect(config.publicExposure?.masterCaddy.domain).toBe("agentrun.127-0-0-1.nip.io");
    expect(config.auth.env).toBe("HWLAB_API_KEY");
    expect(config.auth.header).toBe("Authorization");
    expect(config.auth.scheme).toBe("Bearer");
    expect(config.client.role).toBe("render-only");
    expect(config.client.transport).toBe("direct-http");
  });

  test("uses env auth before configured file auth without exposing the key", () => {
    const config = parseAgentRunClientConfigYaml(agentRunClientYaml, "config/agentrun.yaml");
    const auth = resolveAgentRunAuth(config, { HWLAB_API_KEY: "secret-value" });
    expect(auth.source).toBe("env");
    expect(auth.value).toBe("secret-value");
  });

  test("requires explicit render-only direct-http client contract", () => {
    expect(() => parseAgentRunClientConfigYaml(agentRunClientYaml.replace("  transport: direct-http", "  transport: ssh-bridge"), "config/agentrun.yaml")).toThrow("client.transport must be direct-http");
    expect(() => parseAgentRunClientConfigYaml(agentRunClientYaml.replace("  role: render-only", "  role: proxy"), "config/agentrun.yaml")).toThrow("client.role must be render-only");
  });
});

describe("AgentRun default transport contract", () => {
  test("server-facing compatibility groups use REST dispatcher, not official SSH CLI wrapper", () => {
    const source = readFileSync(new URL("./agentrun.ts", import.meta.url), "utf8");
    const commandRouter = source.slice(source.indexOf("export async function runAgentRunCommand"), source.indexOf("function isAgentRunRestCompatGroup"));
    expect(commandRouter).toContain("runAgentRunRestCompatCommand");
    expect(commandRouter).not.toContain("runOfficialAgentRunCli");
    expect(commandRouter).not.toContain("runPreparedOfficialAgentRunCli");
  });

  test("resource verbs can use direct REST without UniDesk SSH config", async () => {
    const server = Bun.serve({
      port: 0,
      fetch(request) {
        const url = new URL(request.url);
        expect(request.headers.get("authorization")).toBe("Bearer secret-value");
        expect(url.pathname).toBe("/api/v1/queue/tasks");
        expect(url.searchParams.get("queue")).toBe("commander");
        expect(url.searchParams.get("state")).toBe("running");
        return Response.json({
          ok: true,
          data: {
            items: [
              { id: "qt_1", state: "queued", queue: "commander" },
            ],
          },
        });
      },
    });
    const previousConfig = process.env.AGENTRUN_CLIENT_CONFIG;
    const previousKey = process.env.HWLAB_API_KEY;
    process.env.HWLAB_API_KEY = "secret-value";
    const tempConfigPath = `/tmp/unidesk-agentrun-test-${process.pid}-${Date.now()}.yaml`;
    try {
      process.env.AGENTRUN_CLIENT_CONFIG = tempConfigPath;
      await Bun.write(process.env.AGENTRUN_CLIENT_CONFIG, agentRunMinimalClientYaml.replace("http://agentrun.example.local:8080", server.url.href.replace(/\/$/u, "")));
      const result = await runAgentRunCommand(null, ["get", "tasks", "--queue", "commander", "-o", "json"]);
      expect(result.ok).toBe(true);
      expect("renderedText" in result).toBe(true);
      if ("renderedText" in result) {
        expect(result.renderedText).toContain("\"kind\": \"TaskList\"");
        expect(result.renderedText).toContain("\"name\": \"qt_1\"");
      }
    } finally {
      server.stop(true);
      if (previousConfig === undefined) delete process.env.AGENTRUN_CLIENT_CONFIG;
      else process.env.AGENTRUN_CLIENT_CONFIG = previousConfig;
      if (previousKey === undefined) delete process.env.HWLAB_API_KEY;
      else process.env.HWLAB_API_KEY = previousKey;
      rmSync(tempConfigPath, { force: true });
    }
  });
});
