import { createOptionBuilder, setMaybeRefValue, isObject, hasOwnProperty, unrefWithDefault, isPromise, applyPluginBaseOptions } from '@vue-layout/core';
import { h, unref, mergeProps, defineComponent } from 'vue';

function buildFormBaseOptions(options, component, defaults) {
    defaults = defaults || {};
    const { buildOrFail } = createOptionBuilder(component);
    return {
        ...options,
        hint: buildOrFail({
            key: 'hint',
            value: options.hint,
            alt: undefined
        }),
        class: buildOrFail({
            key: 'class',
            value: options.class,
            alt: defaults.class || ''
        }),
        props: buildOrFail({
            key: 'props',
            value: options.props,
            alt: defaults.props || {}
        }),
        label: buildOrFail({
            key: 'label',
            value: options.label,
            alt: defaults.label ?? true
        }),
        labelClass: buildOrFail({
            key: 'labelClass',
            value: options.labelClass,
            alt: defaults.labelClass || ''
        }),
        labelContent: buildOrFail({
            key: 'labelContent',
            value: options.labelContent,
            alt: defaults.labelContent || 'Input'
        }),
        validationMessages: options.validationMessages || {},
        validationResult: options.validationResult || {}
    };
}
function handleFormValueChanged(options, value) {
    if (typeof options.value !== 'undefined') {
        options.value = setMaybeRefValue(options.value, value);
    }
    if (options.onChange) {
        options.onChange.call(null, value);
    }
    return options;
}

/*
 * Copyright (c) 2022.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */ var Component;
(function(Component) {
    Component["FormInput"] = 'formInput';
    Component["FormInputCheckbox"] = 'formInputCheckbox';
    Component["FormInputText"] = 'formInputText';
    Component["FormSelect"] = 'formSelect';
    Component["FormSubmit"] = 'formSubmit';
    Component["FormTextarea"] = 'formTextarea';
    Component["ValidationGroup"] = 'validationGroup';
})(Component || (Component = {}));

function isValidationRuleResultWithoutParams(input) {
    return isObject(input) && hasOwnProperty(input, '$message') && hasOwnProperty(input, '$pending') && hasOwnProperty(input, '$invalid') && hasOwnProperty(input, '$response');
}
function isValidationRuleResultWithParams(input) {
    return isValidationRuleResultWithoutParams(input) && hasOwnProperty(input, '$params');
}
function template(str, data, regex = /\{\{(.+?)\}\}/g) {
    return Array.from(str.matchAll(regex)).reduce((acc, match)=>{
        if (typeof data[match[1]] !== 'undefined') {
            return acc.replace(match[0], data[match[1]]);
        }
        return acc;
    }, str);
}

function buildValidationGroupOptions(options) {
    const { buildOrFail } = createOptionBuilder(Component.ValidationGroup);
    return {
        ...options,
        class: buildOrFail({
            key: 'class',
            value: options.class,
            alt: []
        }),
        props: buildOrFail({
            key: 'props',
            value: options.props,
            alt: {}
        }),
        errorClass: buildOrFail({
            key: 'errorClass',
            value: options.errorClass,
            alt: []
        }),
        warningClass: buildOrFail({
            key: 'warningClass',
            value: options.warningClass,
            alt: []
        }),
        validationMessages: options.validationMessages || {},
        validationResult: options.validationResult || {}
    };
}
function buildValidationGroup(input) {
    const options = buildValidationGroupOptions(input);
    const translate = (validator, properties)=>{
        if (options.validationMessages && Object.prototype.hasOwnProperty.call(options.validationMessages, validator)) {
            return template(options.validationMessages[validator], properties || {});
        }
        if (typeof options.validationTranslator !== 'undefined') {
            let translation = options.validationTranslator(validator, properties || {});
            if (typeof translation === 'string') {
                translation = template(translation, properties || {});
                if (translation !== validator) {
                    return translation;
                }
            }
        }
        return `The ${validator} operator condition is not fulfilled.`;
    };
    const invalid = !!options.validationResult && !!options.validationResult.$dirty && !!options.validationResult.$invalid;
    const errors = [];
    const keys = Object.keys(options.validationResult);
    for(let i = 0; i < keys.length; i++){
        if (isObject(options.validationResult[keys[i]]) && options.validationResult[keys[i]].$invalid) {
            if (isValidationRuleResultWithParams(options.validationResult[keys[i]])) {
                errors.push(translate(keys[i], options.validationResult[keys[i]].$params));
            } else if (isValidationRuleResultWithoutParams(options.validationResult[keys[i]])) {
                errors.push(translate(keys[i]));
            }
        }
    }
    const renderChildren = ()=>{
        const children = [];
        if (typeof options.content === 'function') {
            children.push(options.content({
                errors,
                invalid
            }));
        } else {
            children.push(options.content);
        }
        children.push(errors.map((error)=>h('div', {
                class: 'form-group-hint group-required'
            }, [
                error
            ])));
        if (options.hint) {
            children.push(h('div', {
                class: 'form-group-hint'
            }, [
                options.hint
            ]));
        }
        return children;
    };
    return h('div', {
        class: [
            options.class,
            ...options.validationResult && options.validationResult.$invalid && options.validationResult.$dirty ? [
                options.errorClass
            ] : [],
            ...options.validationResult && options.validationResult.$invalid && !options.validationResult.$dirty ? [
                options.warningClass
            ] : []
        ],
        ...options.props
    }, renderChildren());
}

