import { defaultCodexPoolRuntimeTargetId } from "./runtime-target";

export type RuntimeAction = "list" | "get" | "errors" | "events" | "infrastructure" | "apply" | "delete";

export interface RuntimeOptions {
  action: RuntimeAction;
  account: string | null;
  accounts: string[];
  selectConfiguredPolicy: boolean;
  accountType: "apikey" | null;
  excludeAccounts: string[];
  group: string | null;
  allGroups: boolean;
  platform: string | null;
  pageToken: string | null;
  template: string | null;
  kind: "temp-unschedulable" | "priority" | "account-name" | "capacity";
  priority: number | null;
  capacity: number | null;
  name: string | null;
  confirm: boolean;
  full: boolean;
  raw: boolean;
  json: boolean;
  recent: string | null;
  since: string;
  tail: number;
  targetId: string;
}

export function parseRuntimeOptions(args: string[]): RuntimeOptions {
  const [actionRaw = "list", ...rest] = args;
  if (!(["list", "get", "errors", "events", "infrastructure", "apply", "delete"] as string[]).includes(actionRaw)) {
    throw new Error("runtime usage: list|get|errors|events|infrastructure|apply|delete [--account <name-or-id>|--accounts <selectors>|--select-configured-policy --account-type apikey [--exclude-accounts <selectors>]] [--recent 24h] [--group <name-or-id>|--all-groups] [--platform <name>] [--page-token <token>] [--since 24h] [--tail 50000] [--template <id>] [--kind temp-unschedulable|priority|account-name|capacity] [--priority <0-1000>|--name <account-name>|--capacity <1-100000>] [--confirm] [--target <id>] [--json|--full|--raw]");
  }
  let account: string | null = null;
  let accounts: string[] = [];
  let selectConfiguredPolicy = false;
  let accountType: "apikey" | null = null;
  let excludeAccounts: string[] = [];
  let group: string | null = null;
  let allGroups = false;
  let platform: string | null = null;
  let pageToken: string | null = null;
  let template: string | null = null;
  let kind: "temp-unschedulable" | "priority" | "account-name" | "capacity" = "temp-unschedulable";
  let priority: number | null = null;
  let capacity: number | null = null;
  let name: string | null = null;
  let confirm = false;
  let full = false;
  let raw = false;
  let json = false;
  let recent: string | null = null;
  let since = "24h";
  let tail = 50_000;
  let targetId = defaultCodexPoolRuntimeTargetId();
  for (let index = 0; index < rest.length; index += 1) {
    const arg = rest[index]!;
    const readValue = (name: string): string => {
      const value = rest[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error(`${name} requires a value`);
      index += 1;
      return value.trim();
    };
    if (arg === "--confirm") confirm = true;
    else if (arg === "--full") full = true;
    else if (arg === "--raw") raw = true;
    else if (arg === "--json") json = true;
    else if (arg === "-o" && readValue("-o") === "json") json = true;
    else if (arg === "--account") account = readValue("--account");
    else if (arg.startsWith("--account=")) account = arg.slice("--account=".length).trim();
    else if (arg === "--accounts") accounts = parseAccountSelectors(readValue("--accounts"));
    else if (arg.startsWith("--accounts=")) accounts = parseAccountSelectors(arg.slice("--accounts=".length));
    else if (arg === "--select-configured-policy") selectConfiguredPolicy = true;
    else if (arg === "--account-type") accountType = parseAccountType(readValue("--account-type"));
    else if (arg.startsWith("--account-type=")) accountType = parseAccountType(arg.slice("--account-type=".length));
    else if (arg === "--exclude-accounts") excludeAccounts = parseAccountSelectors(readValue("--exclude-accounts"), "--exclude-accounts");
    else if (arg.startsWith("--exclude-accounts=")) excludeAccounts = parseAccountSelectors(arg.slice("--exclude-accounts=".length), "--exclude-accounts");
    else if (arg === "--group") group = readValue("--group");
    else if (arg.startsWith("--group=")) group = arg.slice("--group=".length).trim();
    else if (arg === "--all-groups") allGroups = true;
    else if (arg === "--platform") platform = readValue("--platform");
    else if (arg.startsWith("--platform=")) platform = arg.slice("--platform=".length).trim();
    else if (arg === "--page-token") pageToken = readValue("--page-token");
    else if (arg.startsWith("--page-token=")) pageToken = arg.slice("--page-token=".length).trim();
    else if (arg === "--template") template = readValue("--template");
    else if (arg.startsWith("--template=")) template = arg.slice("--template=".length).trim();
    else if (arg === "--kind") kind = parseRuntimeKind(readValue("--kind"));
    else if (arg.startsWith("--kind=")) kind = parseRuntimeKind(arg.slice("--kind=".length));
    else if (arg === "--priority") priority = parsePriority(readValue("--priority"));
    else if (arg.startsWith("--priority=")) priority = parsePriority(arg.slice("--priority=".length));
    else if (arg === "--capacity") capacity = parseCapacity(readValue("--capacity"));
    else if (arg.startsWith("--capacity=")) capacity = parseCapacity(arg.slice("--capacity=".length));
    else if (arg === "--name") name = readValue("--name");
    else if (arg.startsWith("--name=")) name = arg.slice("--name=".length).trim();
    else if (arg === "--target") targetId = readValue("--target");
    else if (arg.startsWith("--target=")) targetId = arg.slice("--target=".length).trim();
    else if (arg === "--recent") recent = parseDuration(readValue("--recent"), "--recent");
    else if (arg.startsWith("--recent=")) recent = parseDuration(arg.slice("--recent=".length), "--recent");
    else if (arg === "--since") since = readValue("--since");
    else if (arg.startsWith("--since=")) since = arg.slice("--since=".length).trim();
    else if (arg === "--tail") tail = parseRuntimeTail(readValue("--tail"));
    else if (arg.startsWith("--tail=")) tail = parseRuntimeTail(arg.slice("--tail=".length));
    else throw new Error(`unsupported runtime option: ${arg}`);
  }
  const action = actionRaw as RuntimeAction;
  if (account !== null && accounts.length > 0) throw new Error("use only one of --account or --accounts");
  if (selectConfiguredPolicy && (account !== null || accounts.length > 0)) throw new Error("--select-configured-policy cannot be combined with --account or --accounts");
  if ((action === "get" || action === "infrastructure") && !account) throw new Error(`runtime ${action} requires --account <name-or-id>`);
  if ((action === "apply" || action === "delete") && account === null && accounts.length === 0 && !selectConfiguredPolicy) {
    throw new Error(`runtime ${action} requires --account, --accounts, or --select-configured-policy`);
  }
  if (accounts.length > 0 && action !== "apply" && action !== "delete") throw new Error(`runtime ${action} does not accept --accounts`);
  if (account !== null && (account.length > 256 || /[\r\n]/u.test(account))) throw new Error("--account has an unsupported format");
  if (group !== null && (group.length > 256 || /[\r\n]/u.test(group))) throw new Error("--group has an unsupported format");
  if (platform !== null && (!/^[A-Za-z0-9._-]+$/u.test(platform) || platform.length > 64)) throw new Error("--platform has an unsupported format");
  if (pageToken !== null && (!/^\d+$/u.test(pageToken) || pageToken.length > 20)) throw new Error("--page-token must be a numeric group cursor");
  if (group !== null && allGroups) throw new Error("use only one of --group or --all-groups");
  if ((allGroups || pageToken !== null) && action !== "errors") throw new Error(`runtime ${action} does not accept all-groups pagination options`);
  if ((group !== null || platform !== null) && action !== "errors" && action !== "infrastructure") throw new Error(`runtime ${action} does not accept group scope options`);
  if (recent !== null && action !== "list") throw new Error(`runtime ${action} does not accept --recent`);
  if (pageToken !== null && !allGroups) throw new Error("--page-token requires --all-groups");
  if (account !== null && allGroups) throw new Error("--account cannot be combined with --all-groups; use --group first");
  if (selectConfiguredPolicy && !((action === "apply" || action === "delete") && kind === "temp-unschedulable")) {
    throw new Error("--select-configured-policy only supports runtime apply|delete --kind temp-unschedulable");
  }
  if (selectConfiguredPolicy && accountType === null) throw new Error("--select-configured-policy requires --account-type apikey");
  if (!selectConfiguredPolicy && accountType !== null) throw new Error("--account-type requires --select-configured-policy");
  if (!selectConfiguredPolicy && excludeAccounts.length > 0) throw new Error("--exclude-accounts requires --select-configured-policy");
  if (action === "apply" && kind === "temp-unschedulable" && !template) throw new Error("runtime apply --kind temp-unschedulable requires --template <id>");
  if (kind === "priority" && action !== "apply") throw new Error("runtime --kind priority only supports apply");
  if (kind === "priority" && priority === null) throw new Error("runtime apply --kind priority requires --priority <0-1000>");
  if (kind === "priority" && template !== null) throw new Error("runtime apply --kind priority does not accept --template");
  if (kind !== "priority" && priority !== null) throw new Error("--priority requires --kind priority");
  if (kind === "capacity" && action !== "apply") throw new Error("runtime --kind capacity only supports apply");
  if (kind === "capacity" && capacity === null) throw new Error("runtime apply --kind capacity requires --capacity <1-100000>");
  if (kind === "capacity" && template !== null) throw new Error("runtime apply --kind capacity does not accept --template");
  if (kind !== "capacity" && capacity !== null) throw new Error("--capacity requires --kind capacity");
  if (kind === "account-name" && action !== "apply") throw new Error("runtime --kind account-name only supports apply");
  if (kind === "account-name" && (name === null || name.length === 0 || name.length > 256 || /[\r\n]/u.test(name))) {
    throw new Error("runtime apply --kind account-name requires --name with a supported account name");
  }
  if (kind === "account-name" && accounts.length > 0) throw new Error("runtime account-name updates exactly one --account at a time");
  if (kind === "account-name" && template !== null) throw new Error("runtime apply --kind account-name does not accept --template");
  if (kind !== "account-name" && name !== null) throw new Error("--name requires --kind account-name");
  if (action !== "apply" && template !== null) throw new Error(`runtime ${action} does not accept --template`);
  if (action !== "errors" && action !== "events" && action !== "infrastructure" && (since !== "24h" || tail !== 50_000)) throw new Error(`runtime ${action} does not accept --since or --tail`);
  if (!/^\d+[mhd]$/u.test(since)) throw new Error("--since must use <number>m, <number>h, or <number>d");
  if (["list", "get", "errors", "events", "infrastructure"].includes(action) && confirm) throw new Error(`runtime ${action} does not accept --confirm`);
  if ([full, raw, json].filter(Boolean).length > 1) throw new Error("use only one of --json, --full, or --raw");
  return { action, account, accounts, selectConfiguredPolicy, accountType, excludeAccounts, group, allGroups, platform, pageToken, template, kind, priority, capacity, name, confirm, full, raw, json, recent, since, tail, targetId };
}

function parseDuration(value: string, option: string): string {
  const normalized = value.trim();
  if (!/^[1-9]\d*[mhd]$/u.test(normalized)) throw new Error(`${option} must use <positive-number>m, <positive-number>h, or <positive-number>d`);
  return normalized;
}

function parseAccountSelectors(value: string, option = "--accounts"): string[] {
  const selectors = value.split(",").map((item) => item.trim()).filter(Boolean);
  if (selectors.length === 0 || selectors.length > 100) throw new Error(`${option} requires 1 to 100 comma-separated selectors`);
  if (selectors.some((item) => item.length > 256 || /[\r\n]/u.test(item))) throw new Error(`${option} has an unsupported selector`);
  if (new Set(selectors).size !== selectors.length) throw new Error(`${option} contains duplicate selectors`);
  return selectors;
}

function parseAccountType(value: string): "apikey" {
  if (value !== "apikey") throw new Error("--account-type currently supports only apikey");
  return value;
}

function parseRuntimeKind(value: string): "temp-unschedulable" | "priority" | "account-name" | "capacity" {
  if (value !== "temp-unschedulable" && value !== "priority" && value !== "account-name" && value !== "capacity") throw new Error("--kind must be temp-unschedulable, priority, account-name, or capacity");
  return value;
}

function parseCapacity(value: string): number {
  const parsed = Number(value);
  if (!Number.isInteger(parsed) || parsed < 1 || parsed > 100_000) throw new Error("--capacity must be an integer from 1 to 100000");
  return parsed;
}

function parsePriority(value: string): number {
  const parsed = Number(value);
  if (!Number.isInteger(parsed) || parsed < 0 || parsed > 1000) throw new Error("--priority must be an integer from 0 to 1000");
  return parsed;
}

function parseRuntimeTail(value: string): number {
  const parsed = Number(value);
  if (!Number.isInteger(parsed) || parsed < 100 || parsed > 200_000) throw new Error("--tail must be an integer from 100 to 200000");
  return parsed;
}
