import type { cliui } from '@poppinss/cliui';
import type { Arguments, Options } from 'yargs-parser';
import type { HookHandler } from '@poppinss/hooks/types';
import type { Kernel } from './kernel.js';
/**
 * Parsed output of yargs
 */
export type YargsOutput = Arguments;
/**
 * Parsed output from the parser
 */
export type ParsedOutput = YargsOutput & {
    nodeArgs: string[];
    /**
     * Parsed arguments
     */
    args: (any | any[])[];
    /**
     * Left over arguments after parsing flags
     * and args
     */
    _: Array<string | number>;
    /**
     * An array of unknown flags that were parsed
     */
    unknownFlags: string[];
    /**
     * List of parsed flags
     */
    flags: {
        [argName: string]: any;
    };
};
/**
 * The UI primitives used by commands
 */
export type UIPrimitives = ReturnType<typeof cliui>;
/**
 * All loaders must adhere to the LoadersContract
 */
export interface LoadersContract<Command extends AbstractBaseCommand> {
    /**
     * The method should return an array of commands metadata
     */
    getMetaData(): Promise<CommandMetaData[]>;
    /**
     * The method should return the command instance by command
     * name
     */
    getCommand(command: CommandMetaData): Promise<Command | null>;
}
/**
 * Command executor is used to create a new instance of the command
 * and run it.
 */
export interface ExecutorContract<Command extends AbstractBaseCommand> {
    /**
     * Create a new instance of the command
     */
    create(command: Command, parsedOutput: ParsedOutput, kernel: Kernel<Command>): Promise<InstanceType<Command>> | InstanceType<Command>;
    /**
     * Run the command
     */
    run<Instance extends InstanceType<Command>>(command: Instance, kernel: Kernel<Command>): Promise<Instance>;
}
/**
 * Parser options accepted by the yargs to process
 * flags
 */
export type FlagsParserOptions = {
    all: string[];
    array?: string[];
    boolean?: Options['boolean'];
    string?: Options['string'];
    number?: Options['boolean'];
    default?: Options['default'];
    coerce?: Options['coerce'];
    alias?: Options['alias'];
    count?: Options['count'];
};
/**
 * The options accepted by the arguments parser
 */
export type ArgumentsParserOptions = {
    type: 'string' | 'spread';
    default?: any;
    parse?: (value: any) => any;
};
/**
 * Options for defining an argument
 */
export type BaseArgument<T> = {
    name: string;
    argumentName: string;
    required?: boolean;
    description?: string;
    default?: T;
};
/**
 * Type for a string argument
 */
export type StringArgument<T> = BaseArgument<T> & {
    type: 'string';
    /**
     * Whether or not to allow empty values. When set to false,
     * the validation will fail if the argument is provided
     * an empty string
     *
     * Defaults to false
     */
    allowEmptyValue?: boolean;
    parse?: (input: T) => T;
};
/**
 * Type for a spread argument
 */
export type SpreadArgument<T extends any> = BaseArgument<T> & {
    type: 'spread';
    /**
     * Whether or not to allow empty values. When set to false,
     * the validation will fail if the argument is provided
     * an empty string
     *
     * Defaults to false
     */
    allowEmptyValue?: boolean;
    parse?: (input: T extends any[] ? T : [T]) => T;
};
/**
 * A union of known arguments
 */
export type Argument = StringArgument<any> | SpreadArgument<any>;
/**
 * Base properties for a flag
 */
export type BaseFlag<T> = {
    name: string;
    flagName: string;
    required?: boolean;
    default?: T;
    description?: string;
    alias?: string | string[];
};
/**
 * String flag
 */
export type StringFlag<T> = BaseFlag<T> & {
    type: 'string';
    /**
     * Whether or not to allow empty values. When set to false,
     * the validation will fail if the flag is mentioned but
     * no value is provided
     *
     * Defaults to false
     */
    allowEmptyValue?: boolean;
    parse?: (input: T) => T;
};
/**
 * Boolean flag
 */
export type BooleanFlag<T> = BaseFlag<T> & {
    type: 'boolean';
    /**
     * Whether or not to display the negated variant in the
     * help output.
     *
     * Applicable for boolean flags only
     *
     * Defaults to false
     */
    showNegatedVariantInHelp?: boolean;
    parse?: (input: T) => T;
};
/**
 * Number flag
 */