function buildFormInputOptions(input, component) {
    component = component || Component.FormInput;
    const options = buildFormBaseOptions(input, component);
    const { build, buildOrFail } = createOptionBuilder(component);
    return {
        ...options,
        type: buildOrFail({
            key: 'type',
            value: options.type,
            alt: 'text'
        }),
        groupClass: buildOrFail({
            key: 'groupClass',
            value: options.groupClass,
            alt: []
        }),
        groupAppend: buildOrFail({
            key: 'groupAppend',
            value: options.groupAppend,
            alt: false
        }),
        groupAppendClass: build({
            key: 'groupAppendClass',
            value: options.groupAppendClass,
            alt: ''
        }),
        groupAppendContent: build({
            key: 'groupAppendContent',
            value: options.groupAppendContent,
            alt: ''
        }),
        groupPrepend: buildOrFail({
            key: 'groupPrepend',
            value: options.groupPrepend,
            alt: false
        }),
        groupPrependClass: build({
            key: 'groupPrependClass',
            value: options.groupPrependClass,
            alt: ''
        }),
        groupPrependContent: build({
            key: 'groupPrependContent',
            value: options.groupPrependContent,
            alt: ''
        })
    };
}
function buildFormInput(input) {
    const options = buildFormInputOptions(input);
    return buildFormInputFromOptions(options);
}
function buildFormInputFromOptions(options) {
    const children = [];
    if (options.label) {
        children.push(h('label', {
            class: options.labelClass
        }, [
            options.labelContent
        ]));
    }
    const inputGroupChildren = [];
    if (options.groupPrepend) {
        inputGroupChildren.push(h('span', {
            class: options.groupPrependClass
        }, [
            options.groupPrependContent
        ]));
    }
    const rawValue = unref(options.value);
    inputGroupChildren.push(h('input', mergeProps({
        type: options.type,
        class: options.class,
        onInput ($event) {
            if ($event.target.composing) {
                return;
            }
            handleFormValueChanged(options, $event.target.value);
        },
        ...typeof rawValue !== 'undefined' ? {
            value: rawValue
        } : {}
    }, options.props)));
    if (options.groupAppend) {
        inputGroupChildren.push(h('span', {
            class: options.groupAppendClass
        }, [
            options.groupAppendContent
        ]));
    }
    children.push(h('div', {
        class: options.groupClass
    }, inputGroupChildren));
    return buildValidationGroup({
        content: children,
        hint: options.hint,
        validationResult: options.validationResult,
        validationMessages: options.validationMessages,
        validationTranslator: options.validationTranslator
    });
}

const FormInput = defineComponent({
    name: 'FormInput',
    props: {
        modelValue: {
            type: String,
            default: ''
        },
        label: {
            type: Boolean,
            default: false
        },
        labelClass: {
            type: String,
            default: ''
        },
        labelContent: {
            type: String,
            default: ''
        },
        type: {
            type: String,
            default: 'text'
        },
        hint: {
            type: String,
            default: undefined
        },
        validationResult: {
            type: Object,
            default: undefined
        },
        validationMessages: {
            type: Object,
            default: undefined
        },
        validationTranslator: {
            type: Function,
            default: undefined
        }
    },
    emits: [
        'update:modelValue'
    ],
    setup (props, { attrs, emit }) {
        return ()=>buildFormInput({
                label: props.label,
                labelClass: props.labelClass,
                labelContent: props.labelContent,
                hint: props.hint,
                type: props.type,
                value: props.modelValue,
                onChange (input) {
                    emit('update:modelValue', input);
                },
                validationResult: props.validationResult,
                validationMessages: props.validationMessages,
                validationTranslator: props.validationTranslator,
                props: attrs
            });
    }
});

