import * as _QSTATE from '@qundus/qstate';
import { deriveAddon, hooksInUseAddon } from '@qundus/qstate/addons';

declare const IGNORED_SETUP_KEYS: Pick<Field.Setup, "type" | "validate" | "value" | "onMount" | "onChange" | "onAttrs" | "labelReplace" | "props" | "select" | "checkbox" | "tel" | "date" | "attrs">;
declare namespace FORM {
    enum STATUS {
        INIT = 0,
        IDLE = 1,
        INCOMPLETE = 2,
        ERROR = 3,
        VALID = 4,
        SUBMIT = 5
    }
}
declare namespace FIELD {
    enum CYCLE {
        INIT = 0,
        IDLE = 1,
        SUBMIT = 2,
        LOAD = 3,
        SKELETON = 4
    }
    enum DOM {
        INIT = "DOM.INIT",
        IDLE = "DOM.IDLE",
        FOCUS = "DOM.FOCUS",
        BLUR = "DOM.BLUR",
        INPUT = "DOM.INPUT",
        CHANGE = "DOM.CHANGE",
        CLICK = "DOM.CLICK",
        CLICK_OPTION = "DOM.CLICK.OPTION",
        CLICK_DATE_EVENT = "DOM.CLICK.DATE.EVENT",
        CLICK_DATE_CELL = "DOM.CLICK.DATE.CELL",
        CLICK_DATE_OPTION = "DOM.CLICK.DATE.OPTION",
        FILE_PROGRESS = "DOM.FILE.PROGRESS",
        FILE_DONE = "DOM.FILE.DONE"
    }
    enum MUTATE {
        INIT = "MUTATE.INIT",
        IDLE = "MUTATE.IDLE",
        VALUE = "MUTATE.VALUE",
        CONDITION = "MUTATE.CONDITION",
        ELEMENT = "MUTATE.ELEMENT",
        CYCLE = "MUTATE.CYCLE",
        PROPS = "MUTATE.PROPS",
        EXTRAS = "MUTATE.EXTRAS",
        __EXTRAS = "MUTATE.__EXTRAS",
        __ATTRIBUTE = "MUTATE.__ATTRIBUTE",
        __RESET = "MUTATE.__RESET",
        __ABORT_VALIDATION = "MUTATE.__ABORT_VALIDATION"
    }
    enum ATTRIBUTE {
        INIT = 0,
        READY = 1
    }
}
declare namespace MISC {
    const PLACEHOLDERS: {
        readonly select: {
            value: string;
            disabled: boolean;
            selected: boolean;
        };
        readonly selectButton: {
            value: string;
        };
    };
    const COUNTRIES: {
        name: string;
        flag: string;
        code: string;
        dial_code: string;
    }[];
}
declare namespace CALENDAR {
    /**
     * calendar modes, by default this is calculated based on the format.
     * if a mode is not offered by the format it won't be displayed and the next
     * logical mode is going to take place
     */
    enum MODE {
        YEAR = 0,
        MONTH = 1,
        DAY = 2,
        HOUR = 3,
        MINUTE = 4,
        SECOND = 5
    }
    enum MODE_TYPE {
        DATE = "DATE",
        TIME = "TIME"
    }
    enum OPTIONS {
        TIME_PERIOD = 11
    }
    enum EVENTS {
        NAV_PREV = 11,
        NAV_NEXT = 12,
        MODE_YEARS = 21,
        MODE_MONTHS = 22,
        MODE_DAYS = 23
    }
}

type Configs = {
    preprocess?: boolean;
    validate?: boolean;
};
interface FieldAddonUpdate<S extends Field.Setup, O extends Form.Options, V = S["value"]> {
    value: {
        (value: V | undefined | null, configs?: Pick<Configs, "preprocess" | "validate">): void;
        (value: (prev: V) => V | undefined | null, configs?: Pick<Configs, "preprocess" | "validate">): void;
    };
    condition: (value: Partial<Field.Condition> | ((prev: Field.Condition) => Partial<Field.Condition>)) => void;
    element: (value: Partial<Field.Element<S>> | ((prev: Field.Element<S>) => Partial<Field.Element<S>>), configs?: {
        validate?: boolean;
    }) => void;
    props: <G extends S["props"]>(value: Partial<G> | ((prev: G) => Partial<G> | undefined) | undefined) => void;
    /**
     * update current cycle to send signal to field listeners of what cycle this field
     * is in.
     * @param cycle the requested cycle, updated immediatly.
     * @returns a function to end the requested cycle and go back to CHANGE cycle only if no
     * other requests have been made
     */
    cycle: <G extends FIELD.CYCLE>(cycle: G | undefined | null) => G extends FIELD.CYCLE.IDLE ? void : () => void;
    select: <E extends Extras.Select.In>(props: Partial<E> | ((prev: E) => Partial<E>)) => void;
    selectByValue: (values: any | any[]) => void;
    selectByIndex: (indecies: number | number[]) => void;
    checkbox: <E extends Extras.Checkbox.In>(props: Partial<E> | ((prev: E) => Partial<E>)) => void;
    tel: (props: {
        country?: (typeof MISC.COUNTRIES)[number] | string;
        value?: string;
    }, configs?: {
        preprocess?: boolean;
        validate?: boolean;
    }) => void;
    date: (props: Partial<Extras.Date.In>, configs?: {
        preprocess?: boolean;
        validate?: boolean;
    }) => void;
}

type FieldAddonRemove<_S extends Field.Setup, _O extends Form.Options> = {
    option: (option: any) => void;
    optionByIndex: (index: number) => void;
};

