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 NonUndefined<T> = T extends undefined ? never : T;
declare type IsAny<T> = 0 extends 1 & T ? true : false;
declare type DeepMap<T, TValue> = IsAny<T> extends true ? any : T extends Date | FileList | File | NestedValue ? TValue : T extends object ? {
    [K in keyof T]: DeepMap<NonUndefined<T[K]>, TValue>;
} : TValue;

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;
    vModelBinding?: string;
    disabled?: boolean;
    shouldUnregister?: boolean;
    onChange?: (event: any) => void;
    onBlur?: (event: any) => void;
}>;

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

declare type FieldValues = Record<string, any>;
declare type FieldElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
interface Field {
    inputValue: Ref;
    el: FieldElement;
    rule: RegisterOptions;
    isDirty: boolean;
    isUnregistered: boolean;
}
declare type Fields<FieldValues extends object, FieldKeys extends keyof FieldValues> = Record<FieldKeys, Field>;

declare type ResolverResult<T> = FieldErrors<T>;
declare type Resolver<FieldValues extends object> = (values: Record<keyof FieldValues, any>) => Promise<ResolverResult<FieldValues>>;

declare type Mode = 'onSubmit' | 'onBlur' | 'onChange' | 'onTouched' | 'all';
declare type CriteriaMode = 'firstError' | 'all';
declare type FieldNamesMarkedBoolean<TFieldValues extends FieldValues> = DeepMap<DeepPartial<TFieldValues>, boolean>;
interface UseFormProps<TFieldValues extends object> {
    mode: Mode;
    reValidateMode: Exclude<Mode, 'onTouched' | 'all'>;
    defaultValues: DefaultValues<TFieldValues>;
    resolver: Resolver<TFieldValues>;
    shouldFocusError: boolean;
    shouldUnregister: boolean;
    criteriaMode: CriteriaMode;
    delayError: number;
}
declare type KeepStateOptions = Partial<{
    keepDirtyValues: boolean;
    keepErrors: boolean;
    keepDirty: boolean;
    keepValues: boolean;
    keepDefaultValues: boolean;
    keepIsSubmitted: boolean;
    keepIsValid: boolean;
    keepSubmitCount: boolean;
}>;
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 type UseFormClearErrors<FieldName> = (fieldName?: FieldName | FieldName[]) => void;
declare type GetValuesReturn<FieldValues, FieldVal = FieldValues[keyof FieldValues]> = {
    [K in keyof FieldValues]: FieldVal;
};
declare type UseFormGetValues<FieldValues, FieldKeys> = (fieldNames?: FieldKeys | FieldKeys[]) => GetValuesReturn<FieldValues>;
interface GetFieldStateReturn {
    isDirty: boolean;
    isValid: boolean;
    error?: FieldError;
}
declare type UseFormGetFieldState<FieldKeys> = (fieldName: FieldKeys) => GetFieldStateReturn;
declare type UseFormSetError<FieldName> = (name: FieldName, error: FieldError, config?: {
    shouldFocusError: boolean;
}) => void;
declare type UseFormSetValue<FieldValues, FieldName extends keyof FieldValues, Value = FieldValues[FieldName]> = (name: FieldName, value: Value, config?: {
    shouldValidate?: boolean;
    shouldDirty?: boolean;
}) => Promise<void>;
declare type UseFormTriggerValidate<FieldKeys> = (fieldNames?: FieldKeys | FieldKeys[]) => Promise<void>;
declare type UseFormReset<TFieldValues extends FieldValues> = (values?: DefaultValues<TFieldValues> | UnpackNestedValue<TFieldValues> | 'all', keepStateOptions?: KeepStateOptions) => void;
declare type UseFormUnregister<TFieldValues extends FieldValues> = (name?: keyof TFieldValues, options?: Omit<KeepStateOptions, 'keepIsSubmitted' | 'keepSubmitCount' | 'keepValues' | 'keepDefaultValues' | 'keepErrors' | 'keepIsValid' | 'keepDirtyValues'> & {
    keepValue?: boolean;
    keepError?: boolean;
}) => void;
interface UseFormRegister<T extends FieldValues> {
    (name: keyof T, options?: RegisterOptions): any;
    (name: string, options?: RegisterOptions): any;
}
declare type UseFormSetFocus<FieldValues> = (name: keyof FieldValues) => void;
declare type UseFormIsExistInErrors<FieldValues> = (name: keyof FieldValues) => boolean;
interface UseFormHandlers<TFieldValues, FieldName = keyof TFieldValues> {
    getValues: UseFormGetValues<TFieldValues, FieldName>;
    getFieldState: UseFormGetFieldState<FieldName>;
    setError: UseFormSetError<FieldName>;
    clearErrors: UseFormClearErrors<FieldName>;
    setValue: UseFormSetValue<TFieldValues, keyof TFieldValues>;
    triggerValidate: UseFormTriggerValidate<FieldName>;
    reset: UseFormReset<TFieldValues>;
    handleSubmit: UseFormHandleSubmit<TFieldValues>;
    unregister: UseFormUnregister<TFieldValues>;
    register: UseFormRegister<TFieldValues>;
    setFocus: UseFormSetFocus<TFieldValues>;
    isExistInErrors: UseFormIsExistInErrors<TFieldValues>;
}
declare type FieldArrayDefaultValues = Record<number, any>;
declare type UseFormControl<TFieldValues extends FieldValues> = {
    _formState: FormState<TFieldValues>;
    _fieldArrayDefaultValues: FieldArrayDefaultValues;
    _fields: Fields<TFieldValues, keyof TFieldValues>;
} & UseFormHandlers<TFieldValues>;
interface FormState<TFieldValues> {
    isDirty: boolean;
    dirtyFields: FieldNamesMarkedBoolean<TFieldValues>;
    isSubmitted: boolean;
    isSubmitSuccessful: boolean;
    submitCount: number;
    isSubmitting: boolean;
    isValidating: boolean;
    isValid: boolean;
    defaultValues: Partial<DefaultValues<TFieldValues>>;
    errors: FieldErrors<TFieldValues>;
}