function buildFormInputCheckboxOptions(input) {
    const options = buildFormBaseOptions(input, Component.FormInputCheckbox);
    const { buildOrFail } = createOptionBuilder(Component.FormInputCheckbox);
    return {
        ...options,
        groupClass: buildOrFail({
            key: 'groupClass',
            value: unref(options.groupClass),
            alt: ''
        })
    };
}
function buildFormInputCheckbox(input) {
    const options = buildFormInputCheckboxOptions(input);
    const children = [];
    const id = (Math.random() + 1).toString(36).substring(7);
    const rawValue = unref(options.value);
    children.push(h('input', mergeProps({
        id,
        type: 'checkbox',
        class: options.class,
        onInput ($event) {
            if ($event.target.composing) {
                return;
            }
            handleFormValueChanged(options, !rawValue);
        },
        ...typeof rawValue !== 'undefined' ? {
            checked: rawValue
        } : {}
    }, options.props)));
    if (options.label) {
        children.push(h('label', {
            class: options.labelClass,
            for: id
        }, [
            options.labelContent
        ]));
    }
    return buildValidationGroup({
        content: h('div', {
            class: options.groupClass
        }, children),
        hint: options.hint,
        validationResult: options.validationResult,
        validationMessages: options.validationMessages,
        validationTranslator: options.validationTranslator
    });
}

const FormInputCheckbox = defineComponent({
    name: 'FormInputCheckbox',
    props: {
        modelValue: {
            type: Boolean,
            default: false
        },
        label: {
            type: Boolean,
            default: false
        },
        labelClass: {
            type: String,
            default: ''
        },
        labelContent: {
            type: String,
            default: ''
        },
        hint: {
            type: String,
            default: undefined
        },
        validationResult: {
            type: Object,
            default: undefined
        },
        validationMessages: {
            type: Object,
            default: undefined
        },
        validationTranslator: {
            type: Function,
            default: undefined
        }
    },
    emits: [
        'update:modelValue'
    ],
    setup (props, { attrs, emit }) {
        return ()=>buildFormInputCheckbox({
                label: props.label,
                labelClass: props.labelClass,
                labelContent: props.labelContent,
                hint: props.hint,
                value: props.modelValue,
                onChange (input) {
                    emit('update:modelValue', input);
                },
                validationResult: props.validationResult,
                validationMessages: props.validationMessages,
                validationTranslator: props.validationTranslator,
                props: attrs
            });
    }
});

function buildFormInputText(input) {
    const options = buildFormInputOptions(input, Component.FormInputText);
    return buildFormInputFromOptions(options);
}

function buildFormSelectOptions(input) {
    const options = buildFormBaseOptions(input, Component.FormSelect);
    const { buildOrFail } = createOptionBuilder(Component.FormSelect);
    return {
        ...options,
        options: options.options,
        optionDefaultText: buildOrFail({
            key: 'optionDefaultText',
            value: options.optionDefaultText,
            alt: 'Select'
        }),
        optionDefaultTextEnabled: buildOrFail({
            key: 'optionDefaultTextEnabled',
            value: options.optionDefaultTextEnabled,
            alt: true
        })
    };
}
function buildFormSelect(input) {
    const options = buildFormSelectOptions(input);
    const rawValue = unref(options.value);
    const children = [];
    if (options.optionDefaultTextEnabled) {
        children.push(h('option', {
            value: ''
        }, [
            '-- ',
            options.optionDefaultText,
            ' --'
        ]));
    }
    for(let i = 0; i < options.options.length; i++){
        children.push(h('option', {
            key: options.options[i].id,
            value: options.options[i].id
        }, options.options[i].value));
    }
    return buildValidationGroup({
        content: [
            ...options.label ? [
                h('label', {
                    class: options.labelClass
                }, [
                    options.labelContent
                ])
            ] : [],
            h('select', mergeProps({
                class: options.class,
                onChange ($event) {
                    const $$selectedVal = Array.prototype.filter.call($event.target.options, (o)=>o.selected).map((o)=>'_value' in o ? o._value : o.value);
                    const value = $event.target.multiple ? $$selectedVal : $$selectedVal[0];
                    handleFormValueChanged(options, value);
                },
                ...typeof rawValue !== 'undefined' ? {
                    value: rawValue
                } : {}
            }, options.props), children)
        ],
        hint: options.hint,
        validationResult: options.validationResult,
        validationMessages: options.validationMessages,
        validationTranslator: options.validationTranslator
    });
}

