import { jsx as _jsx } from "@emotion/react/jsx-runtime";
/* eslint-disable fp/no-delete */
import React from "react";
import { createContext } from "./react-immersive-history";
import { getComponent } from "./interfaces";
import { RuntimeContext } from "./RuntimeContext";
import { VariablesProvider } from "./VariablesContext";
import { usePageParam } from "./hooks/usePageParam";
const initialValues = {
    values: {},
    suggestions: [],
    invalidValues: {},
};
export const inputFieldPrefix = "input.";
export const validateFieldPrefix = "validate.";
export const RuntimeInputContext = createContext(initialValues, (modify) => ({
    handleChange: (key, value) => {
        modify((draft) => {
            draft.values[key] = value;
        });
    },
    setVariables(suggestions) {
        modify((draft) => {
            draft.suggestions = suggestions;
        });
    },
    setValidation: (validation) => {
        modify((draft) => {
            Object.keys(validation).forEach((key) => {
                if (typeof validation[key] === "undefined") {
                    delete draft.invalidValues[key];
                }
                else {
                    draft.invalidValues[key] = validation[key];
                }
            });
        });
    },
    resetValidation: () => {
        modify((draft) => {
            draft.invalidValues = {};
        });
    },
    resetValues: () => {
        modify((draft) => {
            draft.values = {};
        });
    },
    removeKey: (key) => {
        modify((draft) => {
            delete draft.values[key];
        });
    },
}));
const RuntimeVariablesProvider = (props) => {
    const inputValues = RuntimeInputContext.useSelectState((state) => state.values);
    return (_jsx(VariablesProvider, Object.assign({ values: inputValues }, { children: props.children })));
};
export const RuntimeInputProvider = (props) => {
    return (_jsx(RuntimeInputContext.Provider, { children: _jsx(RuntimeVariablesProvider, { children: props.children }) }));
};
export const useRuntimeInput = (data, row, config) => {
    var _a, _b, _c;
    const value = RuntimeInputContext.useSelectState((state) => {
        return state.values[inputFieldPrefix + data.inputID];
    });
    const actions = RuntimeInputContext.useActions();
    const hasChanged = React.useRef(false);
    const handleChange = React.useCallback((value) => {
        hasChanged.current = true;
        actions.handleChange(inputFieldPrefix + data.inputID, value);
    }, [data.inputID, actions.handleChange]);
    const validation = React.useMemo(() => {
        var _a, _b;
        const validationResult = ((_a = data.validation) === null || _a === void 0 ? void 0 : _a.required) && ((_b = config === null || config === void 0 ? void 0 : config.validate) === null || _b === void 0 ? void 0 : _b.call(config, value));
        return validationResult ? validationResult : { error: undefined };
    }, [config, (_a = data.validation) === null || _a === void 0 ? void 0 : _a.required, value]);
    const oldDataInputID = React.useRef(data.inputID);
    const emptyError = React.useMemo(() => ({ error: "" }), []);
    const produceValidationObj = React.useMemo(() => {
        return {
            added: (key, value) => ({ [key]: value }),
            removed: (key) => ({ [key]: undefined }),
        };
    }, []);
    React.useEffect(() => {
        var _a;
        actions.handleChange(inputFieldPrefix + data.inputID, config === null || config === void 0 ? void 0 : config.defaultValue);
        // make required
        if ((_a = data.validation) === null || _a === void 0 ? void 0 : _a.required) {
            actions.setValidation(produceValidationObj.added(data.inputID, emptyError));
        }
        return () => {
            actions.removeKey(inputFieldPrefix + data.inputID);
        };
    }, []);
    React.useEffect(() => {
        var _a;
        if ((_a = data.validation) === null || _a === void 0 ? void 0 : _a.required) {
            if (oldDataInputID.current !== data.inputID) {
                actions.setValidation(Object.assign(Object.assign({}, produceValidationObj.removed(oldDataInputID.current)), produceValidationObj.added(data.inputID, emptyError)));
                oldDataInputID.current = data.inputID;
            }
            else {
                actions.setValidation(produceValidationObj.added(data.inputID, emptyError));
            }
        }
        else {
            actions.setValidation(produceValidationObj.removed(data.inputID));
        }
    }, [data.inputID, (_b = data.validation) === null || _b === void 0 ? void 0 : _b.required]);
    React.useEffect(() => {
        var _a;
        if (typeof validation.error !== "undefined" && ((_a = data.validation) === null || _a === void 0 ? void 0 : _a.required)) {
            actions.setValidation(produceValidationObj.added(data.inputID, validation));
        }
        else {
            actions.setValidation(produceValidationObj.removed(data.inputID));
        }
    }, [validation.error, data.inputID, (_c = data.validation) === null || _c === void 0 ? void 0 : _c.required]);
    React.useEffect(() => {
        if (!hasChanged.current && data.inputID in row && row[data.inputID]) {
            handleChange(row === null || row === void 0 ? void 0 : row[data.inputID]);
        }
    }, [row === null || row === void 0 ? void 0 : row[data.inputID], handleChange, value, config === null || config === void 0 ? void 0 : config.defaultValue]);
    return {
        onChange: handleChange,
        value,
        validation,
    };
};
export const useInputVariables = () => {
    const pageID = usePageParam();
    const componentRefs = RuntimeContext.useSelectState((state) => { var _a; return ((_a = state.maps.page[pageID]) === null || _a === void 0 ? void 0 : _a.components) || []; });
    const componentsMap = RuntimeContext.useSelectState((state) => state.maps.component);
    const components = React.useMemo(() => componentRefs.map((ref) => componentsMap[ref.component]).filter((x) => x), [componentRefs, componentsMap]);
    const suggestions = React.useMemo(() => components.flatMap((comp) => {
        const CompType = getComponent(comp.componentID);
        return Object.entries(
        // app does not have to be valid to parse the suggestions
        CompType ? CompType.propDefinition : {}).flatMap(([key, propDef]) => {
            if (propDef.type === "role")
                return [
                    {
                        id: inputFieldPrefix + "roleId",
                        display: inputFieldPrefix + "roleId",
                    },
                ];
            if (propDef.type !== "state")
                return [];
            const fieldValue = comp.properties[key];
            // Previously has !fieldValue || fieldValue.type === "field" condition
            if (!fieldValue)
                return [];
            const id = inputFieldPrefix + fieldValue.inputID;
            return [
                {
                    id,
                    display: id,
                },
            ];
        });
    }), [components]);
    return suggestions;
};
//# sourceMappingURL=RuntimeInput.js.map