import { create } from '@dojo/framework/core/vdom';
import { createICacheMiddleware } from '@dojo/framework/core/middleware/icache';
function compareValidity(a, b) {
    if (typeof a === 'boolean' && typeof b === 'boolean') {
        return true;
    }
    if (typeof a === 'boolean' || typeof b === 'boolean') {
        return false;
    }
    if (b.valid === undefined) {
        return false;
    }
    return a.message === b.message;
}
export const createFormMiddleware = () => {
    const icache = createICacheMiddleware();
    const factory = create({ icache });
    const formMiddleware = factory(function Form({ middleware: { icache } }) {
        const api = {
            value(values) {
                const currentValues = icache.getOrSet('values', {});
                if (values !== undefined) {
                    icache.set('values', values);
                    const newValues = Object.assign({}, currentValues, values);
                    const callbacks = icache.get('callbacks');
                    callbacks && callbacks.onValue && callbacks.onValue(newValues);
                    return newValues;
                }
                return currentValues;
            },
            submit(callback, defaults) {
                if (!this.valid()) {
                    return;
                }
                if (defaults) {
                    return callback(Object.assign({}, defaults, this.value()));
                }
                return callback(this.value());
            },
            onValue(callback) {
                icache.set('callbacks', { onValue: callback }, false);
            },
            disabled(disabled) {
                if (disabled !== undefined) {
                    icache.set('formDisabled', disabled);
                    return disabled;
                }
                return icache.getOrSet('formDisabled', false);
            },
            valid() {
                const values = icache.getOrSet('valid', {});
                const requiredValues = icache.getOrSet('required', {});
                return Object.keys(Object.assign({}, values, requiredValues)).every((key) => {
                    const valid = values[key];
                    const value = typeof valid === 'boolean' || valid === undefined ? valid : valid.valid;
                    return (value === undefined && !requiredValues[key]) || Boolean(value);
                });
            },
            reset() {
                icache.set('values', {});
                let valid = {};
                const values = icache.getOrSet('valid', {});
                Object.keys(values).map((key) => {
                    valid[key] = { valid: undefined, message: '' };
                });
                icache.set('valid', valid);
                icache.set('required', {});
                icache.set('formDisabled', false);
                icache.set('disabled', {});
            },
            field(name, required = false) {
                const requiredValues = icache.getOrSet('required', {});
                if (requiredValues[name] === undefined) {
                    icache.set('required', Object.assign({}, requiredValues, { [name]: required }));
                }
                const values = icache.getOrSet('values', {});
                if (!values.hasOwnProperty(name)) {
                    icache.set('values', Object.assign({}, values, { [name]: undefined }));
                }
                return {
                    name,
                    value: (newValue) => {
                        const values = icache.getOrSet('values', {});
                        if (newValue !== undefined && values[name] !== newValue) {
                            icache.set('values', Object.assign({}, values, { [name]: newValue }));
                            const callbacks = icache.get('callbacks');
                            callbacks &&
                                callbacks.onValue &&
                                callbacks.onValue({ [name]: newValue });
                            return newValue;
                        }
                        return values[name];
                    },
                    valid: (valid, message) => {
                        let newValue = valid || {
                            valid,
                            message: message || ''
                        };
                        const values = icache.getOrSet('valid', {});
                        if (!values.hasOwnProperty(name)) {
                            icache.set('valid', Object.assign({}, values, { [name]: newValue }));
                            return newValue;
                        }
                        if (valid !== undefined) {
                            if (!compareValidity(newValue, values[name])) {
                                icache.set('valid', Object.assign({}, values, { [name]: newValue }));
                                return newValue;
                            }
                        }
                        return values[name];
                    },
                    required: (required) => {
                        const values = icache.getOrSet('required', {});
                        if (required !== undefined && values[name] !== required) {
                            icache.set('required', Object.assign({}, values, { [name]: required }));
                            return required;
                        }
                        return Boolean(values[name]);
                    },
                    disabled: (disabled) => {
                        const formValue = icache.getOrSet('formDisabled', false);
                        const values = icache.getOrSet('disabled', {});
                        if (disabled !== undefined && values[name] !== disabled) {
                            icache.set('disabled', Object.assign({}, values, { [name]: disabled }));
                            return formValue || disabled;
                        }
                        return formValue || Boolean(values[name]);
                    }
                };
            }
        };
        const apiFactory = () => {
            return api;
        };
        apiFactory.value = api.value;
        apiFactory.submit = api.submit;
        apiFactory.onValue = api.onValue;
        apiFactory.disabled = api.disabled;
        apiFactory.valid = api.valid;
        apiFactory.reset = api.reset;
        apiFactory.field = api.field;
        return apiFactory;
    });
    return formMiddleware;
};
export default createFormMiddleware;

/*# sourceMappingURL=middleware.mjs.map*/