import { ArgToken } from "./parser-C6MbpZjd.js";

//#region src/resolver.d.ts

/**
 * An argument schema definition for command-line argument parsing.
 *
 * This schema is similar to the schema of Node.js `util.parseArgs` but with extended features:
 * - Additional `required` and `description` properties
 * - Extended `type` support: 'string', 'boolean', 'number', 'enum', 'positional', 'custom'
 * - Simplified `default` property (single type, not union types)
 *
 * @example
 * Basic string argument:
 * ```ts
 * const schema: ArgSchema = {
 *   type: 'string',
 *   description: 'Server hostname',
 *   default: 'localhost'
 * }
 * ```
 *
 * @example
 * Required number argument with alias:
 * ```ts
 * const schema: ArgSchema = {
 *   type: 'number',
 *   short: 'p',
 *   description: 'Port number to listen on',
 *   required: true
 * }
 * ```
 *
 * @example
 * Enum argument with choices:
 * ```ts
 * const schema: ArgSchema = {
 *   type: 'enum',
 *   choices: ['info', 'warn', 'error'],
 *   description: 'Logging level',
 *   default: 'info'
 * }
 * ```
 */
interface ArgSchema {
  /**
   * Type of the argument value.
   *
   * - `'string'`: Text value (default if not specified)
   * - `'boolean'`: `true`/`false` flag (can be negatable with `--no-` prefix)
   * - `'number'`: Numeric value (parsed as integer or float)
   * - `'enum'`: One of predefined string values (requires `choices` property)
   * - `'positional'`: Non-option argument by position
   * - `'custom'`: Custom parsing with user-defined `parse` function
   *
   * @example
   * Different argument types:
   * ```ts
   * {
   *   name: { type: 'string' },        // --name value
   *   verbose: { type: 'boolean' },     // --verbose or --no-verbose
   *   port: { type: 'number' },         // --port 3000
   *   level: { type: 'enum', choices: ['debug', 'info'] },
   *   file: { type: 'positional' },     // first positional arg
   *   config: { type: 'custom', parse: JSON.parse }
   * }
   * ```
   */
  type: 'string' | 'boolean' | 'number' | 'enum' | 'positional' | 'custom';
  /**
   * Single character alias for the long option name.
   *
   * As example, allows users to use `-x` instead of `--extended-option`.
   * Only valid for non-positional argument types.
   *
   * @example
   * Short alias usage:
   * ```ts
   * {
   *   verbose: {
   *     type: 'boolean',
   *     short: 'v'  // Enables both --verbose and -v
   *   },
   *   port: {
   *     type: 'number',
   *     short: 'p'  // Enables both --port 3000 and -p 3000
   *   }
   * }
   * ```
   */
  short?: string;
  /**
   * Human-readable description of the argument's purpose.
   *
   * Used for help text generation and documentation.
   * Should be concise but descriptive enough to understand the argument's role.
   *
   * @example
   * Descriptive help text:
   * ```ts
   * {
   *   config: {
   *     type: 'string',
   *     description: 'Path to configuration file'
   *   },
   *   timeout: {
   *     type: 'number',
   *     description: 'Request timeout in milliseconds'
   *   }
   * }
   * ```
   */
  description?: string;
  /**
   * Marks the argument as required.
   *
   * When `true`, the argument must be provided by the user.
   * If missing, an `ArgResolveError` with type 'required' will be thrown.
   *
   * Note: Only `true` is allowed (not `false`) to make intent explicit.
   *
   * @example
   * Required arguments:
   * ```ts
   * {
   *   input: {
   *     type: 'string',
   *     required: true,  // Must be provided: --input file.txt
   *     description: 'Input file path'
   *   },
   *   source: {
   *     type: 'positional',
   *     required: true   // First positional argument must exist
   *   }
   * }
   * ```
   */
  required?: true;
  /**
   * Allows the argument to accept multiple values.
   *
   * When `true`, the resolved value becomes an array.
   * For options: can be specified multiple times (--tag foo --tag bar)
   * For positional: collects remaining positional arguments
   *
   * Note: Only `true` is allowed (not `false`) to make intent explicit.
   *
   * @example
   * Multiple values:
   * ```ts
   * {
   *   tags: {
   *     type: 'string',
   *     multiple: true,  // --tags foo --tags bar → ['foo', 'bar']
   *     description: 'Tags to apply'
   *   },
   *   files: {
   *     type: 'positional',
   *     multiple: true   // Collects all remaining positional args
   *   }
   * }
   * ```
   */
  multiple?: true;
  /**
   * Enables negation for boolean arguments using `--no-` prefix.
   *
   * When `true`, allows users to explicitly set the boolean to `false`
   * using `--no-option-name`. When `false` or omitted, only positive
   * form is available.
   *
   * Only applicable to `type: 'boolean'` arguments.
   *
   * @example
   * Negatable boolean:
   * ```ts
   * {
   *   color: {
   *     type: 'boolean',
   *     negatable: true,
   *     default: true,
   *     description: 'Enable colorized output'
   *   }
   *   // Usage: --color (true), --no-color (false)
   * }
   * ```
   */
  negatable?: boolean;
  /**
   * Array of allowed string values for enum-type arguments.
   *
   * Required when `type: 'enum'`. The argument value must be one of these choices,
   * otherwise an `ArgResolveError` with type 'type' will be thrown.
   *
   * Supports both mutable arrays and readonly arrays for type safety.
   *
   * @example
   * Enum choices:
   * ```ts
   * {
   *   logLevel: {
   *     type: 'enum',
   *     choices: ['debug', 'info', 'warn', 'error'] as const,
   *     default: 'info',
   *     description: 'Logging verbosity level'
   *   },
   *   format: {
   *     type: 'enum',
   *     choices: ['json', 'yaml', 'toml'],
   *     description: 'Output format'
   *   }
   * }
   * ```
   */
  choices?: string[] | readonly string[];
  /**
   * Default value used when the argument is not provided.
   *
   * The type must match the argument's `type` property:
   * - `string` type: string default
   * - `boolean` type: boolean default
   * - `number` type: number default
   * - `enum` type: must be one of the `choices` values
   * - `positional`/`custom` type: any appropriate default
   *
   * @example
   * Default values by type:
   * ```ts
   * {
   *   host: {
   *     type: 'string',
   *     default: 'localhost'  // string default
   *   },
   *   verbose: {
   *     type: 'boolean',
   *     default: false        // boolean default
   *   },
   *   port: {
   *     type: 'number',
   *     default: 8080         // number default
   *   },
   *   level: {
   *     type: 'enum',
   *     choices: ['low', 'high'],
   *     default: 'low'        // must be in choices
   *   }
   * }
   * ```
   */
  default?: string | boolean | number;
  /**
   * Converts the argument name from camelCase to kebab-case for CLI usage.
   *
   * When `true`, a property like `maxCount` becomes available as `--max-count`.
   * This allows [CAC](https://github.com/cacjs/cac) user-friendly property names while maintaining CLI conventions.
   *
   * Can be overridden globally with `resolveArgs({ toKebab: true })`.
   *
   * Note: Only `true` is allowed (not `false`) to make intent explicit.
   *
   * @example
   * Kebab-case conversion:
   * ```ts
   * {
   *   maxRetries: {
   *     type: 'number',
   *     toKebab: true,        // Accessible as --max-retries
   *     description: 'Maximum retry attempts'
   *   },
   *   enableLogging: {
   *     type: 'boolean',
   *     toKebab: true         // Accessible as --enable-logging
   *   }
   * }
   * ```
   */
  toKebab?: true;
  /**
   * Names of other options that conflict with this option.
   *
   * When this option is used together with any of the conflicting options,
   * an `ArgResolveError` with type 'conflict' will be thrown.
   *
   * Conflicts only need to be defined on one side - if option A defines a conflict
   * with option B, the conflict is automatically detected when both are used,
   * regardless of whether B also defines a conflict with A.
   *
   * Supports both single option name or array of option names.
   * Option names must match the property keys in the schema object exactly
   * (no automatic conversion between camelCase and kebab-case).
   *
   * @example
   * Single conflict (bidirectional definition):
   * ```ts
   * {
   *   summer: {
   *     type: 'boolean',
   *     conflicts: 'autumn'  // Cannot use --summer with --autumn
   *   },
   *   autumn: {
   *     type: 'boolean',
   *     conflicts: 'summer'  // Can define on both sides for clarity
   *   }
   * }
   * ```
   *
   * @example
   * Single conflict (one-way definition):
   * ```ts
   * {
   *   summer: {
   *     type: 'boolean',
   *     conflicts: 'autumn'  // Only defined on summer side
   *   },
   *   autumn: {
   *     type: 'boolean'
   *     // No conflicts defined, but still cannot use with --summer
   *   }
   * }
   * // Usage: --summer --autumn will throw error
   * // Error: "Optional argument '--summer' conflicts with '--autumn'"
   * ```
   *
   * @example
   * Multiple conflicts:
   * ```ts
   * {
   *   port: {
   *     type: 'number',
   *     conflicts: ['socket', 'pipe'],  // Cannot use with --socket or --pipe
   *     description: 'TCP port number'
   *   },
   *   socket: {
   *     type: 'string',
   *     conflicts: ['port', 'pipe'],    // Cannot use with --port or --pipe
   *     description: 'Unix socket path'
   *   },
   *   pipe: {
   *     type: 'string',
   *     conflicts: ['port', 'socket'],  // Cannot use with --port or --socket
   *     description: 'Named pipe path'
   *   }
   * }
   * // These three options are mutually exclusive
   * ```
   *
   * @example
   * With kebab-case conversion:
   * ```ts
   * {
   *   summerSeason: {
   *     type: 'boolean',
   *     toKebab: true,  // Accessible as --summer-season
   *     conflicts: 'autumnSeason'  // Must use property key, not CLI name
   *   },
   *   autumnSeason: {
   *     type: 'boolean',
   *     toKebab: true  // Accessible as --autumn-season
   *   }
   * }
   * // Error: "Optional argument '--summer-season' conflicts with '--autumn-season'"
   * ```
   */
  conflicts?: string | string[];
  /**
   * Custom parsing function for `type: 'custom'` arguments.
   *
   * Required when `type: 'custom'`. Receives the raw string value and must
   * return the parsed result. Should throw an Error (or subclass) if parsing fails.
   *
   * The function's return type becomes the resolved argument type.
   *
   * @param value - Raw string value from command line
   * @returns Parsed value of any type
   * @throws Error or subclass when value is invalid
   *
   * @example
   * Custom parsing functions:
   * ```ts
   * {
   *   config: {
   *     type: 'custom',
   *     parse: (value: string) => {
   *       try {
   *         return JSON.parse(value)  // Parse JSON config
   *       } catch {
   *         throw new Error('Invalid JSON configuration')
   *       }
   *     },
   *     description: 'JSON configuration object'
   *   },
   *   date: {
   *     type: 'custom',
   *     parse: (value: string) => {
   *       const date = new Date(value)
   *       if (isNaN(date.getTime())) {
   *         throw new Error('Invalid date format')
   *       }
   *       return date
   *     }
   *   }
   * }
   * ```
   */
  parse?: (value: string) => any;
}
/**
 * An object that contains {@link ArgSchema | argument schema}.
 *
 * This type is used to define the structure and validation rules for command line arguments.
 */
