import { readConfig } from "./src/config";
import { isHelpToken, renderSshHelpText, sshHelp, sshHelpScope } from "./src/help";
import { CliInputError, emitError, emitJson, emitText } from "./src/output";
import { extractRemoteCliOptions } from "./src/remote-options";
import { runRemoteSshCli } from "./src/remote-ssh";
import { runSsh } from "./src/ssh";

const remoteOptions = extractRemoteCliOptions(process.argv.slice(2));
const args = normalizeSshCommandArgs(remoteOptions.args);
const commandName = displayCommandName(args);

function normalizeSshCommandArgs(rawArgs: string[]): string[] {
  if (rawArgs[0] === "ssh") return rawArgs;
  return ["ssh", ...rawArgs];
}

function displayCommandName(normalizedArgs: string[]): string {
  const rawEntrypoint = process.env.UNIDESK_SSH_ENTRYPOINT?.trim();
  const entrypoint = rawEntrypoint === "trans" || rawEntrypoint === "tran" || rawEntrypoint === "ssh" ? rawEntrypoint : "ssh";
  const displayArgs = normalizedArgs[0] === "ssh" ? normalizedArgs.slice(1) : normalizedArgs;
  return [entrypoint, ...displayArgs].join(" ") || entrypoint;
}

function isGhContentRouteTarget(target: string | undefined): boolean {
  return typeof target === "string" && target.startsWith("gh:");
}

interface SshHelpRequest {
  args: string[];
  json: boolean;
}

function parseSshHelpRequest(normalizedArgs: string[]): SshHelpRequest | null {
  const helpArgs = [normalizedArgs[0]];
  let json = false;
  let outputError: CliInputError | null = null;
  for (let index = 1; index < normalizedArgs.length; index += 1) {
    const arg = normalizedArgs[index];
    if (arg === "--json") {
      json = true;
      continue;
    }
    if (arg === "-o") {
      const format = normalizedArgs[index + 1];
      if (format === undefined) {
        outputError = new CliInputError("-o requires an output format", {
          code: "missing-option-value",
          argument: "-o",
          usage: ["trans --help --json", "trans --help -o json"],
        });
      } else if (format !== "json") {
        outputError = new CliInputError(`Unsupported trans help output format: ${format}`, {
          code: "unsupported-output-format",
          argument: format,
          supported: ["json"],
          usage: ["trans --help --json", "trans --help -o json"],
        });
      } else {
        json = true;
      }
      index += format === undefined ? 0 : 1;
      continue;
    }
    helpArgs.push(arg);
  }

  const [, sub, third] = helpArgs;
  const helpFirst = isHelpToken(sub);
  const routeFirst = helpArgs.length === 3 && isHelpToken(third);
  if (!helpFirst && !routeFirst) return null;
  if (outputError !== null) throw outputError;
  return { args: helpArgs, json };
}

function emitSshHelp(request: SshHelpRequest): void {
  const [, sub, third] = request.args;
  const scope = isHelpToken(sub) ? sshHelpScope(request.args) : undefined;
  if (isHelpToken(sub) && request.args.length > 2 && scope === undefined) {
    throw new CliInputError(`Unknown trans help scope: ${third ?? "<missing>"}`, {
      code: "unknown-help-scope",
      argument: third ?? "",
      usage: ["trans --help", "trans --help <operation>"],
      hint: "Use trans --help to list the bounded operation groups before opening scoped help.",
    });
  }
  if (request.json) emitJson(commandName, sshHelp(scope));
  else emitText(renderSshHelpText(scope), commandName);
}

async function main(): Promise<void> {
  const [top, sub] = args;
  if (top !== "ssh") throw new Error(`ssh-cli supports only the ssh command, got: ${top || "<empty>"}`);

  if (sub === undefined) {
    emitText(renderSshHelpText(), commandName);
    return;
  }

  const helpRequest = parseSshHelpRequest(args);
  if (helpRequest !== null) {
    emitSshHelp(helpRequest);
    return;
  }

  if (remoteOptions.host !== null) {
    process.exitCode = await runRemoteSshCli({ ...remoteOptions, args }, readConfig());
    return;
  }

  if (isGhContentRouteTarget(sub)) {
    const { runGhContentRoute } = await import("./src/gh-route");
    process.exitCode = await runGhContentRoute(sub, args.slice(2));
    return;
  }

  process.exitCode = await runSsh(readConfig(), sub, args.slice(2));
}

main().catch((error) => {
  emitError(commandName, error);
  process.exitCode = 1;
});