export type NumberFlag<T> = BaseFlag<T> & {
    type: 'number';
    parse?: (input: T) => T;
};
/**
 * An array of string flag
 */
export type ArrayFlag<T extends any> = BaseFlag<T> & {
    type: 'array';
    /**
     * Whether or not to allow empty values. When set to false,
     * the validation will fail if the flag is mentioned but
     * no value is provided
     *
     * Defaults to false
     */
    allowEmptyValue?: boolean;
    parse?: (input: T) => T;
};
/**
 * A union of known flags
 */
export type Flag = StringFlag<any> | BooleanFlag<any> | NumberFlag<any> | ArrayFlag<any>;
/**
 * Command metdata required to display command help.
 */
export type CommandMetaData = {
    /**
     * Help text for the command
     */
    help?: string | string[];
    /**
     * The name of the command
     */
    commandName: string;
    /**
     * The command description to show on the help
     * screen
     */
    description: string;
    /**
     * Command namespace. The namespace is extracted
     * from the command name
     */
    namespace: string | null;
    /**
     * Command aliases. The same command can be run using
     * these aliases as well.
     */
    aliases: string[];
    /**
     * Flags accepted by the command
     */
    flags: Omit<Flag, 'parse'>[];
    /**
     * Args accepted by the command
     */
    args: Omit<Argument, 'parse'>[];
    /**
     * Command configuration options
     */
    options: CommandOptions;
} & Record<string, any>;
/**
 * Static set of command options
 */
export type CommandOptions = {
    /**
     * Whether or not to allow for unknown flags. If set to false,
     * the command will not run when unknown flags are provided
     * through the CLI
     *
     * Defaults to false
     */
    allowUnknownFlags?: boolean;
    /**
     * When flag set to true, the kernel will not trigger the termination
     * process unless the command explicitly calls the terminate method.
     *
     * Defaults to false
     */
    staysAlive?: boolean;
} & Record<string, any>;
/**
 * Finding hook handler and data
 */
export type FindingHookArgs = [[string], [string]];
export type FindingHookHandler = HookHandler<FindingHookArgs[0], FindingHookArgs[1]>;
/**
 * Found hook handler and data
 */
export type LoadingHookArgs = [[CommandMetaData], [CommandMetaData]];
export type LoadingHookHandler = HookHandler<LoadingHookArgs[0], LoadingHookArgs[1]>;
/**
 * Found hook handler and data
 */
export type LoadedHookArgs<Command extends AbstractBaseCommand> = [[Command], [Command]];
export type LoadedHookHandler<Command extends AbstractBaseCommand> = HookHandler<LoadedHookArgs<Command>[0], LoadedHookArgs<Command>[1]>;
/**
 * Executing hook handler and data
 */
export type ExecutingHookArgs<Command> = [[Command, boolean], [Command, boolean]];
export type ExecutingHookHandler<Command> = HookHandler<ExecutingHookArgs<Command>[0], ExecutingHookArgs<Command>[1]>;
/**
 * Executed hook handler and data
 */
export type ExecutedHookArgs<Command> = ExecutingHookArgs<Command>;
export type ExecutedHookHandler<Command> = ExecutingHookHandler<Command>;
/**
 * A listener that listeners for flags when they are mentioned.
 */
export type FlagListener<Command extends AbstractBaseCommand> = (command: Command, kernel: Kernel<Command>, parsedOutput: ParsedOutput) => any | Promise<any>;
/**
 * Commands and options list table
 */
export type ListTable = {
    columns: {
        option: string;
        description: string;
    }[];
    heading: string;
};
/**
 * A union of data types allowed for the info key-value pair
 */
export type AllowedInfoValues = number | boolean | string | string[] | number[] | boolean[];
/**
 * Abstract command defines the mandatory properties on a
 * command class needed by the internals of ace.
 */
export type AbstractBaseCommand = {
    commandName: string;
    options: CommandOptions;
    serialize(): CommandMetaData;
    validate(parsedOutput: ParsedOutput): void;
    getParserOptions(options?: FlagsParserOptions): {
        flagsParserOptions: Required<FlagsParserOptions>;
        argumentsParserOptions: ArgumentsParserOptions[];
    };
    new (...args: any[]): {
        hydrate(): void;
        exitCode?: number;
    };
};
