// Route-first argv parsers for commands that can skip full Commander startup.
import { isValueToken } from "../../infra/cli-root-options.js";
import {
  getCommandPositionalsWithRootOptions,
  getFlagValue,
  getPositiveIntFlagValue,
  getVerboseFlag,
  hasFlag,
} from "../argv.js";
import { parseStrictPositiveIntOrUndefined } from "./helpers.js";

type OptionalFlagParse = {
  ok: boolean;
  value?: string;
};

function parseOptionalFlagValue(argv: string[], name: string): OptionalFlagParse {
  const value = getFlagValue(argv, name);
  if (value === null) {
    return { ok: false };
  }
  return { ok: true, value };
}

function parseRepeatedFlagValues(argv: string[], name: string): string[] | null {
  const values: string[] = [];
  const args = argv.slice(2);
  for (let i = 0; i < args.length; i += 1) {
    const arg = args[i];
    if (!arg || arg === "--") {
      break;
    }
    if (arg === name) {
      const next = args[i + 1];
      if (!isValueToken(next)) {
        // Invalid fast-path shapes fall back to Commander so its normal errors and help text win.
        return null;
      }
      values.push(next);
      i += 1;
      continue;
    }
    if (arg.startsWith(`${name}=`)) {
      const value = arg.slice(name.length + 1).trim();
      if (!value) {
        return null;
      }
      values.push(value);
    }
  }
  return values;
}

function parseSinglePositional(
  argv: string[],
  params: {
    commandPath: string[];
    booleanFlags?: string[];
  },
): string | null {
  const positionals = getCommandPositionalsWithRootOptions(argv, params);
  if (!positionals || positionals.length !== 1) {
    return null;
  }
  return positionals[0] ?? null;
}

/** Parse `openclaw health` flags for the route-first status family. */
export function parseHealthRouteArgs(argv: string[]) {
  const timeoutMs = getPositiveIntFlagValue(argv, "--timeout");
  if (timeoutMs === null) {
    return null;
  }
  return {
    json: hasFlag(argv, "--json"),
    verbose: getVerboseFlag(argv, { includeDebug: true }),
    timeoutMs,
  };
}

/** Parse `openclaw status` flags without registering the full command tree. */
export function parseStatusRouteArgs(argv: string[]) {
  const timeoutMs = getPositiveIntFlagValue(argv, "--timeout");
  if (timeoutMs === null) {
    return null;
  }
  return {
    json: hasFlag(argv, "--json"),
    deep: hasFlag(argv, "--deep"),
    all: hasFlag(argv, "--all"),
    usage: hasFlag(argv, "--usage"),
    verbose: getVerboseFlag(argv, { includeDebug: true }),
    timeoutMs,
  };
}

/** Parse `openclaw gateway status` RPC-only flags accepted by the fast route. */
export function parseGatewayStatusRouteArgs(argv: string[]) {
  const url = parseOptionalFlagValue(argv, "--url");
  if (!url.ok) {
    return null;
  }
  const token = parseOptionalFlagValue(argv, "--token");
  if (!token.ok) {
    return null;
  }
  const password = parseOptionalFlagValue(argv, "--password");
  if (!password.ok) {
    return null;
  }
  const timeout = parseOptionalFlagValue(argv, "--timeout");
  if (!timeout.ok) {
    return null;
  }
  const ssh = parseOptionalFlagValue(argv, "--ssh");
  if (!ssh.ok || ssh.value !== undefined) {
    // SSH probe options need the full command because they resolve host aliases and identity files.
    return null;
  }
  const sshIdentity = parseOptionalFlagValue(argv, "--ssh-identity");
  if (!sshIdentity.ok || sshIdentity.value !== undefined) {
    return null;
  }
  if (hasFlag(argv, "--ssh-auto")) {
    return null;
  }
  return {
    rpc: {
      url: url.value,
      token: token.value,
      password: password.value,
      timeout: timeout.value,
    },
    deep: hasFlag(argv, "--deep"),
    json: hasFlag(argv, "--json"),
    requireRpc: hasFlag(argv, "--require-rpc"),
    probe: !hasFlag(argv, "--no-probe"),
  };
}

