import { DeepReadonly } from 'vue';
import { MaybeRefOrGetter } from 'vue';

declare interface Config {
    message?: ValidationMessage;
}

declare interface Config_10 {
    message?: ValidationMessage;
}

declare interface Config_2 {
    max: MaybeRefOrGetter<number>;
    message?: ValidationMessage;
    trim?: boolean;
}

declare interface Config_3 {
    max: MaybeRefOrGetter<number>;
    message?: ValidationMessage;
}

declare interface Config_4 {
    min: MaybeRefOrGetter<number>;
    message?: ValidationMessage;
    trim?: boolean;
}

declare interface Config_5 {
    min: MaybeRefOrGetter<number>;
    message?: ValidationMessage;
}

declare interface Config_6 {
    regex: RegExp;
    /** A custom message is required in order to inform the user of the required pattern. */
    message: ValidationMessage;
}

declare interface Config_7 {
    message?: ValidationMessage;
}

declare interface Config_8 {
    message?: ValidationMessage;
}

declare interface Config_9 {
    message?: ValidationMessage;
}

export declare function email(config?: Config): ValidationRule;

/**
 * A utility function that can be utilized within validator functions to determine if a value is defined.
 * @returns returns `false` if the value is `undefined`, `null`, `[]`, `''`, or an invalid Date.
 */
export declare function isDefined(value: unknown): boolean;

/**
 * Minimal shape for a JSON:API error object when setting validation errors from an HTTP response.
 * @see https://jsonapi.org/format/#error-objects
 */
export declare interface JsonApiValidationError {
    detail?: string;
    source?: {
        pointer?: string;
    };
    title?: string;
}

export declare function maxLength(config: Config_2): ValidationRule;

export declare function maxValue(config: Config_3): ValidationRule;

export declare function minLength(config: Config_4): ValidationRule;

export declare function minValue(config: Config_5): ValidationRule;

export declare function pattern(config: Config_6): ValidationRule;

export declare function positiveNumber(config?: Config_7): ValidationRule;

export declare function price(config?: Config_8): ValidationRule;

export declare function required(config?: Config_9): ValidationRule;

/**
 * Set how long `useValidation` waits before copying `values` changes into each field's
 * local value. Pass `0` for an immediate sync, so reading `hasErrors` right after
 * mutating `values` sees the updated state. Pass `null` to restore the default
 * `DEBOUNCE.FAST`.
 *
 * Mainly used in test setup:
 *
 * ```ts
 * import { setUseValidationDebounceMs } from '@leaflink/stash-vue/useValidation';
 * setUseValidationDebounceMs(0);
 * ```
 *
 * The override is module-level — call it once per test worker. Existing instances
 * aren't affected; only fields registered after the call pick up the new value.
 */
export declare function setUseValidationDebounceMs(ms: number | null): void;

declare function useValidation<Values extends object>({ rules, values, }: UseValidationArgs<Values>): ValidationGroup<Values>;
export default useValidation;

/**
 * The inputs for useValidation
 */
export declare interface UseValidationArgs<Values extends object> {
    rules: MaybeRefOrGetter<ValidationRules<Values> | ValidationRulesDeep>;
    values: MaybeRefOrGetter<{
        [Property in keyof Values]: Values[Property];
    }>;
}

/**
 * Meta data for a validation error
 */
export declare interface ValidationError {
    ruleName: string;
    message: string;
}

/**
 * Reactive validation properties for a single field
 */
export declare interface ValidationField<Value = unknown> {
    name: string;
    /**
     * The field's current value, which comes from the `values` argument passed to `useValidation()`.
     */
    currentValue: DeepReadonly<Value>;
    /**
     * The field's initial value, which comes from the `values` argument passed to `useValidation()`.
     * This value can be set to any value with `setInitialValue(value)`.
     */
    initialValue: DeepReadonly<Value>;
    /**
     * Indicates if the field's value has been changed at least one time;
     * this value can be reset to `false` with `setTouched(false)`.
     */
    isTouched: boolean;
    /**
     * Indicates if the field's current value is different from its initial value;
     */
    isDirty: boolean;
    /**
     * A list of validation errors. A rule only results in an error if the field's `isTouched` property is `true` and the rule's validator returns `false`.
     */
    errors: ValidationError[];
    /**
     * If the field is touched and has errors, this will contain the error message from the first error in `errors`;
     * otherwise, it will be an empty string.
     */
    errorMessage: string;
    /**
     * Sets the isTouched property to `true` by default, or `false` if given as an argument.
     */
    setTouched: (isTouched?: boolean) => void;
    /**
     * Sets the initial value for the field, which is used to determine the field's `isDirty` property.
     * This is useful for resetting the form after doing a PUT/PATCH where the `initialValue` needs to be the result of the PUT/PATCH.
     */
    setInitialValue: (value: Value) => void;
}