type FieldAddonReset<_S extends Field.Setup, _O extends Form.Options> = {
    /** reset field to setup.value, use configs.clear to force clearing = undefined */
    value: (configs?: {
        clear?: boolean;
    }) => void;
    tel: (configs?: {
        clear?: boolean;
        keepCountry?: boolean;
    }) => void;
    /** reset all data to field start setup */
    origin: () => void;
};

type FormAddonSubmit<F extends Form.Fields, O extends Form.Options<F>> = ReturnType<typeof formSubmitAddon<F, O>>;
declare function formSubmitAddon<F extends Form.Fields, O extends Form.Options<F>>(props: FunctionProps.FormAddon<F, O>): {
    /**
     * check if it's possible to submit or not, this checks if all required
     * non-hidden fields have been fulfilled.
     */
    possible: () => boolean;
    /**
     * you can start submission by calling this function and control it's end
     * with the returned function, as opposed to task which controls
     * everything internally.
     * @returns a function to end submission, must be called
     */
    start: () => (() => void) | null;
    /**
     * a submission cycle internally controlled and allows access to
     * result after it's fulfillment, as opposed to start function which
     * gives total freedom.
     * @param runner the method to run for submission, maybe an api call or something.
     * @returns
     */
    task: <W, E = Record<string, any>>(runner: () => W | Promise<W>) => Promise<[W, null] | [null, {
        message: string;
    } | E]>;
};

type FormAddonUpdate<F extends Form.Fields, O extends Form.Options<F>> = ReturnType<typeof formUpdateAddon<F, O>>;
declare function formUpdateAddon<F extends Form.Fields, O extends Form.Options<F>>(props: FunctionProps.FormAddon<F, O>): {
    values: <G extends Object>(values: G, paths?: Record<string, string | {
        value: string;
        key?: string;
    }>, configs?: {
        preprocess?: boolean;
    }) => void;
    conditions: <G extends Record<keyof F, Partial<Field.Condition>>>(conditions: G) => void;
    elements: <G extends Record<keyof F, Field.Element<any>>>(elements: G) => void;
    elementsForAll: (element: Partial<Field.Element<any>>) => void;
    props: <G extends O["props"]>(props: Partial<G>) => void;
};

type FormAddonValues<F extends Form.Fields, O extends Form.Options<F>> = ReturnType<typeof formValuesAddon<F, O>>;
declare function formValuesAddon<F extends Form.Fields, O extends Form.Options<F>>(props: FunctionProps.FormAddon<F, O>): {
    get<RV extends FieldsReturnedValues<F>, KC extends FieldsKeysCaseMap<F>>(rv?: RV, special?: KC): FieldsValues<F, "same", KC>;
    getLowercase<KC extends FieldsKeysCaseMap<F>>(special?: KC): FieldsValues<F, "lowercase", KC>;
    getUppercase<KC extends FieldsKeysCaseMap<F>>(special?: KC): FieldsValues<F, "uppercase", KC>;
    getSnakecase<KC extends FieldsKeysCaseMap<F>>(special?: KC): FieldsValues<F, "snake", KC>;
    getSnakecaseAggressive<KC extends FieldsKeysCaseMap<F>>(special?: KC): FieldsValues<F, "snake_aggressive", KC>;
    getKebabcase<KC extends FieldsKeysCaseMap<F>>(special?: KC): FieldsValues<F, "kebab", KC>;
    getKebabcaseAggressive<KC extends FieldsKeysCaseMap<F>>(special?: KC): FieldsValues<F, "kebab_aggressive", KC>;
};
type FieldsKeysCaseMap<T extends Form.Fields> = {
    [K in keyof T]?: FieldKeyCase;
};
type FieldsReturnedValues<T extends Form.Fields> = {
    [K in keyof T as T[K]["setup"]["type"] extends "select" | "select.radio" ? K : never]?: "index" | "value";
};
type CamelToSnakeCase<S extends string, Sep extends string = "_", UppercaseIsNewWord extends boolean = false, Start extends boolean = true, PreviousLetterIsCapital = false> = S extends `${infer T}${infer U}` ? `${T extends Capitalize<T> ? Start extends false ? UppercaseIsNewWord extends true ? Sep : PreviousLetterIsCapital extends false ? Sep : "" : "" : ""}${Lowercase<T>}${T extends Capitalize<T> ? CamelToSnakeCase<U, Sep, UppercaseIsNewWord, false, true> : CamelToSnakeCase<U, Sep, UppercaseIsNewWord, false, false>}` : S;
type FieldKeyCase = "same" | "snake" | "snake_aggressive" | "kebab" | "kebab_aggressive" | "lowercase" | "uppercase";
type IsValueKeyOfCase<T extends FieldKeyCase, V extends FieldKeyCase | undefined> = true extends Check.IsUnknown<V> | Check.IsUndefined<V> | Check.IsNull<V> ? false : V extends T ? true : false;
type ValueKeyCaseType<K, V extends FieldKeyCase | undefined> = IsValueKeyOfCase<"snake", V> extends true ? CamelToSnakeCase<string & K> : IsValueKeyOfCase<"snake_aggressive", V> extends true ? CamelToSnakeCase<string & K, "_", true> : IsValueKeyOfCase<"kebab_aggressive", V> extends true ? CamelToSnakeCase<string & K, "-", true> : IsValueKeyOfCase<"kebab", V> extends true ? CamelToSnakeCase<string & K, "-"> : IsValueKeyOfCase<"lowercase", V> extends true ? Lowercase<string & K> : IsValueKeyOfCase<"uppercase", V> extends true ? Uppercase<string & K> : K;
type GetValueKeyCase<V extends FieldKeyCase | undefined, Default extends FieldKeyCase> = true extends Check.IsUnknown<V> | Check.IsUndefined<V> | Check.IsNull<V> ? Default : FieldKeyCase extends V ? Default : V;
type FieldsValues<T extends Form.Fields, V extends FieldKeyCase, O extends FieldsKeysCaseMap<T>> = {
    [K in keyof T as ValueKeyCaseType<K, GetValueKeyCase<O[K], V>>]: T[K]["setup"]["value"];
};

