import { Ref } from 'vue';

declare type FieldPathValue<FieldValues, FiledName extends keyof FieldValues> = FieldValues[FiledName];
declare const $NestedValue: unique symbol;
declare type NestedValue<TValue extends object = object> = {
    [$NestedValue]: never;
} & TValue;
declare type DefaultValues<TFieldValues> = UnpackNestedValue<DeepPartial<TFieldValues>>;
declare type UnpackNestedValue<T> = T extends NestedValue<infer U> ? U : T extends Date | FileList | File | Blob ? T : T extends object ? {
    [K in keyof T]: UnpackNestedValue<T[K]>;
} : T;
declare type DeepPartial<T> = T extends Date | FileList | File | NestedValue ? T : {
    [K in keyof T]?: DeepPartial<T[K]>;
};

declare type FieldValues = Record<string, any>;
declare type FieldElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;

declare type Message = string;
declare type ValidationValue = boolean | number | string | RegExp;
declare type ValidationRule<TValidationValue extends ValidationValue = ValidationValue> = TValidationValue | ValidationValueMessage<TValidationValue>;
interface ValidationValueMessage<TValidationValue extends ValidationValue = ValidationValue> {
    value: TValidationValue;
    message: Message;
}
declare type ValidateResult = Message | Message[] | boolean | undefined;
declare type Validate<TFieldValue> = (value: TFieldValue) => ValidateResult | Promise<ValidateResult>;
declare type RegisterOptions<TFieldValues extends FieldValues = FieldValues, TFieldName extends string = string> = Partial<{
    required: Message | ValidationRule<boolean>;
    min: ValidationRule<number | string>;
    max: ValidationRule<number | string>;
    maxLength: ValidationRule<number>;
    minLength: ValidationRule<number>;
    pattern: ValidationRule<RegExp>;
    validate: Validate<FieldPathValue<TFieldValues, TFieldName>> | Record<string, Validate<FieldPathValue<TFieldValues, TFieldName>>>;
    valueAsNumber: boolean;
    valueAsDate: boolean;
    value: FieldPathValue<TFieldValues, TFieldName>;
    setValueAs: (value: any) => any;
    shouldUnregister?: boolean;
    onChange?: (event: any) => void;
    onBlur?: (event: any) => void;
    disabled: boolean;
}>;

declare type FieldError = Partial<{
    type: keyof RegisterOptions | string;
    message?: string;
    ref?: FieldElement;
}>;
declare type FieldErrors<TFieldValues> = Partial<Record<keyof TFieldValues, FieldError>>;

declare type Mode = 'onSubmit' | 'onBlur' | 'onChange' | 'onTouched' | 'all';
declare type CriteriaMode = 'firstError' | 'all';
interface UseFormProps<TFieldValues, TContext> {
    mode: Mode;
    reValidateMode: Exclude<Mode, 'onTouched' | 'all'>;
    defaultValues: DefaultValues<TFieldValues>;
    context: TContext;
    shouldFocusError: boolean | Ref<boolean>;
    shouldUnregister: boolean;
    shouldUseNativeValidation: boolean;
    criteriaMode: CriteriaMode;
    delayError: number;
}
declare type SubmitHandler<TFieldValues extends FieldValues> = (data: UnpackNestedValue<TFieldValues>, event?: Event) => any | Promise<any>;
declare type SubmitErrorHandler<TFieldValues extends FieldValues> = (errors: FieldErrors<TFieldValues>, event?: Event) => any | Promise<any>;
declare type UseFormHandleSubmit<TFieldValues extends FieldValues> = (onValid: SubmitHandler<TFieldValues>, onInvalid?: SubmitErrorHandler<TFieldValues>) => (e?: Event) => Promise<void>;

declare function useForm<TFieldValues extends FieldValues = FieldValues, TContext = any>(props?: Partial<UseFormProps<TFieldValues, TContext>>): {
    formState: any;
    register: (name: keyof TFieldValues, options: Partial<{
        required: string | ValidationRule<boolean>;
        min: ValidationRule<string | number>;
        max: ValidationRule<string | number>;
        maxLength: ValidationRule<number>;
        minLength: ValidationRule<number>;
        pattern: ValidationRule<RegExp>;
        validate: Validate<any> | Record<string, Validate<any>>;
        valueAsNumber: boolean;
        valueAsDate: boolean;
        value: any;
        setValueAs: (value: any) => any;
        shouldUnregister?: boolean | undefined;
        onChange?: ((event: any) => void) | undefined;
        onBlur?: ((event: any) => void) | undefined;
        disabled: boolean;
    }>) => {
        ref: any;
        modelValue: any;
        onBlur: () => void;
        "onUpdate:modelValue": (newValue: TFieldValues[keyof TFieldValues]) => void;
        onInput(evt: InputEvent): void;
    };
    unregister: (fieldsName: keyof TFieldValues | (keyof TFieldValues)[]) => void;
    useRegister: (name: keyof TFieldValues, options: Partial<{
        required: string | ValidationRule<boolean>;
        min: ValidationRule<string | number>;
        max: ValidationRule<string | number>;
        maxLength: ValidationRule<number>;
        minLength: ValidationRule<number>;
        pattern: ValidationRule<RegExp>;
        validate: Validate<any> | Record<string, Validate<any>>;
        valueAsNumber: boolean;
        valueAsDate: boolean;
        value: any;
        setValueAs: (value: any) => any;
        shouldUnregister?: boolean | undefined;
        onChange?: ((event: any) => void) | undefined;
        onBlur?: ((event: any) => void) | undefined;
        disabled: boolean;
    }>) => () => {
        ref: any;
        modelValue: any;
        onBlur: () => void;
        "onUpdate:modelValue": (newValue: TFieldValues[keyof TFieldValues]) => void;
        onInput(evt: InputEvent): void;
    };
    handleSubmit: UseFormHandleSubmit<TFieldValues>;
    createSubmitHandler: (fn: SubmitHandler<TFieldValues>) => SubmitHandler<TFieldValues>;
    createErrorHandler: (fn: SubmitErrorHandler<TFieldValues>) => SubmitErrorHandler<TFieldValues>;
};

export { useForm };
