import { __assign, __read, __rest } from "tslib";
import * as React from "react";
import { valueOrDefault } from "@intelligentgraphics/ig.utilities";
var validateField = function (value, config) {
    if (config.required) {
        if (value === "") {
            return {
                valid: false,
                message: { type: "Required" },
            };
        }
    }
    if (config.validate !== undefined) {
        return config.validate(value);
    }
    return {
        valid: true,
        value: value,
        message: undefined,
    };
};
var init = function (state) {
    var result = {
        valid: true,
        fields: {},
        config: state.config,
    };
    for (var fieldIdentifier in state.config.fields) {
        var field = state.config.fields[fieldIdentifier];
        var value = valueOrDefault(field.defaultValue, "");
        var validationResult = validateField(value, field);
        if (!validationResult) {
            result.valid = false;
        }
        var newValue = valueOrDefault(validationResult.value, value);
        result.fields[fieldIdentifier] = {
            message: validationResult.message,
            valid: validationResult.valid,
            value: newValue,
        };
    }
    return result;
};
var reducer = function (state, action) {
    var _a;
    switch (action.type) {
        case "changeValue":
            var fieldConfig = state.config.fields[action.identifier];
            var validationResult = validateField(action.value, fieldConfig);
            var value = valueOrDefault(validationResult.value, action.value);
            var newState = __assign(__assign({}, state), { fields: __assign(__assign({}, state.fields), (_a = {}, _a[action.identifier] = {
                    valid: validationResult.valid,
                    message: validationResult.message,
                    value: value,
                }, _a)) });
            newState.valid = true;
            for (var key in newState.fields) {
                if (!newState.fields[key].valid) {
                    newState.valid = false;
                    break;
                }
            }
            return newState;
        case "init":
            return init(__assign(__assign({}, state), { config: action.config }));
    }
    return state;
};
export var useForm = function (config) {
    var _a = __read(React.useReducer(reducer, { config: config, fields: {}, valid: true }, init), 2), state = _a[0], dispatch = _a[1];
    React.useEffect(function () {
        if (state.config === config) {
            return;
        }
        dispatch({
            type: "init",
            config: config,
        });
    }, [config]);
    var data = React.useMemo(function () {
        var data = {
            fields: [],
            values: {},
            valid: state.valid,
        };
        var _loop_1 = function (fieldIdentifier) {
            var fieldState = state.fields[fieldIdentifier];
            var _a = state.config.fields[fieldIdentifier], required = _a.required, defaultValue = _a.defaultValue, validate = _a.validate, customConfig = __rest(_a, ["required", "defaultValue", "validate"]);
            data.fields.push(__assign(__assign(__assign({}, fieldState), customConfig), { required: required, identifier: fieldIdentifier, onChange: function (value) {
                    return dispatch({
                        type: "changeValue",
                        identifier: fieldIdentifier,
                        value: value,
                    });
                } }));
            data.values[fieldIdentifier] = fieldState.value;
        };
        for (var fieldIdentifier in state.config.fields) {
            _loop_1(fieldIdentifier);
        }
        return data;
    }, [state]);
    return data;
};
var Form = function (props) {
    var state = useForm(props);
    return props.children(state);
};
Form.displayName = "Form";
export default Form;