const FormSelect = defineComponent({
    name: 'FormSelect',
    props: {
        modelValue: {
            type: String,
            default: ''
        },
        label: {
            type: Boolean,
            default: false
        },
        labelClass: {
            type: String,
            default: ''
        },
        labelContent: {
            type: String,
            default: ''
        },
        hint: {
            type: String,
            default: undefined
        },
        validationResult: {
            type: Object,
            default: undefined
        },
        validationMessages: {
            type: Object,
            default: undefined
        },
        validationTranslator: {
            type: Function,
            default: undefined
        },
        options: {
            type: Object,
            required: true
        }
    },
    emits: [
        'update:modelValue'
    ],
    setup (props, { attrs, emit }) {
        return ()=>buildFormSelect({
                label: props.label,
                labelClass: props.labelClass,
                labelContent: props.labelContent,
                hint: props.hint,
                value: props.modelValue,
                onChange (input) {
                    emit('update:modelValue', input);
                },
                validationResult: props.validationResult,
                validationMessages: props.validationMessages,
                validationTranslator: props.validationTranslator,
                props: attrs,
                options: props.options
            });
    }
});

function buildFormSubmitOptions(options) {
    const { buildOrFail } = createOptionBuilder(Component.FormSubmit);
    return {
        ...options,
        type: buildOrFail({
            key: 'type',
            value: options.type,
            alt: 'button'
        }),
        class: buildOrFail({
            key: 'class',
            value: options.class,
            alt: []
        }),
        props: buildOrFail({
            key: 'props',
            value: options.props,
            alt: {}
        }),
        icon: buildOrFail({
            key: 'icon',
            value: options.icon,
            alt: true
        }),
        validationResult: unrefWithDefault(options.validationResult, {}),
        updateText: buildOrFail({
            key: 'updateText',
            value: options.updateText,
            alt: 'Update'
        }),
        updateIconClass: buildOrFail({
            key: 'updateIconClass',
            value: options.updateIconClass,
            alt: []
        }),
        updateButtonClass: buildOrFail({
            key: 'updateButtonClass',
            value: options.updateButtonClass,
            alt: []
        }),
        createText: buildOrFail({
            key: 'createText',
            value: options.createText,
            alt: 'Create'
        }),
        createIconClass: buildOrFail({
            key: 'createIconClass',
            value: options.createIconClass,
            alt: []
        }),
        createButtonClass: buildOrFail({
            key: 'createButtonClass',
            value: options.createButtonClass,
            alt: []
        }),
        busy: options.busy ?? false,
        valid: options.valid ?? true,
        isEditing: options.isEditing ?? false
    };
}
function buildFormSubmit(input) {
    const options = buildFormSubmitOptions(input);
    let icon = [];
    if (options.icon) {
        icon = [
            h('i', {
                class: [
                    ...options.isEditing ? [
                        options.updateIconClass
                    ] : [],
                    ...!options.isEditing ? [
                        options.createIconClass
                    ] : []
                ]
            })
        ];
    }
    return h(options.type, mergeProps({
        ...options.type === 'button' ? {
            type: 'submit'
        } : {},
        class: [
            ...options.isEditing ? [
                options.updateButtonClass
            ] : [],
            ...!options.isEditing ? [
                options.createButtonClass
            ] : []
        ],
        disabled: options.validationResult.$invalid || !options.valid || unref(options.busy),
        onClick ($event) {
            $event.preventDefault();
            options.busy = setMaybeRefValue(options.busy, true);
            const promise = options.submit();
            if (isPromise(promise)) {
                promise.finally(()=>{
                    options.busy = setMaybeRefValue(options.busy, false);
                });
            }
            return promise;
        }
    }, options.props), [
        icon,
        ' ',
        options.isEditing ? options.updateText : options.createText
    ]);
}