type ButtonObject = {
    status: FORM.STATUS;
    disabled: boolean;
    canSubmit: boolean;
    submitting: boolean;
};
type ButtonStore<F extends Form.Fields, O extends Form.Options<F>> = _QSTATE.StoreDerived.Factory<ButtonObject, {
    hooks: O["storeHooks"];
}>;
type FormAddonButton<F extends Form.Fields, O extends Form.Options<F>> = {
    store: ButtonStore<F, O>;
};

type SelectedList = ReturnType<typeof createSelectedList>;
declare function createSelectedList(extras: Extras.Date.Out<any>): {
    list: Extras.Date.ParsedResult[];
    readonly validCount: number;
    requiresDate: boolean;
    requiresTime: boolean;
    append: (parsed: Extras.Date.ParsedResult) => void;
    hasYear: (year: number) => boolean;
    hasYearMonth: (year: number, month: number) => boolean;
    hasDate: (year: number, month: number, day: number) => boolean;
    populateSelectedTime(year: number, month: number, day: number): {
        list: Extras.Date.ParsedTime[];
        hasHour: (_hour: number) => boolean;
        hasHourMinute: (_hour: number, minute: number) => boolean;
        hasTime: (_hour: number, minute: number, second: number) => boolean;
    };
};

type DateAttributeCells = {
    YEAR?: Extras.Date.CellDate;
    MONTH?: Extras.Date.CellDate;
    DAY?: Extras.Date.CellDate;
    HOUR?: Extras.Date.CellTime;
    MINUTE?: Extras.Date.CellTime;
    SECOND?: Extras.Date.CellTime;
};