declare function useForm<TFieldValues extends FieldValues = FieldValues>(props?: Partial<UseFormProps<TFieldValues>>): {
    control: UseFormControl<TFieldValues>;
    formState: FormState<TFieldValues>;
    getValues: UseFormGetValues<TFieldValues, keyof TFieldValues>;
    getFieldState: UseFormGetFieldState<keyof TFieldValues>;
    setError: UseFormSetError<keyof TFieldValues>;
    clearErrors: UseFormClearErrors<keyof TFieldValues>;
    setValue: UseFormSetValue<TFieldValues, keyof TFieldValues, TFieldValues[keyof TFieldValues]>;
    triggerValidate: UseFormTriggerValidate<keyof TFieldValues>;
    reset: UseFormReset<TFieldValues>;
    handleSubmit: UseFormHandleSubmit<TFieldValues>;
    unregister: UseFormUnregister<TFieldValues>;
    register: UseFormRegister<TFieldValues>;
    setFocus: UseFormSetFocus<TFieldValues>;
    isExistInErrors: UseFormIsExistInErrors<TFieldValues>;
};

interface UseFieldArrayField<TFieldValues extends FieldValues = FieldValues> {
    index: number;
    name: keyof TFieldValues;
}
interface UseFieldArrayProps<TFieldValues extends FieldValues> {
    control: UseFormControl<TFieldValues>;
    name: keyof TFieldValues;
}
declare type FieldPayload<TFieldValues extends FieldValues[] = FieldValues[], FieldNames extends string = TFieldValues extends (infer R)[] ? keyof R : ''> = {
    [K in FieldNames]?: TFieldValues extends (infer R)[] ? R[keyof R] : never;
};
declare type UseFieldArrayInsert<TFieldValues extends FieldValues[]> = (startIndex: number, field: FieldPayload<TFieldValues>) => void;
declare type UseFieldArrayAppend<TFieldValues extends FieldValues[]> = (field: FieldPayload<TFieldValues>) => void;
declare type UseFieldArrayPrepend<TFieldValues extends FieldValues[]> = (field: FieldPayload<TFieldValues>) => void;
declare type UseFieldArrayRemove = (id: number | number[]) => void;
declare type UseFieldArraySwap = (from: number, to: number) => void;

declare function useFieldArray<TFieldsValues extends FieldValues = FieldValues>(props: UseFieldArrayProps<TFieldsValues>): {
    append: UseFieldArrayAppend<TFieldsValues[keyof TFieldsValues] extends [infer R] ? R extends FieldValues ? R[] : FieldValues[] : FieldValues[]>;
    prepend: UseFieldArrayPrepend<TFieldsValues[keyof TFieldsValues] extends [infer R] ? R extends FieldValues ? R[] : FieldValues[] : FieldValues[]>;
    remove: UseFieldArrayRemove;
    insert: UseFieldArrayInsert<TFieldsValues[keyof TFieldsValues] extends [infer R] ? R extends FieldValues ? R[] : FieldValues[] : FieldValues[]>;
    swap: UseFieldArraySwap;
    fields: UseFieldArrayField<TFieldsValues>[];
};

declare function createSubmitHandler<T extends FieldValues = FieldValues>(fn: SubmitHandler<T>): SubmitHandler<T>;
declare function createErrorHandler<T extends FieldValues = FieldValues>(fn: SubmitErrorHandler<T>): SubmitErrorHandler<T>;

declare function set<T extends object, K extends keyof T>(obj: T, key: K, value: T[K] | any): boolean;
declare function get<T extends object, K extends keyof T>(obj: T, key: K): T[K] | undefined;
declare function unset<T extends object, K extends keyof T>(obj: T, key: K): boolean;
declare const hasProp: <T extends object, K extends keyof T>(obj: T, key: K) => boolean;

declare const isFunction: (val: unknown) => val is Function;
declare const isNumber: (val: unknown) => val is number;
declare const isString: (val: unknown) => val is string;
declare const isBoolean: (val: unknown) => val is Boolean;
declare const isObject: (val: unknown) => boolean;
declare const isArray: (val: unknown) => val is unknown[];
declare const isEmptyObject: (val: unknown) => boolean;
declare const isUndefined: (val: unknown) => val is undefined;
declare const isNull: (val: unknown) => val is null;
declare const isNullOrUndefined: (val: unknown) => boolean;
declare const isHTMLElement: (val: unknown) => val is HTMLElement;
declare const isEmpty: (val: unknown) => boolean;
declare const isRegex: (val: unknown) => val is RegExp;
declare const isObjectType: (val: unknown) => boolean;
declare const isPrimitive: (val: unknown) => boolean;
declare const isDateObject: (val: unknown) => val is Date;

export { createErrorHandler, createSubmitHandler, get, hasProp, isArray, isBoolean, isDateObject, isEmpty, isEmptyObject, isFunction, isHTMLElement, isNull, isNullOrUndefined, isNumber, isObject, isObjectType, isPrimitive, isRegex, isString, isUndefined, set, unset, useFieldArray, useForm };
