import * as _angular_core from '@angular/core';
import { Provider, InjectionToken, Signal, Injector, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { AbstractControl } from '@angular/forms';

interface CommandOptions {
    /**
     * Css Class which gets added/removed on the Command element's host while Command `isExecuting$`.
     */
    executingCssClass: string;
    /** Determines whether the disabled will be handled by the directive or not.
     * Disable handled by directive's doesn't always play nice when used with other component/pipe/directive and they also handle disabled.
     * This disables the handling manually and need to pass explicitly `[disabled]="!saveCmd.canExecute"`.
     */
    handleDisabled: boolean;
}
declare const COMMAND_OPTIONS: InjectionToken<CommandOptions>;
declare function provideSsvCommandOptions(options: Partial<CommandOptions> | ((defaults: Readonly<CommandOptions>) => Partial<CommandOptions>)): Provider[];

/** Type that represents a sync or async value. */
type MaybeAsync<T> = T | Observable<T> | Promise<T>;
type SignalLike<T> = (() => T);
/** Converts Observable<T> to Promise<T>, leaves other types unchanged */
type ConvertObservableToPromise<T> = T extends Observable<infer U> ? Promise<U> : T;
/** Return type of Execute function, converting `Observable` to `Promise` if needed */
type ExecuteReturnType<TExecute extends ExecuteFn> = ConvertObservableToPromise<ReturnType<TExecute>>;
type ExecuteFn<TArgs extends any[] = any[], TReturn = unknown> = (...args: TArgs) => MaybeAsync<TReturn>;
type CanExecute = SignalLike<boolean> | Signal<boolean> | Observable<boolean> | boolean;
/**
 * Type for command parameters that allows:
 * - Single parameter passed directly (not in array)
 * - Multiple parameters as tuple array
 * - Single array parameter wrapped in array to prevent spreading
 */
type CommandParams<TExec extends ExecuteFn> = Parameters<TExec> extends [infer Single] ? Single | [Single] : Parameters<TExec> extends [] ? never : Parameters<TExec>;
/** `command` input type convenience.
 * @example
 * For a command with a single parameter:
 * ```ts
 * readonly myCmd = input.required<CommandInput<MyType>>();
 * ```
 * For a command with multiple parameters:
 * ```ts
 * readonly myCmd = input.required<CommandInput<[param1: string, param2: number]>>();
 * ```
 */
type CommandInput<TArgs = unknown, R = unknown> = TArgs extends readonly [unknown, ...unknown[]] ? Command<(...args: TArgs) => R> : TArgs extends readonly [infer Single] ? Command<(arg: Single) => R> : Command<(arg: TArgs) => R>;
interface ICommand<TExecute extends ExecuteFn = ExecuteFn> {
    /** Determines whether the command is currently executing, as a snapshot value.
     * @deprecated Use {@link $isExecuting} signal instead.
    */
    readonly isExecuting: boolean;
    /** Determines whether the command is currently executing, as a signal. */
    readonly $isExecuting: Signal<boolean>;
    /** Determines whether the command can execute or not, as a snapshot value.
     * @deprecated Use {@link $canExecute} signal instead.
    */
    readonly canExecute: boolean;
    /** Determines whether the command can execute or not, as a signal. */
    readonly $canExecute: Signal<boolean>;
    /** Execute function to invoke. Returns Promise if the execute function returns Observable, otherwise returns the original type. */
    execute(...args: Parameters<TExecute>): ExecuteReturnType<TExecute>;
}
interface CommandCreator<TExecute extends ExecuteFn = ExecuteFn> {
    /** Execute function to invoke. */
    execute: TExecute;
    /** Determines whether the command can execute or not. Can be a signal, observable, or function. */
    canExecute?: CanExecute | ((...args: Parameters<TExecute>) => CanExecute);
    /** Parameters to pass to the execute function. */
    params?: CommandParams<TExecute>;
    /** Host context for binding the execute function. */
    host: unknown;
}

interface CommandCreateOptions {
    injector?: Injector;
}
/** Creates an async {@link Command}. Must be used within an injection context.
 * @deprecated Use {@link command} instead, as it handles both sync and async execute functions.
 */
declare const commandAsync: typeof command;
/** Creates a {@link Command}. Must be used within an injection context (or the injector must be provided in the options). */
declare function command<TExecute extends ExecuteFn>(execute: TExecute, canExecute?: CanExecute, opts?: CommandCreateOptions): Command<TExecute>;
/**
 * Command object used to encapsulate information which is needed to perform an action.
 */
declare class Command<TExecute extends ExecuteFn = ExecuteFn> implements ICommand<TExecute> {
    #private;
    private readonly _execute;
    get isExecuting(): boolean;
    get canExecute(): boolean;
    readonly $isExecuting: _angular_core.WritableSignal<boolean>;
    readonly $canExecute: Signal<boolean>;
    /**
     * Creates an instance of Command.
     *
     * @param execute Execute function to invoke.
     * @param canExecute Observable which determines whether it can execute or not.
     * @deprecated Use {@link command} or {@link commandAsync} instead for creating instances.
     */
    constructor(_execute: TExecute, canExecute?: CanExecute, injector?: Injector);
    /** Execute function to invoke. Returns Promise if the execute function returns Observable, otherwise returns the original type. */
    execute(...args: Parameters<TExecute>): ExecuteReturnType<TExecute>;
}

/** Helper type to extract ExecuteFn from ICommand/Command or use ExecuteFn directly */
type ExtractExecuteFn<T> = T extends Command<infer TExec> ? TExec : T extends ICommand<infer TExec> ? TExec : T extends ExecuteFn ? T : never;
/**
 * Controls the state of a component in sync with `Command`.
 *
 * @example
 * ### Most common usage
 * ```html
 * <button [ssvCommand]="saveCmd">Save</button>
 * ```
 *
 *
 * ### Usage with options
 * ```html
 * <button [ssvCommand]="saveCmd" [ssvCommandOptions]="{executingCssClass: 'in-progress'}">Save</button>
 * ```
 *
 *
 * ### Usage with params
 * This is useful for collections (loops) or using multiple actions with different args.
 * *NOTE: This will share the `isExecuting` when used with multiple controls.*
 *
 * #### With single param (direct)
 *
 * ```html
 * <button [ssvCommand]="saveCmd" [ssvCommandParams]="hero">Save</button>
 * ```
 *
 * #### With single param (array)
 *
 * ```html
 * <button [ssvCommand]="saveCmd" [ssvCommandParams]="[hero]">Save</button>
 * ```
 *
 * *NOTE: if you have only 1 argument as an array, it should be enclosed within an array e.g. `[['apple', 'banana']]`,
 * else it will spread and you will get `arg1: "apple", arg2: "banana"`*
 *
 * #### With multi params
 * ```html
 * <button [ssvCommand]="saveCmd" [ssvCommandParams]="[{id: 1}, 'hello', hero]">Save</button>
 * ```
 *
 * ### Usage with Command Creator
 * This is useful for collections (loops) or using multiple actions with different args, whilst not sharing `isExecuting`.
 *
 *
 * ```html
 * <button [ssvCommand]="{host: this, execute: removeHero$, canExecute: isValid$, params: [hero, 1337, 'xx']}">Save</button>
 * ```
 *
 */
declare class SsvCommand<T extends ICommand | ExecuteFn = ExecuteFn> implements OnInit {
    #private;
    readonly commandOrCreator: _angular_core.InputSignal<T extends ICommand<ExecuteFn<any[], unknown>> ? T : ICommand<ExtractExecuteFn<T>> | CommandCreator<ExtractExecuteFn<T>>>;
    readonly ssvCommandOptions: _angular_core.InputSignal<Partial<CommandOptions>>;
    readonly commandOptions: _angular_core.Signal<CommandOptions>;
    readonly ssvCommandParams: _angular_core.InputSignal<(CommandParams<ExtractExecuteFn<T>> extends infer T_1 ? { [KeyType in keyof T_1]: T_1[KeyType]; } : never) | undefined>;
    readonly commandParams: _angular_core.Signal<Parameters<ExtractExecuteFn<T>> | undefined>;
    readonly _hostClasses: _angular_core.Signal<string[]>;
    readonly command: _angular_core.Signal<ICommand<ExtractExecuteFn<T>>>;
    constructor();
    ngOnInit(): void;
    _handleClick(): void;
    private trySetDisabled;
    static ɵfac: _angular_core.ɵɵFactoryDeclaration<SsvCommand<any>, never>;
    static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SsvCommand<any>, "[ssvCommand]", ["ssvCommand"], { "commandOrCreator": { "alias": "ssvCommand"; "required": true; "isSignal": true; }; "ssvCommandOptions": { "alias": "ssvCommandOptions"; "required": false; "isSignal": true; }; "ssvCommandParams": { "alias": "ssvCommandParams"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
}

/**
 * Command creator ref, directive which allows creating Command in the template
 * and associate it to a command (in order to share executions).
 * @example
 * ### Most common usage
 * ```html
 * <div #actionCmd="ssvCommandRef" [ssvCommandRef]="{host: this, execute: removeHero$, canExecute: isValid$}">
 *    <button [ssvCommand]="actionCmd.command()" [ssvCommandParams]="[hero]">
 *      Remove
 *    </button>
 *    <button [ssvCommand]="actionCmd.command()" [ssvCommandParams]="[hero]">
 *       Remove
 *    </button>
 * </div>
 * ```
 *
 */
declare class SsvCommandRef<TExecute extends ExecuteFn = ExecuteFn> implements OnInit {
    #private;
    readonly commandCreator: _angular_core.InputSignal<CommandCreator<TExecute>>;
    readonly command: _angular_core.Signal<ICommand<TExecute>>;
    ngOnInit(): void;
    static ɵfac: _angular_core.ɵɵFactoryDeclaration<SsvCommandRef<any>, never>;
    static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SsvCommandRef<any>, "[ssvCommandRef]", ["ssvCommandRef"], { "commandCreator": { "alias": "ssvCommandRef"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
}

/** @deprecated Use standalone instead. */
declare class SsvCommandModule {
    static ɵfac: _angular_core.ɵɵFactoryDeclaration<SsvCommandModule, never>;
    static ɵmod: _angular_core.ɵɵNgModuleDeclaration<SsvCommandModule, never, [typeof SsvCommand, typeof SsvCommandRef], [typeof SsvCommand, typeof SsvCommandRef]>;
    static ɵinj: _angular_core.ɵɵInjectorDeclaration<SsvCommandModule>;
}

/** Determines whether the arg object is of type `Command`. */
declare function isCommand<T extends ICommand>(arg: unknown | T): arg is T;
/** Determines whether the arg object is of type `CommandCreator`. */
declare function isCommandCreator<T extends CommandCreator>(arg: unknown | T): arg is T;
interface CanExecuteFormOptions {
    /** Determines whether to check for validity. (defaults: true) */
    validity?: boolean;
    /** Determines whether to check whether UI has been touched. (defaults: true) */
    dirty?: boolean;
}
/** Get can execute from form validity/pristine as an observable. */
declare function canExecuteFromNgForm(form: AbstractControl, options?: CanExecuteFormOptions): Observable<boolean>;
/** Can executed based on valid/dirty signal inputs. */
declare function canExecuteFromSignals(signals: {
    valid: Signal<boolean>;
    dirty: Signal<boolean>;
}, options?: CanExecuteFormOptions): Signal<boolean>;

declare const VERSION = "5.1.0";

export { COMMAND_OPTIONS, Command, SsvCommand, SsvCommandModule, SsvCommandRef, VERSION, canExecuteFromNgForm, canExecuteFromSignals, command, commandAsync, isCommand, isCommandCreator, provideSsvCommandOptions };
export type { CanExecute, CanExecuteFormOptions, CommandCreateOptions, CommandCreator, CommandInput, CommandOptions, ExecuteFn, ICommand };
