import { spawn } from "node:child_process";
import { EventEmitter } from "node:events";
import { describe, expect, it, vi } from "vitest";

vi.mock("node:child_process", () => {
  const spawn = vi.fn(() => {
    const child = new EventEmitter() as EventEmitter & {
      stdout?: EventEmitter & { setEncoding?: (enc: string) => void };
      kill?: (signal?: string) => void;
    };
    const stdout = new EventEmitter() as EventEmitter & {
      setEncoding?: (enc: string) => void;
    };
    stdout.setEncoding = vi.fn();
    child.stdout = stdout;
    child.kill = vi.fn();
    process.nextTick(() => {
      stdout.emit(
        "data",
        [
          "user steipete",
          "hostname peters-mac-studio-1.sheep-coho.ts.net",
          "port 2222",
          "identityfile none",
          "identityfile /tmp/id_ed25519",
          "",
        ].join("\n"),
      );
      child.emit("exit", 0);
    });
    return child;
  });
  return { spawn };
});

const spawnMock = vi.mocked(spawn);

describe("ssh-config", () => {
  it("parses ssh -G output", async () => {
    const { parseSshConfigOutput } = await import("./ssh-config.js");
    const parsed = parseSshConfigOutput(
      "user bob\nhostname example.com\nport 2222\nidentityfile none\nidentityfile /tmp/id\n",
    );
    expect(parsed.user).toBe("bob");
    expect(parsed.host).toBe("example.com");
    expect(parsed.port).toBe(2222);
    expect(parsed.identityFiles).toEqual(["/tmp/id"]);
  });

  it("resolves ssh config via ssh -G", async () => {
    const { resolveSshConfig } = await import("./ssh-config.js");
    const config = await resolveSshConfig({ user: "me", host: "alias", port: 22 });
    expect(config?.user).toBe("steipete");
    expect(config?.host).toBe("peters-mac-studio-1.sheep-coho.ts.net");
    expect(config?.port).toBe(2222);
    expect(config?.identityFiles).toEqual(["/tmp/id_ed25519"]);
  });

  it("returns null when ssh -G fails", async () => {
    spawnMock.mockImplementationOnce(() => {
      const child = new EventEmitter() as EventEmitter & {
        stdout?: EventEmitter & { setEncoding?: (enc: string) => void };
        kill?: (signal?: string) => void;
      };
      const stdout = new EventEmitter() as EventEmitter & {
        setEncoding?: (enc: string) => void;
      };
      stdout.setEncoding = vi.fn();
      child.stdout = stdout;
      child.kill = vi.fn();
      process.nextTick(() => {
        child.emit("exit", 1);
      });
      return child;
    });

    const { resolveSshConfig } = await import("./ssh-config.js");
    const config = await resolveSshConfig({ user: "me", host: "bad-host", port: 22 });
    expect(config).toBeNull();
  });
});