declare namespace Check {
    type IsUnknown<T> = unknown extends T ? true : false;
    type IsUndefined<T> = Exclude<T, undefined> extends never ? true : false;
    type IsNull<T> = Exclude<T, null> extends never ? true : false;
    type IsEmpty<T> = {} extends T ? true : false;
    type IsSetupOfType<S extends Field.Setup, T extends Field.Type> = S extends {
        type: T;
    } ? true : never;
}
declare namespace Field {
    type Type = "checkbox" | "color" | "date" | "email" | "file" | "image" | "month" | "number" | "password" | "range" | "reset" | "search" | "tel" | "text" | "time" | "url" | "week" | "select" | "select.radio";
    type Condition = {
        valid: boolean;
        error: false | "validation" | "incomplete" | "optional";
        updated: boolean;
        by: false | "user" | "manual";
    };
    type Errors = string[] | null | undefined;
    type Validate<T extends Type> = (props: {
        value: any;
        prev: any;
        readonly extras: Extras.Factory<Setup<T>>;
        readonly form: Form.StoreObject<Form.Fields, Form.Options> | undefined;
    }) => string | string[] | undefined | null | void;
    type VMCM = "normal" | "bypass" | "force-valid";
    type ValidateOn = "input" | "change";
    type OnMount<T extends Type, V> = (props: {
        setup: Setup;
        update: Addon.FieldUpdate<Setup, Form.Options>;
        SSR: boolean;
    }) => void | (() => void) | Promise<void | (() => void)>;
    type OnChange<T extends Type, V> = (props: {
        $next: StoreObject<Setup, Form.Options>;
        prev: StoreObject<Setup, Form.Options>;
        setup: Setup;
        form: Form.StoreObject<any, any> | undefined;
        update: Addon.FieldUpdate<Setup, Form.Options>;
        SSR: boolean;
    }) => void | Promise<void>;
    type OnAttrs<T extends Type> = (props: {
        key: string;
        state: StoreObject<any, Form.Options>;
    } /** this is the final attributes passed to the element */ & ({
        attrFor: "input";
        attrs: Attributes.Standard.Input;
    } | {
        attrFor: "trigger";
        attrs: Attributes.Select.Trigger;
    } | {
        attrFor: "option";
        attrs: Attributes.Select.Option;
    })) => void;
    type Event = {
        value?: any;
        checked?: any;
        files?: FileList;
    };
    type Setup<T extends Type = Type, V = any> = {
        type: T;
        /** initial value */
        value?: V;
        placeholder?: string;
        label?: string;
        /**
         * when labels are taken from key because they're null, this replaces
         * certain chars like '_' or '-' with ' '
         */
        labelReplace?: string | string[];
        /** validate value function or array of functions */
        validate?: Validate<T> | Validate<T>[] | null;
        /**
         * some developers like to validate on field.blur and others on field.change.
         * @option {change} run checks only on field.blur
         * @option {input} run checks on everychange occurs
         */
        validateOn?: ValidateOn;
        onMount?: OnMount<T, V>;
        /**
         * event used in case of complex data values
         * need to be extracted from field element and the basic
         * element.value event isn't accurate enough.
         * some processors run when events like onfocus and onblur fire,
         * this gives the chance to modify field state like required,
         * disabled..etc, according to specific needs or logic.
         */
        onChange?: OnChange<T, V> | OnChange<T, V>[];
        /**
         * html bare element attributes passed to dom.
         */
        onAttrs?: OnAttrs<T>;
        hidden?: boolean;
        required?: boolean;
        disabled?: boolean;
        /**
         * can be used for when a field is mandatory, like a checkbox.
         */
        mandatory?: boolean;
        /**
         * usually the cycle starts with INIT then IDLE moving to whatever developer logic
         * prefers to set through onMount function, this alters the MOUNT cycle allowing for any
         * cycle to replace it.
         * @default CYCLE.IDLE
         */
        initCycle?: FIELD.CYCLE;
        ssr?: boolean;
        /**
         * Value Manual Change Mechanism (VMCM), happens when values are updated from api
         * fetch data or just manual programmatic interferrence.
         * this affects whether the updated values go through the proper
         * channels of validation, proccessing and affects on form status or just
         * updates values without affecting anything else.
         * @option normal: value updates go through the proper channeels of validation, proccessing, error handling and condition report.
         * @option bypass: value updates are not validated so no proccessing or error handling, condition is changed though.
         * @option force-valid: value updates defaults fields value condition to valid.
         * @default "normal"
         */
        vmcm?: VMCM;
        /**
         * all values go through preprocessing phase, use this to prevent that
         * @default true
         */
        preprocessValue?: boolean;
        /**
         * checks for missing/required value and mark condition.error as
         * incomplete.
         * @default true
         */
        incompleteStatus?: boolean;
        /**
         * allowing the field value to be null
         */
        valueNullable?: boolean;
        /**
         * abort state changes when an exception is thrown from onChange
         * method or not
         * @default false
         */
        onChangeException?: boolean;
        /** coming soon, a way to defing nested field fields */
        props?: Record<string, any>;
        multiple?: boolean;
        tel?: T extends "tel" ? Extras.Tel.In : never;
        select?: T extends "select" | "select.radio" ? Extras.Select.In : never;
        checkbox?: T extends "checkbox" ? Extras.Checkbox.In : never;
        date?: T extends "date" ? Partial<Extras.Date.In> : never;
        attrs?: Attributes.Setup;
    };
    type ValueFromType<T extends Type, S extends Setup<T> = Setup<T>> = T extends "file" ? FileList : T extends "checkbox" ? S["checkbox"] extends Extras.Checkbox.In ? (undefined | unknown extends S["checkbox"]["yes"] ? true : S["checkbox"]["yes"]) | (undefined | unknown extends S["checkbox"]["no"] ? false : S["checkbox"]["no"]) : boolean : T extends "select" | "select.radio" ? (Extras.Factory<S, "select" | "select.radio">["options"][number] extends infer G ? {
        [K in keyof G as K extends `__${infer _internal}` ? never : K]: G[K];
    } : never) extends infer G ? S["multiple"] extends true ? G[] : G : never : T extends "tel" ? string : string;
    type ValueFromOptions<T extends Type, V, S extends Setup<T, V> = Setup<T, V>> = (true extends Check.IsUnknown<V> | Check.IsUndefined<V> | Check.IsNull<V> ? {
        value: ValueFromType<T, S>;
    } : T extends "file" | "select" | "select.radio" ? {
        value: ValueFromType<T, S>;
    } : {
        value: V;
    }) extends infer G ? {
        [K in keyof G]: S["required"] extends false ? S["valueNullable"] extends false ? G[K] : G[K] | undefined : S["hidden"] extends true ? S["valueNullable"] extends false ? G[K] : G[K] | undefined : G[K];
    } : never;
    type SetupIn = Type | Setup | null | undefined;
    type SetupInToSetup<S extends SetupIn> = S extends Setup<infer type, infer value> ? ValueFromOptions<type, value, S> & Omit<S, "value"> : S extends Type ? ValueFromOptions<S, undefined> & Omit<Field.Setup<S>, "value"> : ValueFromOptions<Type, string> & Omit<Setup<Type, string>, "value">;
    type Element<S extends Setup> = {
        focused: boolean;
        visited: boolean;
        entered: boolean;
        left: boolean;
    } & {
        [K in keyof Setup as K extends keyof typeof IGNORED_SETUP_KEYS ? never : K]: Setup[K];
    };
    type StoreObject<S extends Setup, O extends Form.Options> = {
        readonly __internal: {
            key: string;
            manual: boolean;
            preprocess?: boolean;
            validate?: boolean;
        };
        readonly event: {
            DOM: FIELD.DOM;
            MUTATE: FIELD.MUTATE;
            CYCLE: FIELD.CYCLE;
            ATTRIBUTE: FIELD.ATTRIBUTE;
            ev: undefined | Event;
        };
        value: S["value"] | undefined;
        condition: Condition;
        element: Element<S>;
        /** user defined data */
        props: undefined | unknown extends S["props"] ? any : S["props"];
        extras: Extras.Factory<S>;
        errors?: string[];
        attrs: Attributes.Factory<S, O>;
    };
    type StoreState<S extends Setup, O extends Form.Options> = _QSTATE.Nano.Atom<StoreObject<S, O>>;
    type Store<S extends Setup, O extends Form.Options> = _QSTATE.Store.Factory<StoreState<S, O>, {
        hooks: O["storeHooks"];
        addons: {
            hooksUsed: typeof hooksInUseAddon;
        };
    }>;
    type Factory<S extends Setup, O extends Form.Options> = {
        readonly key: string;
        readonly setup: S;
        readonly update: Addon.FieldUpdate<S, O>;
        readonly remove: Addon.FieldRemove<S, O>;
        readonly reset: Addon.FieldReset<S, O>;
        readonly store: Store<S, O>;
        readonly storeh: "hooks" extends keyof Store<S, O> ? Store<S, O>["hooks"] : undefined;
    };
    type Component<T extends Type> = Omit<Factory<Setup<T>, Form.Options>, "storeh" | "update"> & {
        readonly update: FieldAddonUpdate<Setup<T>, Form.Options, any>;
    };
}
declare namespace Extras {
    namespace Checkbox {
        type In<Y = any, N = any> = {
            yes?: Y;
            no?: N;
        };
        type Out<S extends Field.Setup> = {
            checked: boolean;
            yes?: Exclude<S["checkbox"], undefined>["yes"];
            no?: Exclude<S["checkbox"], undefined>["no"];
        };
    }
    namespace File {
        type Out<S extends Field.Setup> = {
            count: {
                upload: number;
                failed: number;
                done: number;
            };
            fallback?: {
                name: string;
                url: string;
            }[];
            files?: {
                file: File;
                name: string;
                loading: boolean;
                stage: "start" | "success" | "fail" | "abort";
                progress: {
                    loadedBytes: number;
                    totalBytes: number;
                    percentage: number;
                };
                buffer?: string | ArrayBuffer | null;
                url?: string;
                error?: DOMException | null;
            }[];
        };
    }
    namespace Select {
        type In = {
            options?: (string | number | Record<string, unknown> | {
                label: string;
                value: string;
            })[];
            valueKey?: string;
            labelKey?: string;
            /**
             * incase the valueKey is not found in the option object, the dafault
             * behvior is to find a key dynamically and store it in the option
             * @default false
             */
            throwOnKeyNotFound?: boolean;
            /**
             * allows for dynamic creation of selection options by deriving the options
             * from the selected option at runtime, useful for adding options to an existing
             * list or creating a whole selection options dynamically.
             */
            dynamic?: boolean;
            /**
             * what should happen if an option is selected and it's clicked/chosen again?.
             * by default, the option will get deselected, you can prevent that here by setting
             * this option to false which will disallow option deselection.
             * @default true
             */
            removeOnReselect?: boolean;
        };
        type Out<S extends Field.Setup> = {
            dynamic: boolean | undefined;
            valueKey: string;
            labelKey: string;
            selected: number;
            throwOnKeyNotFound: boolean;
            prev: number[];
            current: number[];
            removeOnReselect: boolean;
            options: ((S["select"] extends In ? S["select"]["options"] extends (infer option)[] ? option extends string | number ? {
                label: option;
                value: option;
            } : option : {
                label: string;
                value: string;
            } : {
                label: string;
                value: string;
            }) & {
                __selected: boolean;
                __key: string;
                __valueKey?: string;
                __labelKey?: string;
            })[];
        };
    }
    namespace Tel {
        type In = {
            /**
             * some phone numbers may include chars like '-', by default these chars
             * get sanitized, you can ignore some sanitization chars here to be included
             * in the final tel value.
             * @default undefined
             */
            preserveChars?: string;
            international?: {
                /**
                 * international numbers prefixes, use this if your field accepts
                 * weird international prefixes like (00) or (+00). this option replaces defaults.
                 * @default ["+", "00", "+(00)"]
                 */
                prefixes?: string | string[];
                /**
                 * unify international prefixes with only + and 00 while preserving user
                 * input international prefix such as +(00), this is useful for clear user
                 * experience and UI while maintaining user data in the background.
                 * @default false
                 */
                prefixNormalization?: boolean;
                /**
                 * this option allows removes international code from the value
                 * displaying only the phone number. useful for components that display
                 * international code seprately.
                 * @default 'normal'
                 */
                displayMode?: "normal" | "no-prefix" | "keep-prefix";
            };
        };
        type Out<S extends Field.Setup> = {
            preserveChars: string | undefined;
            international: {
                prefixes: string | string[] | null;
                prefixNormalization: boolean | undefined;
                displayMode: "normal" | "no-prefix" | "keep-prefix";
                prefix: string | null;
                country: null | {
                    name: string;
                    flag: string;
                    code: string;
                    dial_code: string;
                    dial_code_no_id: string;
                    index: number;
                };
            };
            value: {
                number?: string | null;
                numberNoCode?: string | null;
                numberNoZero?: string | null;
                numberNoCodeNoZero?: string | null;
                preserved?: string | null;
                preservedNoCode?: string | null;
                preservedNoZero?: string | null;
                preservedNoCodeNoZero?: string | null;
            };
        };
    }
    namespace Date {
        interface Cell {
            key: string;
            mode: CALENDAR.MODE;
            modeName: keyof typeof CALENDAR.MODE;
            value: string;
            valueNumber: number;
            isSelected: boolean;
            name: string;
            shortName: string;
        }
        export interface CellDate extends Cell {
            isToday?: boolean;
            isOtherMonth?: boolean;
        }
        export interface CellTime extends Cell {
            is24Hour?: boolean;
            suffix: string;
            shortSuffix: string;
        }
        export interface Header {
            value: string;
            name: string;
            shortName: string;
        }
        export interface Option {
            type: CALENDAR.OPTIONS;
            typeName: keyof typeof CALENDAR.OPTIONS;
            value: string;
            name: string;
            shortName: string;
            isSelected: boolean;
        }
        export interface ParsedDate {
            year: string | null;
            month: string | null;
            day: string | null;
            yearNumber: number | null;
            monthNumber: number | null;
            dayNumber: number | null;
            valid: boolean;
            formatted: string | null;
        }
        export interface ParsedTime {
            hour: string | null;
            minute: string | null;
            second: string | null;
            hourNumber: number | null;
            minuteNumber: number | null;
            secondNumber: number | null;
            period: "AM" | "PM" | null;
            valid: boolean;
            formatted: string | null;
            formatted24h: string | null;
        }
        export interface ParsedResult {
            date: ParsedDate;
            time: ParsedTime[];
            valid: boolean;
            others: string | null;
            error?: string;
        }
        export type In = {
            defaultMode: keyof typeof CALENDAR.MODE;
            /**
             * format of the date, use char n to denote minutes, everything else is universal standard.
             * @option {yyyy or yy} for years
             * @option {mm or m} for months, mm won't detect user typed single digits
             * @option {dd or d} for days, dd won't detect user typed single digits
             * @option {hh or h} for hours, hh won't detect user typed single digits
             * @option {nn or n} for minutes, nn won't detect user typed single digits
             * @option {ss or s} for seconds, ss won't detect user typed single digits
             * @example
             * format: "d-m-yyyy hh:nn";
             * // note the '/', the detection allows free familiar human language.
             * value: "meeting on 22-12/2025 at exactly 14:30"
             * @default "d-m-yyyy h:n:s"
             */
            format: string;
            /**
             * separators used for dates
             * @default ['-', '/', '.']
             */
            dateSeparators: string | string[];
            /**
             * separators used for time
             * @default [':']
             */
            timeSeparators: string | string[];
            /**
             * separator used to split multiple dates
             * @default |
             */
            multipleDateSeparator: string;
            /**
             * separator used to split multiple times for selected dates
             * @default ,
             */
            multipleTimeSeparator: string;
            multipleTime: boolean;
            /**
             * locale used in date objects parsing.
             * @default 'en-US'
             */
            locale: string;
            yearSpan: number;
            firstDayOfWeek: number;
            timeFormat: "12h" | "24h";
        };
        export type Out<S extends Field.Setup> = {
            format: string;
            dateSeparators: string[];
            timeSeparators: string[];
            multipleDateSeparator: string;
            multipleTimeSeparator: string;
            multipleTime: boolean;
            rangeSeparator: string;
            locale: string;
            yearSpan: number;
            firstDayOfWeek: number;
            timeFormat: "12h" | "24h";
            selected: SelectedList;
            mode: {
                active: CALENDAR.MODE;
                activeType: CALENDAR.MODE_TYPE;
                default: CALENDAR.MODE;
                defaultType: CALENDAR.MODE_TYPE;
                applyDate: CALENDAR.MODE | null;
                applyTime: CALENDAR.MODE | null;
                activeName: keyof typeof CALENDAR.MODE;
                activeTypeName: keyof typeof CALENDAR.MODE_TYPE;
                defaultName: keyof typeof CALENDAR.MODE;
                defaultTypeName: keyof typeof CALENDAR.MODE;
                applyDateName: keyof typeof CALENDAR.MODE | null;
                applyTimeName: keyof typeof CALENDAR.MODE | null;
                sequence: CALENDAR.MODE[];
            };
            DATE: {
                cells?: CellDate[];
            };
            TIME: {
                cells?: CellTime[];
                periods?: Extras.Date.Option[];
                activePeriod?: string;
                suffix: {
                    dir: "ltr" | "rtl";
                    short: {
                        hour: string;
                        minute: string;
                        second: string;
                    };
                    long: {
                        hour: string;
                        minute: string;
                        second: string;
                    };
                };
            };
            YEAR: {
                cells?: CellDate[];
                active: number;
                current: number;
                start: number;
                end: number;
            };
            MONTH: {
                cells?: CellDate[];
                active: number;
                current: number;
                name: string;
                shortName: string;
            };
            DAY: {
                headers: Header[];
                cells?: CellDate[];
                active: number;
                current: number;
                name: string;
                shortName: string;
            };
            HOUR: {
                cells?: CellTime[];
                active: number;
            };
            MINUTE: {
                cells?: CellTime[];
                active: number;
            };
            SECOND: {
                cells?: CellTime[];
                active: number;
            };
        };
        export {  };
    }
    /**
     * sometimes some field types require additional information beyond the
     * the standard field "value", this offers that through value processing
     * and places it under FieldState or State
     */
    type Factory<S extends Field.Setup<Field.Type>, T = S["type"]> = T extends "file" ? File.Out<S> : T extends "select" | "select.radio" ? Select.Out<S> : T extends "checkbox" ? Checkbox.Out<S> : T extends "tel" ? Tel.Out<S> : T extends "date" ? Date.Out<S> : never;
}
declare namespace Form {
    type FieldsIn = Record<string, Field.SetupIn> | undefined | null;
    type Fields<I extends FieldsIn = FieldsIn, O extends Options = Options> = I extends Record<string, Field.SetupIn> ? {
        [K in keyof I]: Field.SetupInToSetup<I[K]> extends Field.Setup ? Field.Factory<Field.SetupInToSetup<I[K]>, O> : never;
    } : Record<string, Field.Factory<Field.Setup, O>>;
    type Options<F extends Fields = any> = {
        vmcm?: Field.VMCM;
        /**
         * when labels are taken from key because they're null, this replaces
         * certain chars like '_' or '-' with ' '
         */
        labelReplace?: string | string[];
        /**
         * global options to optin or out of values preprocessing based on field type.
         * this option precedes individual ones
         */
        preprocessValues?: boolean;
        /**
         * usually all values are immediatly updated in the state,
         * by setting this to true, only valid values will be commited.
         * @default false
         */
        preventErroredValues?: boolean;
        /**
         * wheather the preferred method of checking values
         * is ran oninput or onchange, oninput checks for validation
         * for every change happens, onchange checks once there's a
         * state change like blur or focus.
         * field specific validateOn takes precedence here.
         * @default input
         */
        validateOn?: Field.ValidateOn;
        /** store and pass any data around */
        props?: Record<string, any>;
        /**
         * how's the props passed/merged with field's specific props.
         * @option 'none' each props is kept independantly
         * @option 'form-override' global form props trumps/overrides field's props
         * @option 'field-override' field specific props trumps/overrides form's props
         * @default 'none'
         */
        propsMergeStrategy?: "none" | "form-override" | "field-override";
        storeHooks?: _QSTATE.Option.Hooks.In<any>;
        onMount?: (props: {
            readonly SSR: boolean;
            readonly form: StoreObject<F, Options<F>>;
            readonly prev: StoreObject<F, Options<F>>;
            readonly getForm: () => StoreObject<F, Options<F>>;
            readonly update: Addon.FormUpdate<F, Options<F>>;
            readonly fields: F;
        }, listen: <Value, OriginStores extends _QSTATE.Nano.Abstract[]>(stores: [...OriginStores], cb: (...values: _QSTATE.Nano.Values<OriginStores>) => void | Promise<void | Value>) => void) => void | Promise<void>;
        onEffect?: (props: {
            readonly SSR: boolean;
            readonly form: StoreObject<F, Options<F>>;
            readonly prev: StoreObject<F, Options<F>>;
            readonly fields: F;
        }) => void;
        ssr?: boolean;
        /**
         * default behavior of form is to consider all fields required,
         * use this to change that default, indvidual fields 'required'
         * options supercedes this.
         * @default true
         */
        fieldsRequired?: boolean;
        /**
         * default behavior of form is to consider all fields enabled,
         * use this to change that default, indvidual fields 'disabled'
         * options supercedes this.
         * @default true
         */
        fieldsDisabled?: boolean;
        /**
         * default behavior of form is to start with CYCLES.IDLE,
         * use this to change that default, indvidual fields 'initCycle'
         * options supercedes this.
         * @default CYCLE.INIT
         */
        fieldsInitCycle?: FIELD.CYCLE;
        /**
         * listen to all changes occured on any field and alter it's data if necessary,
         * this gets called before the individual field's onChange method if any.
         */
        fieldsOnChange?: Field.OnChange<Field.Type, any>;
        /**
         * global per element dom attributes listener, gets called after field's specific
         * onAttrs event if it exists.
         */
        fieldsOnAttrs?: Field.OnAttrs<Field.Type>;
        /**
         * the last step of checking for form validity is to check for
         * required fields' values and add them to the incompleteList,
         * this option allows for choosing how big or small this list goes.
         * @option true collect all incomplete fields
         * @option false don't collect any incomplete fields
         * @option number collect this many of incomplete fields
         * @default false
         */
        incompleteListCount?: boolean | number;
        /**
         * how should the form react to updating values using form.actions.update
         * @default "silent"
         */
        onUpdateKeyNotFound?: "silent" | "warn";
        /**
         * if the desired data extracted from the form is in the
         * shape of a nested object, then this splitter is used
         * to determine which keys are nested, for now only
         * the dot is supported.
         * @default '.'
         */
        flatObjectKeysChar?: ".";
        /**
         * when no label is provided, the key is used as fallback but sometimes
         * the key is meant to be unflattened later on when fetching the form data,
         * so this offers a way to replace the key flatObjectKeysChar with any
         * character.
         * @default ' ' or empty spcace
         */
        flatLabelJoinChar?: string;
        attrs?: Attributes.Setup;
    };
    type OptionsMerged<G extends Options, D extends Options> = D & G;
    interface StoreObject<F extends Fields, O extends Options<F>> extends _QSTATE.NanoType.DeepMapObject {
        status: FORM.STATUS;
        incomplete: string[];
        values: {
            [K in keyof F]: F[K]["setup"]["value"];
        };
        elements: {
            [K in keyof F]: F[K]["store"]["value"]["element"];
        };
        conditions: {
            [K in keyof F]: Field.Condition;
        };
        errors: {
            [K in keyof F]?: string[];
        };
        extras: {
            [K in keyof F as Extras.Factory<F[K]["setup"]> extends never ? never : K]: Extras.Factory<F[K]["setup"]>;
        };
        props: O["props"];
        attrs: {
            [K in keyof F]: ReturnType<F[K]["store"]["get"]>["attrs"];
        };
    }
    type StoreState<F extends Fields, O extends Options<F>> = _QSTATE.Nano.Map<StoreObject<F, O>>;
    type Store<F extends Fields, O extends Options<F>> = _QSTATE.Store.Factory<StoreState<F, O>, {
        hooks: O["storeHooks"];
        addons: {
            derive: typeof deriveAddon;
        };
    }>;
    type Factory<I extends FieldsIn, F extends Fields<I>, O extends Options<F>> = {
        readonly fields: Fields<I, O>;
        readonly options: O;
        get keys(): () => (keyof F)[];
        submit: Addon.FormSubmit<F, O>;
        update: Addon.FormUpdate<F, O>;
        values: Addon.FormValues<F, O>;
        button: Addon.FormButton<F, O>;
        /**
         * extreme low-level control of form, use setters with extreme care as this affects
         * the core logic of the form, it's advised to not modify form store
         * directly, instead use update, submit..etc to safely mutate form.
         */
        readonly store: Store<F, O>;
        readonly storeh: "hooks" extends keyof Store<F, O> ? Store<F, O>["hooks"] : undefined;
    };
}
declare namespace FunctionProps {
    interface Field<S extends Field.Setup, O extends Form.Options> {
        key: string;
        setup: S;
        options: O | undefined;
        store: Field.Store<S, O>;
    }
    type FieldCycle<S extends Field.Setup, O extends Form.Options> = Field<S, O>;
    type FieldAddon<S extends Field.Setup, O extends Form.Options> = Field<S, O>;
    interface FieldProcessor<S extends Field.Setup, O extends Form.Options> {
        value: any;
        el: Field.Event | undefined;
        manualUpdate: boolean;
        preprocessValue: boolean;
        $next: Field.StoreObject<S, O>;
    }
    type FormCycle<F extends Form.Fields, O extends Form.Options> = {
        fields: F;
        options: O;
        store: Form.Store<F, O>;
    };
    type FormAddon<F extends Form.Fields, O extends Form.Options> = FormCycle<F, O>;
    type RenderAttributes<S extends Field.Setup, O extends Form.Options> = {
        reactive: Field.StoreObject<S, O>;
    };
}
declare namespace Addon {
    type FieldUpdate<S extends Field.Setup, O extends Form.Options> = FieldAddonUpdate<S, O>;
    type FieldRemove<S extends Field.Setup, O extends Form.Options> = FieldAddonRemove<S, O>;
    type FieldReset<S extends Field.Setup, O extends Form.Options> = FieldAddonReset<S, O>;
    type FormSubmit<F extends Form.Fields, O extends Form.Options<F>> = FormAddonSubmit<F, O>;
    type FormUpdate<F extends Form.Fields, O extends Form.Options<F>> = FormAddonUpdate<F, O>;
    type FormValues<F extends Form.Fields, O extends Form.Options<F>> = FormAddonValues<F, O>;
    type FormButton<F extends Form.Fields, O extends Form.Options<F>> = FormAddonButton<F, O>;
}
declare namespace Attributes {
    export type Type = "dom" | "vdom";
    export type Setup = {
        map?: Record<string, Type>;
    };
    type ToDom<T extends Record<string, unknown>> = {
        [K in keyof T as `${Lowercase<K & string>}`]: T[K];
    };
    export namespace Standard {
        interface Input extends Record<string, unknown> {
            id: string;
            required: boolean;
            disabled: boolean;
            autoComplete: "on" | "off";
            type: string;
            name: string;
            multiple: boolean;
            value: any;
            onInput: (event: any) => void;
            onChange: (event: any) => void;
            onFocus: (event: any) => void;
            onBlur: (event: any) => void;
        }
    }
    export namespace Select {
        interface Trigger extends Record<string, unknown> {
            onClick: (event: any) => void;
            name: string;
            value: any;
        }
        interface Option extends Record<string, unknown> {
            value: any;
            selected: boolean;
            onClick: (event: any) => void;
        }
        interface Radio extends Record<string, unknown> {
            value: any;
            selected: boolean;
        }
    }
    export namespace Date {
        interface Input extends Record<string, unknown> {
            id: string;
            required: boolean;
            disabled: boolean;
            autoComplete: "on" | "off";
            type: string;
            name: string;
        }
        interface Event extends Record<string, unknown> {
            id: string;
            name: string;
            onClick: (event: any) => void;
        }
        interface Cell extends Record<string, unknown> {
            id: string;
            name: string;
            onClick: (event: any) => void;
        }
        interface Option extends Record<string, unknown> {
            id: string;
            name: string;
            onClick: (event: any) => void;
        }
    }
    type Attrs<S extends Field.Setup, O extends Form.Options, T extends Record<string, any>> = (S["attrs"] extends object ? S["attrs"]["map"] extends Record<any, any> ? {
        [K in keyof S["attrs"]["map"]]: "vdom" extends S["attrs"]["map"][K] ? T : ToDom<T>;
    } : {} : {}) & (O["attrs"] extends object ? O["attrs"]["map"] extends Record<any, any> ? {
        [K in keyof O["attrs"]["map"]]: "vdom" extends O["attrs"]["map"][K] ? T : ToDom<T>;
    } : {} : {}) extends infer G ? Omit<G, "dom" | "vdom" | "ref"> & {
        ref: (element: any) => void;
        vdom: T;
        dom: ToDom<T>;
    } extends infer L ? {
        [K in keyof L]: L[K];
    } : never : never;
    export type Factory<S extends Field.Setup, O extends Form.Options> = S extends {
        type: "select";
    } ? {
        trigger: Attrs<S, O, Select.Trigger>;
        option: (option: any) => Attrs<S, O, Select.Option>;
    } : S extends {
        type: "select.radio";
    } ? {
        trigger: Attrs<S, O, Select.Trigger>;
        option: (option: any) => Attrs<S, O, Select.Radio>;
    } : S extends {
        type: "date";
    } ? {
        input: Attrs<S, O, Date.Input>;
        event(event: CALENDAR.EVENTS | keyof typeof CALENDAR.EVENTS): Attrs<S, O, Date.Event>;
        cell(cell: Extras.Date.CellDate | Extras.Date.CellTime | DateAttributeCells): Attrs<S, O, Date.Cell>;
        option(option: Extras.Date.Option): Attrs<S, O, Date.Option>;
    } : {
        input: Attrs<S, O, Standard.Input>;
    };
    export {  };
}

export { Addon as A, Check as C, Extras as E, Form as F, IGNORED_SETUP_KEYS as I, MISC as M, Field as a, FunctionProps as b, Attributes as c, FORM as d, FIELD as e, CALENDAR as f };