interface Args {
  [option: string]: ArgSchema;
}
/**
 * An object that contains the values of the arguments.
 *
 * @typeParam T - {@link Args | Arguments} which is an object that defines the command line arguments.
 */
type ArgValues<T> = T extends Args ? ResolveArgValues<T, { [Arg in keyof T]: ExtractOptionValue<T[Arg]> }> : {
  [option: string]: string | boolean | number | (string | boolean | number)[] | undefined;
};
type IsFunction<T> = T extends ((...args: any[]) => any) ? true : false;
/**
 * Extracts the value type from the argument schema.
 *
 * @typeParam A - {@link ArgSchema | Argument schema} which is an object that defines command line arguments.
 *
 * @internal
 */
type ExtractOptionValue<A extends ArgSchema> = A['type'] extends 'string' ? ResolveOptionValue<A, string> : A['type'] extends 'boolean' ? ResolveOptionValue<A, boolean> : A['type'] extends 'number' ? ResolveOptionValue<A, number> : A['type'] extends 'positional' ? ResolveOptionValue<A, string> : A['type'] extends 'enum' ? A['choices'] extends string[] | readonly string[] ? ResolveOptionValue<A, A['choices'][number]> : never : A['type'] extends 'custom' ? IsFunction<A['parse']> extends true ? ResolveOptionValue<A, ReturnType<NonNullable<A['parse']>>> : never : ResolveOptionValue<A, string | boolean | number>;
type ResolveOptionValue<A extends ArgSchema, T> = A['multiple'] extends true ? T[] : T;
/**
 * Resolved argument values.
 *
 * @typeParam A - {@link Arguments | Args} which is an object that defines the command line arguments.
 * @typeParam V - Resolvable argument values.
 *
 * @internal
 */
