import { afterEach, describe, expect, test } from "bun:test";
import type { Server } from "bun";
import { join } from "node:path";
import { fetchHostLogs, type SyncSpawnExec } from "./host-logs";
import { startServer } from "./server";

const TOKEN = "host-logs-token";
const home = "/fixture/home";

describe("fetchHostLogs", () => {
  test("rejects invalid hostnames without spawning", () => {
    let spawned = false;
    const exec: SyncSpawnExec = () => {
      spawned = true;
      return { exitCode: 0, stdout: "", stderr: "" };
    };

    expect(fetchHostLogs("-evil", exec, home)).toEqual({ error: "invalid-hostname" });
    expect(spawned).toBe(false);
  });

  test("invokes exact ssh argv transport for journalctl", () => {
    const calls: string[][] = [];
    const exec: SyncSpawnExec = (cmd) => {
      calls.push(cmd);
      return {
        exitCode: 0,
        stdout: "2026-07-21T10:00:00+0700 debian1 systemd[1]: Started overdeck-controller.\n",
        stderr: "",
      };
    };

    const result = fetchHostLogs("debian1", exec, home, 5_000);
    expect(result).toEqual({
      host: "debian1",
      lines: ["2026-07-21T10:00:00+0700 debian1 systemd[1]: Started overdeck-controller."],
      truncated: false,
    });
    expect(calls).toEqual([[
      "ssh",
      "-p",
      "2222",
      "-i",
      join(home, ".ssh/id_ed25519_buildbox"),
      "debian1",
      "journalctl",
      "-u",
      "overdeck-*",
      "--no-pager",
      "-n",
      "200",
      "--output=short-iso",
    ]]);
  });

  test("marks truncated when line count reaches the fetch limit", () => {
    const lines = Array.from({ length: 200 }, (_, index) => `line-${index}`);
    const exec: SyncSpawnExec = () => ({
      exitCode: 0,
      stdout: `${lines.join("\n")}\n`,
      stderr: "",
    });

    const result = fetchHostLogs("debian1", exec, home);
    if ("error" in result) {
      throw new Error(`unexpected error: ${result.error}`);
    }
    expect(result.truncated).toBe(true);
    expect(result.lines).toHaveLength(200);
  });
});

describe("GET /hosts/:hostname/logs", () => {
  let server: Server<undefined> | undefined;

  afterEach(() => {
    server?.stop(true);
    server = undefined;
  });

  test("requires bearer auth and proxies host logs via injected exec", async () => {
    const exec: SyncSpawnExec = () => ({
      exitCode: 0,
      stdout: "2026-07-21T10:00:00+0700 debian1 overdeck[1]: ready\n",
      stderr: "",
    });

    server = startServer({
      host: "127.0.0.1",
      port: 0,
      token: TOKEN,
      hostLogsExec: exec,
    });
    const origin = `http://127.0.0.1:${server.port}`;

    expect((await fetch(`${origin}/hosts/debian1/logs`)).status).toBe(401);

    const invalid = await fetch(`${origin}/hosts/-evil/logs`, {
      headers: { authorization: `Bearer ${TOKEN}` },
    });
    expect(invalid.status).toBe(400);
    expect(await invalid.json()).toEqual({ error: "invalid-hostname" });

    const response = await fetch(`${origin}/hosts/debian1/logs`, {
      headers: { authorization: `Bearer ${TOKEN}` },
    });
    expect(response.status).toBe(200);
    expect(await response.json()).toEqual({
      host: "debian1",
      lines: ["2026-07-21T10:00:00+0700 debian1 overdeck[1]: ready"],
      truncated: false,
    });
  });
});