const FormSubmit = defineComponent({
    name: 'FormSubmit',
    props: {
        modelValue: {
            type: Boolean,
            default: false
        },
        icon: {
            type: Boolean,
            default: true
        },
        isEditing: {
            type: Boolean,
            default: false
        },
        busy: {
            type: Boolean,
            default: false
        },
        createText: {
            type: [
                String,
                Object
            ],
            default: undefined
        },
        createIconClass: {
            type: [
                String,
                Object
            ],
            default: undefined
        },
        createButtonClass: {
            type: [
                String,
                Object
            ],
            default: undefined
        },
        updateText: {
            type: [
                String,
                Object
            ],
            default: undefined
        },
        updateIconClass: {
            type: [
                String,
                Object
            ],
            default: undefined
        },
        updateButtonClass: {
            type: [
                String,
                Object
            ],
            default: undefined
        },
        submit: {
            type: Function
        },
        validationResult: {
            type: Object,
            default: undefined
        }
    },
    emits: [
        'update:modelValue'
    ],
    setup (props, { attrs, emit }) {
        return ()=>buildFormSubmit({
                icon: props.icon,
                busy: props.busy,
                isEditing: props.isEditing,
                createText: props.createText,
                createIconClass: props.createIconClass,
                createButtonClass: props.createButtonClass,
                updateText: props.updateText,
                updateIconClass: props.updateIconClass,
                updateButtonClass: props.updateButtonClass,
                submit () {
                    if (!props.submit) {
                        return;
                    }
                    emit('update:modelValue', true);
                    Promise.resolve().then(props.submit).then(()=>{
                        emit('update:modelValue', false);
                    });
                },
                validationResult: props.validationResult,
                props: attrs
            });
    }
});

function buildFormTextareaOptions(input) {
    const options = buildFormBaseOptions(input, Component.FormTextarea);
    return {
        ...options
    };
}
function buildFormTextarea(input) {
    const options = buildFormTextareaOptions(input);
    const children = [];
    if (options.label) {
        children.push(h('label', {
            class: options.labelClass
        }, [
            options.labelContent
        ]));
    }
    const rawValue = unref(options.value);
    return buildValidationGroup({
        content: [
            ...children,
            h('textarea', mergeProps({
                placeholder: '...',
                class: options.class,
                onInput ($event) {
                    if ($event.target.composing) {
                        return;
                    }
                    handleFormValueChanged(options, $event.target.value);
                },
                ...typeof rawValue !== 'undefined' ? {
                    value: rawValue
                } : {}
            }, options.props))
        ],
        hint: options.hint,
        validationResult: options.validationResult,
        validationMessages: options.validationMessages,
        validationTranslator: options.validationTranslator
    });
}

const FormTextarea = defineComponent({
    name: 'FormTextarea',
    props: {
        modelValue: {
            type: String,
            default: ''
        },
        label: {
            type: Boolean,
            default: false
        },
        labelClass: {
            type: String,
            default: ''
        },
        labelContent: {
            type: String,
            default: ''
        },
        hint: {
            type: String,
            default: undefined
        },
        validationResult: {
            type: Object,
            default: undefined
        },
        validationMessages: {
            type: Object,
            default: undefined
        },
        validationTranslator: {
            type: Function,
            default: undefined
        }
    },
    emits: [
        'update:modelValue'
    ],
    setup (props, { attrs, emit }) {
        return ()=>buildFormTextarea({
                label: props.label,
                labelClass: props.labelClass,
                labelContent: props.labelContent,
                hint: props.hint,
                value: props.modelValue,
                onChange (input) {
                    emit('update:modelValue', input);
                },
                validationResult: props.validationResult,
                validationMessages: props.validationMessages,
                validationTranslator: props.validationTranslator,
                props: attrs
            });
    }
});

function install(instance, options) {
    options ?? (options = {});
    applyPluginBaseOptions(options);
    Object.entries({
        FormInputCheckbox,
        FormInput,
        FormSelect,
        FormSubmit,
        FormTextarea
    }).forEach(([componentName, component])=>{
        instance.component(componentName, component);
    });
}
var index = {
    install
};

export { Component, FormInput, FormInputCheckbox, FormSelect, FormSubmit, FormTextarea, buildFormBaseOptions, buildFormInput, buildFormInputCheckbox, buildFormInputCheckboxOptions, buildFormInputFromOptions, buildFormInputOptions, buildFormInputText, buildFormSelect, buildFormSelectOptions, buildFormSubmit, buildFormSubmitOptions, buildFormTextarea, buildFormTextareaOptions, buildValidationGroup, buildValidationGroupOptions, index as default, handleFormValueChanged, install };
//# sourceMappingURL=index.mjs.map