/** Parse `openclaw sessions` filters for JSON/list route execution. */
export function parseSessionsRouteArgs(argv: string[]) {
  const agent = parseOptionalFlagValue(argv, "--agent");
  if (!agent.ok) {
    return null;
  }
  const store = parseOptionalFlagValue(argv, "--store");
  if (!store.ok) {
    return null;
  }
  const active = parseOptionalFlagValue(argv, "--active");
  if (!active.ok) {
    return null;
  }
  const limit = parseOptionalFlagValue(argv, "--limit");
  if (!limit.ok) {
    return null;
  }
  return {
    json: hasFlag(argv, "--json"),
    allAgents: hasFlag(argv, "--all-agents"),
    agent: agent.value,
    store: store.value,
    active: active.value,
    limit: limit.value,
  };
}

/** Parse `openclaw agents list` display switches for route-first execution. */
export function parseAgentsListRouteArgs(argv: string[]) {
  return {
    json: hasFlag(argv, "--json"),
    bindings: hasFlag(argv, "--bindings"),
  };
}

/** Parse `openclaw config get <path>` while preserving root option handling. */
export function parseConfigGetRouteArgs(argv: string[]) {
  const path = parseSinglePositional(argv, {
    commandPath: ["config", "get"],
    booleanFlags: ["--json"],
  });
  if (!path) {
    return null;
  }
  return {
    path,
    json: hasFlag(argv, "--json"),
  };
}

/** Parse `openclaw config unset <path>` and its mutation guard flags. */
export function parseConfigUnsetRouteArgs(argv: string[]) {
  const path = parseSinglePositional(argv, {
    commandPath: ["config", "unset"],
    booleanFlags: ["--dry-run", "--allow-exec", "--json"],
  });
  if (!path) {
    return null;
  }
  return {
    path,
    cliOptions: {
      dryRun: hasFlag(argv, "--dry-run"),
      allowExec: hasFlag(argv, "--allow-exec"),
      json: hasFlag(argv, "--json"),
    },
  };
}

/** Parse `openclaw models list` filters for the lightweight model catalog route. */
export function parseModelsListRouteArgs(argv: string[]) {
  const provider = parseOptionalFlagValue(argv, "--provider");
  if (!provider.ok) {
    return null;
  }
  return {
    provider: provider.value,
    all: hasFlag(argv, "--all"),
    local: hasFlag(argv, "--local"),
    json: hasFlag(argv, "--json"),
    plain: hasFlag(argv, "--plain"),
  };
}

/** Parse `openclaw models status` probe controls for the route-first status path. */
export function parseModelsStatusRouteArgs(argv: string[]) {
  const probeProvider = parseOptionalFlagValue(argv, "--probe-provider");
  if (!probeProvider.ok) {
    return null;
  }
  const probeTimeout = parseOptionalFlagValue(argv, "--probe-timeout");
  if (!probeTimeout.ok) {
    return null;
  }
  const probeConcurrency = parseOptionalFlagValue(argv, "--probe-concurrency");
  if (!probeConcurrency.ok) {
    return null;
  }
  const probeMaxTokens = parseOptionalFlagValue(argv, "--probe-max-tokens");
  if (!probeMaxTokens.ok) {
    return null;
  }
  const agent = parseOptionalFlagValue(argv, "--agent");
  if (!agent.ok) {
    return null;
  }
  const probeProfileValues = parseRepeatedFlagValues(argv, "--probe-profile");
  if (probeProfileValues === null) {
    return null;
  }
  const probeProfile =
    probeProfileValues.length === 0
      ? undefined
      : probeProfileValues.length === 1
        ? probeProfileValues[0]
        : probeProfileValues;
  return {
    probeProvider: probeProvider.value,
    probeTimeout: probeTimeout.value,
    probeConcurrency: probeConcurrency.value,
    probeMaxTokens: probeMaxTokens.value,
    agent: agent.value,
    probeProfile,
    json: hasFlag(argv, "--json"),
    plain: hasFlag(argv, "--plain"),
    check: hasFlag(argv, "--check"),
    probe: hasFlag(argv, "--probe"),
  };
}

