import { MethodName, MethodNameWithVersionedParams, MethodVersionedParams } from '@telegram-apps/bridge';
import { Computed } from '@telegram-apps/signals';
import { If, IsNever } from '@telegram-apps/toolkit';
import { AnyFn } from '../../types.js';
export type CustomSupportValidatorFn = () => string | undefined;
export type IsSupportedType = MethodName | CustomSupportValidatorFn | (MethodName | CustomSupportValidatorFn)[] | {
    any: (MethodName | CustomSupportValidatorFn)[];
};
/**
 * A map where the key is a method name with versioned parameters, and the value is a tuple
 * containing the method and parameter names. The third tuple value is a function accepting
 * the wrapped function arguments and returning true if support check must be applied.
 */
export type Supports<Fn extends AnyFn> = Record<string, {
    [M in MethodNameWithVersionedParams]: [
        method: M,
        param: MethodVersionedParams<M>,
        shouldCheck: (...args: Parameters<Fn>) => boolean
    ];
}[MethodNameWithVersionedParams]>;
export type IfAvailableFnResult<Data> = [called: true, data: Data] | [called: false];
export type SafeWrapped<Fn extends AnyFn, HasSupportCheck extends boolean, SupportsSchema extends Record<string, any>> = Fn & {
    /**
     * The signal returning `true` if the function is available in the current environment and
     * conditions.
     *
     * To be more accurate, the method checks the following:
     * 1. The current environment is Telegram Mini Apps.
     * 2. The SDK package is initialized.
     * 3. If passed, the `isSupported` signal returns true.
     * 4. If passed, the `isMounted` signal returns true.
     *
     * *You should use this function when possible because it provides must-have code security
     * mechanisms and makes a developer sure that he is using the package properly.*
     *
     * @returns True if the function is available in the current environment.
     * @example
     * if (showBackButton.isAvailable()) {
     *   showBackButton();
     * }
     */
    isAvailable: Computed<boolean>;
    /**
     * Calls the function only in case it is available.
     *
     * It uses the `isAvailable` internally to check if the function is supported.
     * @example
     * showBackButton.ifAvailable();
     */
    ifAvailable(...args: Parameters<Fn>): IfAvailableFnResult<ReturnType<Fn>>;
} & If<HasSupportCheck, {
    /**
     * The signal returning `true` if the function is supported by the Telegram client,
     * including some possible additional conditions.
     *
     * It is highly recommended to use this signal only in certain narrow cases when only the
     * function support check is required, but not its availability.
     *
     * This signal is not applying additional operations like checking if the current environment
     * is Mini Apps and the SDK is initialized.
     *
     * To check if the function is available for use, use the `isAvailable` signal.
     *
     * @returns True if this function is supported.
     * @see isAvailable
     * @example
     * if (setMiniAppBottomBarColor.isSupported()) {
     *   console.log('Mini App bottom bar is supported, but the function may be unavailable');
     * }
     */
    isSupported: Computed<boolean>;
}, {}> & If<IsNever<SupportsSchema>, {}, {
    /**
     * A map where the key is the function-specific option name and value is a signal indicating
     * if it is supported by the current environment.
     * @example
     * if (setHeaderColor.isAvailable()) {
     *   if (setHeaderColor.supports.rgb()) {
     *     setHeaderColor('#ffaabb');
     *   } else {
     *     setHeaderColor('bg_color');
     *   }
     * }
     */
    supports: Record<keyof SupportsSchema, Computed<boolean>>;
}>;
export interface WrapSafeOptions<Fn extends AnyFn> {
    /**
     * The component name owning the wrapped function.
     */
    component?: string;
    /**
     * Signal returning true if the owning component is mounted.
     */
    isMounted?: () => boolean;
    /**
     * Signal returning true if the owning component is mounting.
     */
    isMounting?: () => boolean;
    /**
     * Value determining if the function is supported by the current environment.
     */
    isSupported?: IsSupportedType;
    /**
     * A map where the key is a method name with versioned parameters, and the value is a tuple
     * containing the method and parameter names. The third tuple value is a function accepting
     * the wrapped function arguments and returning true if support check must be applied.
     */
    supports?: Supports<Fn>;
}
/**
 * Wraps the function enhancing it with the useful utilities described in the SafeWrapped type.
 * @see SafeWrapped
 * @param method - method name
 * @param fn - wrapped function
 */
export declare function wrapSafe<Fn extends AnyFn>(method: string, fn: Fn): SafeWrapped<Fn, false, never>;
/**
 * Wraps the function enhancing it with the useful utilities described in the SafeWrapped type.
 * @see SafeWrapped
 * @param method - method name
 * @param fn - wrapped function
 * @param options - additional options
 */
export declare function wrapSafe<Fn extends AnyFn, O extends WrapSafeOptions<Fn>>(method: string, fn: Fn, options: O): SafeWrapped<Fn, O extends {
    isSupported: any;
} ? true : false, O extends {
    supports: any;
} ? O['supports'] : never>;
