import { JUNCTION_FIELDS, PIPE_FIELDS, type ElementType } from "./constants.js";
import { CliError } from "./errors.js";
import type { OptionSchema, ParsedOptionValue, ParsedOptions } from "./types.js";

export function requireValue(argv: string[], index: number, option: string): string {
  const value = argv[index];
  if (!value || value.startsWith("--")) throw new CliError("CLI 参数错误", "MISSING_OPTION_VALUE", `${option} requires a value`, 2);
  return value;
}

export function parseIntStrict(value: string, option: string): number {
  const parsed = Number.parseInt(value, 10);
  if (!Number.isFinite(parsed)) throw new CliError("CLI 参数错误", "INVALID_INTEGER", `${option} must be an integer`, 2);
  return parsed;
}

export function parseFloatStrict(value: string, option: string): number {
  const parsed = Number.parseFloat(value);
  if (!Number.isFinite(parsed)) throw new CliError("CLI 参数错误", "INVALID_NUMBER", `${option} must be a number`, 2);
  return parsed;
}

export function parseOptions(argv: string[], schema: OptionSchema = {}): ParsedOptions {
  const values: Record<string, ParsedOptionValue> = {};
  const positionals: string[] = [];
  for (let i = 0; i < argv.length; i += 1) {
    const arg = argv[i]!;
    if (!arg.startsWith("--")) {
      positionals.push(arg);
      continue;
    }
    const name = arg.slice(2);
    const kind = schema[name] ?? "string";
    if (kind === "boolean") {
      values[name] = true;
    } else {
      const raw = requireValue(argv, ++i, arg);
      if (kind === "repeat") values[name] = [...asStringArray(values[name]), raw];
      else if (kind === "number") values[name] = parseFloatStrict(raw, arg);
      else if (kind === "integer") values[name] = parseIntStrict(raw, arg);
      else values[name] = raw;
    }
  }
  return { values, positionals };
}

export function required(values: Record<string, ParsedOptionValue>, name: string): string | number | boolean | string[] {
  const value = values[name];
  if (value === undefined || value === null || value === "") {
    throw new CliError("CLI 参数错误", "MISSING_PARAMETER", `Missing option '--${name}'`, 2);
  }
  return value;
}

export function requiredString(values: Record<string, ParsedOptionValue>, name: string): string {
  const value = required(values, name);
  if (typeof value !== "string") throw new CliError("CLI 参数错误", "INVALID_PARAMETER", `--${name} must be a string`, 2);
  return value;
}

export function requiredNumber(values: Record<string, ParsedOptionValue>, name: string): number {
  const value = required(values, name);
  if (typeof value !== "number") throw new CliError("CLI 参数错误", "INVALID_PARAMETER", `--${name} must be a number`, 2);
  return value;
}

export function requiredStringArray(values: Record<string, ParsedOptionValue>, name: string): string[] {
  const value = required(values, name);
  if (!Array.isArray(value)) throw new CliError("CLI 参数错误", "INVALID_PARAMETER", `--${name} must be repeatable`, 2);
  return value;
}

export function optionalString(values: Record<string, ParsedOptionValue>, name: string): string | undefined {
  const value = values[name];
  if (value === undefined) return undefined;
  if (typeof value !== "string") throw new CliError("CLI 参数错误", "INVALID_PARAMETER", `--${name} must be a string`, 2);
  return value;
}

export function optionalNumber(values: Record<string, ParsedOptionValue>, name: string): number | undefined {
  const value = values[name];
  if (value === undefined) return undefined;
  if (typeof value !== "number") throw new CliError("CLI 参数错误", "INVALID_PARAMETER", `--${name} must be a number`, 2);
  return value;
}

export function optionalStringArray(values: Record<string, ParsedOptionValue>, name: string): string[] | undefined {
  const value = values[name];
  if (value === undefined) return undefined;
  if (!Array.isArray(value)) throw new CliError("CLI 参数错误", "INVALID_PARAMETER", `--${name} must be repeatable`, 2);
  return value;
}

export function asStringArray(value: ParsedOptionValue | undefined): string[] {
  if (value === undefined) return [];
  if (Array.isArray(value)) return value;
  throw new CliError("CLI 参数错误", "INVALID_PARAMETER", "repeat option received a non-array value", 2);
}

export function validateChoice<T extends readonly string[]>(value: string, valid: T, option: string): T[number] {
  if (!valid.includes(value)) {
    throw new CliError("CLI 参数错误", `INVALID_${option.replace(/^--/, "").replaceAll("-", "_").toUpperCase()}`, `${option} must be one of: ${valid.join(", ")}`, 2);
  }
  return value as T[number];
}

export function fieldsFor(type: ElementType): typeof PIPE_FIELDS | typeof JUNCTION_FIELDS {
  if (type === "pipe") return PIPE_FIELDS;
  if (type === "junction") return JUNCTION_FIELDS;
  throw new CliError("CLI 参数错误", "INVALID_TYPE", "--type must be one of: pipe, junction", 2);
}