/** Parse `openclaw channels list` display flags for the route-first list path. */
export function parseChannelsListRouteArgs(argv: string[]) {
  return {
    json: hasFlag(argv, "--json"),
    all: hasFlag(argv, "--all"),
  };
}

/** Parse `openclaw channels status` probe flags without full CLI registration. */
export function parseChannelsStatusRouteArgs(argv: string[]) {
  const timeout = parseOptionalFlagValue(argv, "--timeout");
  const channel = parseOptionalFlagValue(argv, "--channel");
  if (!timeout.ok) {
    return null;
  }
  if (!channel.ok) {
    return null;
  }
  return {
    channel: channel.value,
    json: hasFlag(argv, "--json"),
    probe: hasFlag(argv, "--probe"),
    timeout: timeout.value,
  };
}

/** Parse JSON-only `openclaw plugins list` flags for plugin inventory output. */
export function parsePluginsListRouteArgs(argv: string[]) {
  if (!hasFlag(argv, "--json")) {
    return null;
  }
  const positionals = getCommandPositionalsWithRootOptions(argv, {
    commandPath: ["plugins", "list"],
    booleanFlags: ["--json", "--enabled", "--verbose"],
  });
  if (!positionals || positionals.length !== 0) {
    return null;
  }
  return {
    json: true as const,
    enabled: hasFlag(argv, "--enabled"),
    verbose: hasFlag(argv, "--verbose"),
  };
}

function parseTasksListRouteArgsForCommandPath(argv: string[], commandPath: string[]) {
  if (!hasFlag(argv, "--json")) {
    return null;
  }
  const positionals = getCommandPositionalsWithRootOptions(argv, {
    commandPath,
    booleanFlags: ["--json"],
    valueFlags: ["--runtime", "--status"],
  });
  if (!positionals || positionals.length !== 0) {
    return null;
  }
  const runtime = parseOptionalFlagValue(argv, "--runtime");
  if (!runtime.ok) {
    return null;
  }
  const status = parseOptionalFlagValue(argv, "--status");
  if (!status.ok) {
    return null;
  }
  return {
    json: true as const,
    runtime: runtime.value,
    status: status.value,
  };
}

/** Parse both `openclaw tasks --json` and `openclaw tasks list --json` aliases. */
export function parseTasksListRouteArgs(argv: string[]) {
  return (
    parseTasksListRouteArgsForCommandPath(argv, ["tasks"]) ??
    parseTasksListRouteArgsForCommandPath(argv, ["tasks", "list"])
  );
}

/** Parse JSON-only `openclaw tasks audit` filters for the route-first audit path. */
export function parseTasksAuditRouteArgs(argv: string[]) {
  if (!hasFlag(argv, "--json")) {
    return null;
  }
  const positionals = getCommandPositionalsWithRootOptions(argv, {
    commandPath: ["tasks", "audit"],
    booleanFlags: ["--json"],
    valueFlags: ["--severity", "--code", "--limit"],
  });
  if (!positionals || positionals.length !== 0) {
    return null;
  }
  const severity = parseOptionalFlagValue(argv, "--severity");
  if (!severity.ok) {
    return null;
  }
  const code = parseOptionalFlagValue(argv, "--code");
  if (!code.ok) {
    return null;
  }
  const rawLimit = getFlagValue(argv, "--limit");
  if (rawLimit === null) {
    return null;
  }
  const limit = rawLimit === undefined ? undefined : parseStrictPositiveIntOrUndefined(rawLimit);
  if (rawLimit !== undefined && limit === undefined) {
    return null;
  }
  return {
    json: true as const,
    severity: severity.value,
    code: code.value,
    limit,
  };
}