type ResolveArgValues<A extends Args, V extends Record<keyof A, unknown>> = { -readonly [Arg in keyof A]?: V[Arg] } & FilterArgs<A, V, 'default'> & FilterArgs<A, V, 'required'> & FilterPositionalArgs<A, V> extends infer P ? { [K in keyof P]: P[K] } : never;
/**
 * Filters the arguments based on their default values.
 *
 * @typeParam A - {@link Args | Arguments}, which is an object that defines the command line arguments.
 * @typeParam V - Resolvable argument values.
 * @typeParam K - Key of the {@link ArgSchema | argument schema} to filter by.
 *
 * @internal
 */
type FilterArgs<A extends Args, V extends Record<keyof A, unknown>, K extends keyof ArgSchema> = { [Arg in keyof A as A[Arg][K] extends {} ? Arg : never]: V[Arg] };
/**
 * Filters positional arguments from the argument schema.
 *
 * @typeParam A - {@link Args | Arguments}, which is an object that defines the command line arguments.
 * @typeParam V - Resolvable argument values.
 *
 * @internal
 */
type FilterPositionalArgs<A extends Args, V extends Record<keyof A, unknown>> = { [Arg in keyof A as A[Arg]['type'] extends 'positional' ? Arg : never]: V[Arg] };
/**
 * An arguments for {@link resolveArgs | resolve arguments}.
 */