export declare type ValidationFields = Record<string, ValidationField>;

/**
 * The return value from `useValidation()`
 */
export declare interface ValidationGroup<Values extends object> {
    /**
     * Runs all validator functions by setting all fields' `isTouched` property to `true`. Afterwards, if the "name" attribute on the field matches the fieldName in the rules, the page will scroll to the first error unless `preventScroll` is truthy.
     * Can be used when a form is submitted to ensure all validation rules have been tested.
     * @returns a boolean indicating if all fields are valid
     */
    validate: (args?: {
        preventScroll?: boolean;
    }) => Promise<boolean>;
    /**
     * Gets the errorMessage from a ValidationField
     */
    getError: (fieldName: string) => string;
    /**
     * Sets the `isTouched` value to `true` for the given field
     */
    touch: (fieldName: string) => void;
    /**
     * Sets the `isTouched` value for each field to `false`.
     * This is useful for hiding error messages after resetting the form values to their empty/initial state.
     */
    setAllUntouched: () => Promise<void>;
    /**
     * Calls `setInitialValue()` on each field with the corresponding value from the `initialValues` argument.
     */
    setInitialValues: (initialValues: Values) => void;
    fields: ValidationFields;
    /**
     * A list of fields whose current value is different from their initial value
     */
    dirtyFields: ValidationField[];
    /**
     * The validation group is invalid if it has 1 or more errors
     */
    hasErrors: boolean;
    /**
     * Indicates if one or more fields have had their value changed at least one time
     */
    someTouched: boolean;
    /**
     * Sets field error messages from a JSON:API error response.
     * Parses each error's `source.pointer` (e.g. `/data/attributes/email`) to a field name and uses `detail` as the message.
     * Only applies errors for field names that exist in the validation rules; unknown fields are ignored.
     */
    setApiErrors: (errors: JsonApiValidationError[]) => void;
    /**
     * Clears API-set error messages. If `fieldName` is provided, clears only that field; otherwise clears all.
     */
    clearApiErrors: (fieldName?: string) => void;
    /**
     * Cancel any pending debounce and copy `values` into each field's local value
     * immediately. Use this when you need to read `hasErrors` or a field's `errors`
     * right after changing `values` — otherwise the read can race the debounce and
     * return stale data. `touch()` and `validate()` already flush internally, so most
     * consumers don't need this.
     *
     * Pass a `fieldName` to flush a single field; omit to flush all.
     */
    flush: (fieldName?: string) => void;
}

/**
 * An error message or a function that returns an error message;
 */
export declare type ValidationMessage<Value = unknown> = string | ((value: Value) => string);

/**
 * Contains a Validator function and an error message
 */
export declare interface ValidationRule<Value = unknown> {
    /**
     * The name of the rule
     */
    name: string;
    /**
     * Returns `true` if the field is valid, otherwise `false`
     */
    validator: Validator<Value>;
    /**
     * The error message for when the validator returns `false`
     */
    message: ValidationMessage<Value>;
}

/**
 * The ruleset for the ValidationGroup. It contains the validation rules for each form field.
 * Each field name must match a field name in the `values`.
 */
export declare type ValidationRules<Values extends object> = {
    [Property in keyof Values]: ValidationRule<Values[Property]>[];
};

/**
 * Nested rules tree: each leaf key maps to `ValidationRule[]`. Use for nested objects or arrays of
 * per-row rule objects (e.g. `terpenes: [{ name: [...], amount: [...] }]`). Inline rule objects
 * should use `validator(value: unknown)` (then narrow) so they match `ValidationRule<unknown>`;
 * you do not need to import this type when `useValidation` can infer `values`.
 */
export declare interface ValidationRulesDeep {
    [key: string]: ValidationRule<unknown>[] | ValidationRulesDeep | ValidationRulesDeep[];
}

/**
 * A function that returns `true` if the received value is valid and `false` if invalid.
 */
export declare type Validator<Value = unknown> = (value: Value) => boolean;

export declare function wholeNumber(config?: Config_10): ValidationRule;

export { }
