import { readFileSync } from "node:fs";
import {
  isBuildRemoteDisabled,
  parseBuildRemoteConfig,
  safeParseBuildRemoteConfig,
} from "./config-schema";
import { hostEligible } from "./admission";
import { parseReportInput, reportConfig, reportJob } from "./report";

export type CliJsonResult =
  | { ok: true; config?: unknown }
  | { ok: false; error: string; detail?: string };

function writeStdout(payload: unknown): void {
  process.stdout.write(`${JSON.stringify(payload)}\n`);
}

function parseConfigFromFile(path: string): CliJsonResult {
  let rawText: string;
  try {
    rawText = readFileSync(path, "utf8");
  } catch (error) {
    return {
      ok: false,
      error: "config-invalid-json",
      detail: (error as Error).message,
    };
  }

  let raw: unknown;
  try {
    raw = JSON.parse(rawText);
  } catch (error) {
    return {
      ok: false,
      error: "config-invalid-json",
      detail: (error as Error).message,
    };
  }

  const parsed = safeParseBuildRemoteConfig(raw);
  if (!parsed.success) {
    return {
      ok: false,
      error: "config-invalid-shape",
      detail: parsed.error.message,
    };
  }

  return { ok: true, config: parsed.data };
}

async function runReportCommand(stdinText: string): Promise<CliJsonResult> {
  const trimmed = stdinText.trim();
  if (!trimmed) {
    return { ok: false, error: "invalid-args", detail: "stdin report body is required" };
  }

  let raw: unknown;
  try {
    raw = JSON.parse(trimmed);
  } catch (error) {
    return {
      ok: false,
      error: "invalid-args",
      detail: (error as Error).message,
    };
  }

  const parsed = parseReportInput(raw);
  if (parsed.kind === "invalid") {
    return { ok: false, error: "invalid-args", detail: parsed.detail };
  }

  if (parsed.kind === "job") {
    await reportJob(parsed.event);
  } else {
    await reportConfig(parsed.event);
  }

  return { ok: true };
}

async function runHostEligibleCommand(
  host: string | undefined,
  command: string | undefined,
): Promise<CliJsonResult | { eligible: boolean; reason: string }> {
  if (!host || !command) {
    return { ok: false, error: "invalid-args", detail: "host and command are required" };
  }

  return hostEligible(host, command);
}

export async function runCli(argv: string[]): Promise<number> {
  const [command, ...rest] = argv;
  if (!command) {
    writeStdout({ ok: false, error: "invalid-args", detail: "command is required" });
    return 64;
  }

  if (!rest.includes("--json")) {
    writeStdout({ ok: false, error: "invalid-args", detail: "--json is required" });
    return 64;
  }

  if (command === "parse-config") {
    const path = rest.find((entry) => entry !== "--json");
    if (!path) {
      writeStdout({ ok: false, error: "invalid-args", detail: "config path is required" });
      return 64;
    }

    const result = parseConfigFromFile(path);
    writeStdout(result);
    if (!result.ok) {
      return result.error.startsWith("config-invalid") ? 65 : 64;
    }
    return 0;
  }

  if (command === "report") {
    const stdinText = await Bun.stdin.text();
    const result = await runReportCommand(stdinText);
    writeStdout(result.ok ? { ok: true } : result);
    return result.ok ? 0 : 64;
  }

  if (command === "host-eligible") {
    const positional = rest.filter((entry) => entry !== "--json");
    const result = await runHostEligibleCommand(positional[0], positional[1]);
    if ("ok" in result && result.ok === false) {
      writeStdout(result);
      return 64;
    }
    writeStdout(result);
    return 0;
  }

  writeStdout({ ok: false, error: "invalid-args", detail: `unknown command: ${command}` });
  return 64;
}

if (import.meta.main) {
  process.exit(await runCli(process.argv.slice(2)));
}

export {
  isBuildRemoteDisabled,
  parseBuildRemoteConfig,
  safeParseBuildRemoteConfig,
};