interface ResolveArgs {
  /**
   * Whether to group short arguments.
   *
   * @see guideline 5 in https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap12.html
   *
   * @default false
   */
  shortGrouping?: boolean;
  /**
   * Skip positional arguments index.
   *
   * @default -1
   */
  skipPositional?: number;
  /**
   * Whether to convert the argument name to kebab-case. This option is applied to all arguments as `toKebab: true`, if set to `true`.
   *
   * @default false
   */
  toKebab?: boolean;
}
/**
 * Tracks which arguments were explicitly provided by the user.
 *
 * Each property indicates whether the corresponding argument was explicitly
 * provided (true) or is using a default value or not provided (false).
 *
 * @typeParam A - {@link Args | Arguments}, which is an object that defines the command line arguments.
 */
type ArgExplicitlyProvided<A extends Args> = { [K in keyof A]: boolean };
/**
 * Resolve command line arguments.
 *
 * @typeParam A - {@link Args | Arguments}, which is an object that defines the command line arguments.
 *
 * @param args - An arguments that contains {@link ArgSchema | arguments schema}.
 * @param tokens - An array of {@link ArgToken | tokens}.
 * @param resolveArgs - An arguments that contains {@link ResolveArgs | resolve arguments}.
 * @returns An object that contains the values of the arguments, positional arguments, rest arguments, {@link AggregateError | validation errors}, and explicit provision status.
 *
 * @example
 * ```typescript
 * // passed tokens: --port 3000
 *
 * const { values, explicit } = resolveArgs({
 *   port: {
 *     type: 'number',
 *     default: 8080
 *   },
 *   host: {
 *     type: 'string',
 *     default: 'localhost'
 *   }
 * }, parsedTokens)
 *
 * values.port // 3000
 * values.host // 'localhost'
 *
 * explicit.port // true (explicitly provided)
 * explicit.host // false (not provided, fallback to default)
 * ```
 */
declare function resolveArgs<A extends Args>(args: A, tokens: ArgToken[], {
  shortGrouping,
  skipPositional,
  toKebab
}?: ResolveArgs): {
  values: ArgValues<A>;
  positionals: string[];
  rest: string[];
  error: AggregateError | undefined;
  explicit: ArgExplicitlyProvided<A>;
};
/**
 * An error type for {@link ArgResolveError}.
 */
type ArgResolveErrorType = 'type' | 'required' | 'conflict';
/**
 * An error that occurs when resolving arguments.
 * This error is thrown when the argument is not valid.
 */
declare class ArgResolveError extends Error {
  name: string;
  schema: ArgSchema;
  type: ArgResolveErrorType;
  /**
   * Create an `ArgResolveError` instance.
   *
   * @param message - the error message
   * @param name - the name of the argument
   * @param type - the type of the error, either 'type' or 'required'
   * @param schema - the argument schema that caused the error
   */
  constructor(message: string, name: string, type: ArgResolveErrorType, schema: ArgSchema);
}
//#endregion
export { ArgExplicitlyProvided, ArgResolveError, ArgResolveErrorType, ArgSchema, ArgValues, Args, ExtractOptionValue, FilterArgs, FilterPositionalArgs, ResolveArgValues, ResolveArgs, resolveArgs };