import XEUtils from 'xe-utils';
import { renderer, getComponent } from '../../ui';
import { getOnName, getModelEvent, getChangeEvent } from '../../ui/src/vn';
import { createComponentLog } from '../../ui/src/log';
const { errLog } = createComponentLog('form');
const componentDefaultModelProp = 'value';
/**
 * 已废弃
 * @deprecated
 */
function getOldComponentName(name) {
    return `vxe-${`${name || ''}`.replace('$', '')}`;
}
/**
 * 已废弃
 * @deprecated
 */
function getOldComponent({ name }) {
    return getOldComponentName(name);
}
function getDefaultComponent({ name }) {
    return getComponent(name) || name;
}
function getNativeAttrs(renderOpts) {
    let { name, attrs } = renderOpts;
    if (name === 'input') {
        attrs = Object.assign({ type: 'text' }, attrs);
    }
    return attrs;
}
function getComponentFormItemProps(renderOpts, params, value, defaultProps) {
    return XEUtils.assign({}, defaultProps, renderOpts.props, { [componentDefaultModelProp]: value });
}
/**
 * 原生事件处理
 * @param renderOpts
 * @param params
 * @param modelFunc
 * @param changeFunc
 */
function getElementOns(renderOpts, params, modelFunc, changeFunc) {
    const { events } = renderOpts;
    const modelEvent = getModelEvent(renderOpts);
    const changeEvent = getChangeEvent(renderOpts);
    const isSameEvent = changeEvent === modelEvent;
    const ons = {};
    if (events) {
        XEUtils.objectEach(events, (func, key) => {
            ons[getOnName(key)] = function (...args) {
                func(params, ...args);
            };
        });
    }
    if (modelFunc) {
        ons[getOnName(modelEvent)] = function (targetEvnt) {
            modelFunc(targetEvnt);
            if (isSameEvent && changeFunc) {
                changeFunc(targetEvnt);
            }
            if (events && events[modelEvent]) {
                events[modelEvent](params, targetEvnt);
            }
        };
    }
    if (!isSameEvent && changeFunc) {
        ons[getOnName(changeEvent)] = function (...args) {
            changeFunc(...args);
            if (events && events[changeEvent]) {
                events[changeEvent](params, ...args);
            }
        };
    }
    return ons;
}
/**
 * 组件事件处理
 * @param renderOpts
 * @param params
 * @param modelFunc
 * @param changeFunc
 */
function getComponentOns(renderOpts, params, eFns, eventOns) {
    const { events } = renderOpts;
    const { model: modelFunc, change: changeFunc } = eFns || {};
    const modelEvent = getModelEvent(renderOpts);
    const changeEvent = getChangeEvent(renderOpts);
    const ons = {};
    XEUtils.objectEach(events, (func, key) => {
        ons[getOnName(key)] = function (...args) {
            if (!XEUtils.isFunction(func)) {
                errLog('vxe.error.errFunc', [func]);
            }
            func(params, ...args);
        };
    });
    if (modelFunc) {
        ons[getOnName(modelEvent)] = function (targetEvnt) {
            modelFunc(targetEvnt);
            if (events && events[modelEvent]) {
                events[modelEvent](params, targetEvnt);
            }
        };
    }
    if (changeFunc) {
        ons[getOnName(changeEvent)] = function (...args) {
            changeFunc(...args);
            if (events && events[changeEvent]) {
                events[changeEvent](params, ...args);
            }
        };
    }
    return eventOns ? Object.assign(ons, eventOns) : ons;
}
function getItemOns(renderOpts, params) {
    const { $form, data, field } = params;
    return getComponentOns(renderOpts, params, {
        model(value) {
            // 处理 model 值双向绑定
            XEUtils.set(data, field, value);
        },
        change() {
            // 处理 change 事件相关逻辑
            $form.updateStatus(params);
            if (renderOpts.changeToSubmit) {
                $form.handleSubmitEvent(new Event('change'));
            }
        }
    });
}
function getNativeItemOns(renderOpts, params) {
    const { $form, data, field } = params;
    return getElementOns(renderOpts, params, (evnt) => {
        // 处理 model 值双向绑定
        const itemValue = evnt.target.value;
        XEUtils.set(data, field, itemValue);
    }, () => {
        // 处理 change 事件相关逻辑
        $form.updateStatus(params);
    });
}
function renderNativeOptgroup(h, renderOpts, params, renderOptionsMethods) {
    const { optionGroups, optionGroupProps = {} } = renderOpts;
    const groupOptions = optionGroupProps.options || 'options';
    const groupLabel = optionGroupProps.label || 'label';
    if (optionGroups) {
        return optionGroups.map((group, gIndex) => {
            return h('optgroup', {
                key: gIndex,
                attrs: {
                    label: group[groupLabel]
                }
            }, renderOptionsMethods(group[groupOptions], renderOpts, params));
        });
    }
    return [];
}
/**
 * 渲染表单-项
 * 用于渲染原生的标签
 */
function nativeItemRender(h, renderOpts, params) {
    const { data, field } = params;
    const { name } = renderOpts;
    const attrs = getNativeAttrs(renderOpts);
    const itemValue = XEUtils.get(data, field);
    return [
        h(`${name}`, {
            class: `vxe-default-${name}`,
            attrs,
            domProps: {
                value: attrs && name === 'input' && (attrs.type === 'submit' || attrs.type === 'reset') ? null : itemValue
            },
            on: getNativeItemOns(renderOpts, params)
        })
    ];
}
function defaultItemRender(h, renderOpts, params) {
    const { data, field } = params;
    const itemValue = XEUtils.get(data, field);
    return [
        h(getDefaultComponent(renderOpts), {
            props: getComponentFormItemProps(renderOpts, params, itemValue),
            on: getItemOns(renderOpts, params)
        })
    ];
}
/**
 * 已废弃
 * @deprecated
 */
function oldItemRender(h, renderOpts, params) {
    const { data, field } = params;
    const itemValue = XEUtils.get(data, field);
    return [
        h(getOldComponent(renderOpts), {
            props: getComponentFormItemProps(renderOpts, params, itemValue),
            on: getItemOns(renderOpts, params)
        })
    ];
}
/**
 * 已废弃
 * @deprecated
 */
function oldButtonItemRender(h, renderOpts, params) {
    return [
        h('vxe-button', {
            props: getComponentFormItemProps(renderOpts, params, null),
            on: getComponentOns(renderOpts, params)
        })
    ];
}
/**
 * 已废弃
 * @deprecated
 */
function oldButtonsItemRender(h, renderOpts, params) {
    const { children } = renderOpts;
    return children ? children.map((childRenderOpts) => oldButtonItemRender(h, childRenderOpts, params)[0]) : [];
}
/**
 * 渲染原生的 select 标签
 */
function renderNativeFormOptions(h, options, renderOpts, params) {
    const { data, field } = params;
    const { optionProps = {} } = renderOpts;
    const labelProp = optionProps.label || 'label';
    const valueProp = optionProps.value || 'value';
    const disabledProp = optionProps.disabled || 'disabled';
    const cellValue = XEUtils.get(data, field);
    if (options) {
        return options.map((item, oIndex) => {
            return h('option', {
                key: oIndex,
                props: {
                    value: item[valueProp],
                    disabled: item[disabledProp],
                    /* eslint-disable eqeqeq */
                    selected: item[valueProp] == cellValue
                }
            }, item[labelProp]);
        });
    }
    return [];
}
/**
 * 渲染表单-项
 */
function defaultFormItemRender(h, renderOpts, params) {
    const { data, field } = params;
    const itemValue = XEUtils.get(data, field);
    return [
        h(getDefaultComponent(renderOpts), {
            props: getComponentFormItemProps(renderOpts, params, itemValue),
            on: getItemOns(renderOpts, params)
        })
    ];
}
function formItemRadioAndCheckboxRender(h, renderOpts, params) {
    const { options, optionProps } = renderOpts;
    const { data, field } = params;
    const itemValue = XEUtils.get(data, field);
    return [
        h(getDefaultComponent(renderOpts), {
            props: Object.assign({ options,
                optionProps }, getComponentFormItemProps(renderOpts, params, itemValue)),
            on: getItemOns(renderOpts, params)
        })
    ];
}
/**
 * 已废弃
 * @deprecated
 */
function oldFormItemRadioAndCheckboxRender(h, renderOpts, params) {
    const { name, options, optionProps = {} } = renderOpts;
    const { data, field } = params;
    const labelProp = optionProps.label || 'label';
    const valueProp = optionProps.value || 'value';
    const disabledProp = optionProps.disabled || 'disabled';
    const itemValue = XEUtils.get(data, field);
    const compName = getOldComponentName(name);
    // 如果是分组
    if (options) {
        return [
            h(`${compName}-group`, {
                props: getComponentFormItemProps(renderOpts, params, itemValue),
                on: getItemOns(renderOpts, params),
                scopedSlots: {
                    default: () => {
                        return options.map((item, index) => {
                            return h(compName, {
                                key: index,
                                props: {
                                    label: item[valueProp],
                                    content: item[labelProp],
                                    disabled: item[disabledProp]
                                }
                            });
                        });
                    }
                }
            })
        ];
    }
    return [
        h(compName, {
            props: getComponentFormItemProps(renderOpts, params, itemValue),
            on: getItemOns(renderOpts, params)
        })
    ];
}
/**
 * 表单 - 渲染器
 */
renderer.mixin({
    input: {
        formItemAutoFocus: true,
        renderFormItemContent: nativeItemRender
    },
    textarea: {
        formItemAutoFocus: true,
        renderFormItemContent: nativeItemRender
    },
    select: {
        formItemAutoFocus: true,
        renderFormItemContent(h, renderOpts, params) {
            return [
                h('select', {
                    class: 'vxe-default-select',
                    attrs: Object.assign({}, getNativeAttrs(renderOpts)),
                    on: getNativeItemOns(renderOpts, params)
                }, renderOpts.optionGroups ? renderNativeOptgroup(h, renderOpts, params, renderNativeFormOptions) : renderNativeFormOptions(h, renderOpts.options, renderOpts, params))
            ];
        }
    },
    VxeInput: {
        formItemAutoFocus: true,
        renderFormItemContent: defaultItemRender
    },
    VxeNumberInput: {
        formItemAutoFocus: true,
        renderFormItemContent: defaultItemRender
    },
    VxePasswordInput: {
        formItemAutoFocus: true,
        renderFormItemContent: defaultItemRender
    },
    VxeTextarea: {
        formItemAutoFocus: true,
        renderFormItemContent: defaultItemRender
    },
    VxeDatePicker: {
        formItemAutoFocus: true,
        renderFormItemContent: defaultItemRender
    },
    VxeDateRangePicker: {
        formItemAutoFocus: true,
        renderFormItemContent(h, renderOpts, params) {
            const { startField, endField } = renderOpts;
            const { $form, data, field } = params;
            const itemValue = XEUtils.get(data, field);
            const seProps = {};
            const seOs = {};
            if (startField && endField) {
                seProps.startValue = XEUtils.get(data, startField);
                seProps.endValue = XEUtils.get(data, endField);
                seOs['update:startValue'] = (value) => {
                    if (startField) {
                        XEUtils.set(data, startField, value);
                    }
                };
                seOs['update:endValue'] = (value) => {
                    if (endField) {
                        XEUtils.set(data, endField, value);
                    }
                };
            }
            return [
                h(getDefaultComponent(renderOpts), {
                    props: getComponentFormItemProps(renderOpts, params, itemValue, seProps),
                    on: getComponentOns(renderOpts, params, {
                        model(value) {
                            // 处理 model 值双向绑定
                            XEUtils.set(data, field, value);
                        },
                        change({ $event, isFinish }) {
                            // 处理 change 事件相关逻辑
                            $form.updateStatus(params);
                            if (renderOpts.changeToSubmit && isFinish) {
                                $form.handleSubmitEvent($event);
                            }
                        }
                    }, seOs)
                })
            ];
        }
    },
    VxeButton: {
        renderFormItemContent: defaultFormItemRender
    },
    VxeButtonGroup: {
        renderFormItemContent(h, renderOpts, params) {
            const { options } = renderOpts;
            const { data, field } = params;
            const itemValue = XEUtils.get(data, field);
            return [
                h(getDefaultComponent(renderOpts), {
                    props: Object.assign({ options }, getComponentFormItemProps(renderOpts, params, itemValue)),
                    on: getItemOns(renderOpts, params)
                })
            ];
        }
    },
    VxeSelect: {
        formItemAutoFocus: true,
        renderFormItemContent(h, renderOpts, params) {
            const { data, field } = params;
            const { options, optionProps, optionGroups, optionGroupProps } = renderOpts;
            const itemValue = XEUtils.get(data, field);
            return [
                h(getDefaultComponent(renderOpts), {
                    props: getComponentFormItemProps(renderOpts, params, itemValue, { options, optionProps, optionGroups, optionGroupProps }),
                    on: getItemOns(renderOpts, params)
                })
            ];
        }
    },
    VxeTreeSelect: {
        formItemAutoFocus: true,
        renderFormItemContent(h, renderOpts, params) {
            const { data, field } = params;
            const { options, optionProps } = renderOpts;
            const itemValue = XEUtils.get(data, field);
            return [
                h(getDefaultComponent(renderOpts), {
                    props: getComponentFormItemProps(renderOpts, params, itemValue, { options, optionProps }),
                    on: getItemOns(renderOpts, params)
                })
            ];
        }
    },
    VxeCascader: {
        formItemAutoFocus: true,
        renderFormItemContent(h, renderOpts, params) {
            const { data, field } = params;
            const { options, optionProps } = renderOpts;
            const itemValue = XEUtils.get(data, field);
            return [
                h(getDefaultComponent(renderOpts), {
                    props: getComponentFormItemProps(renderOpts, params, itemValue, { options, optionProps }),
                    on: getItemOns(renderOpts, params)
                })
            ];
        }
    },
    VxeTableSelect: {
        formItemAutoFocus: true,
        renderFormItemContent(h, renderOpts, params) {
            const { data, field } = params;
            const { options, optionProps } = renderOpts;
            const itemValue = XEUtils.get(data, field);
            return [
                h(getDefaultComponent(renderOpts), {
                    props: getComponentFormItemProps(renderOpts, params, itemValue, { options, optionProps }),
                    on: getItemOns(renderOpts, params)
                })
            ];
        }
    },
    VxeColorPicker: {
        formItemAutoFocus: true,
        renderFormItemContent(h, renderOpts, params) {
            const { data, field } = params;
            const { options } = renderOpts;
            const itemValue = XEUtils.get(data, field);
            return [
                h(getDefaultComponent(renderOpts), {
                    props: getComponentFormItemProps(renderOpts, params, itemValue, { colors: options }),
                    on: getItemOns(renderOpts, params)
                })
            ];
        }
    },
    VxeIconPicker: {
        formItemAutoFocus: true,
        renderFormItemContent(h, renderOpts, params) {
            const { data, field } = params;
            const { options } = renderOpts;
            const itemValue = XEUtils.get(data, field);
            return [
                h(getDefaultComponent(renderOpts), {
                    props: getComponentFormItemProps(renderOpts, params, itemValue, { icons: options }),
                    on: getItemOns(renderOpts, params)
                })
            ];
        }
    },
    VxeRadio: {
        renderFormItemContent: defaultFormItemRender
    },
    VxeRadioGroup: {
        renderFormItemContent: formItemRadioAndCheckboxRender
    },
    VxeCheckbox: {
        renderFormItemContent: defaultFormItemRender
    },
    VxeCheckboxGroup: {
        renderFormItemContent: formItemRadioAndCheckboxRender
    },
    VxeSwitch: {
        renderFormItemContent: defaultItemRender
    },
    VxeRate: {
        renderFormItemContent: defaultItemRender
    },
    VxeSlider: {
        renderFormItemContent: defaultItemRender
    },
    VxeImage: {
        renderFormItemContent(h, renderOpts, params) {
            const { data, field } = params;
            const { props } = renderOpts;
            const itemValue = XEUtils.get(data, field);
            return [
                h(getDefaultComponent(renderOpts), {
                    props: Object.assign(Object.assign({}, props), { src: itemValue }),
                    on: getItemOns(renderOpts, params)
                })
            ];
        }
    },
    VxeImageGroup: {
        renderFormItemContent(h, renderOpts, params) {
            const { data, field } = params;
            const { props } = renderOpts;
            const itemValue = XEUtils.get(data, field);
            return [
                h(getDefaultComponent(renderOpts), {
                    props: Object.assign(Object.assign({}, props), { urlList: itemValue }),
                    on: getItemOns(renderOpts, params)
                })
            ];
        }
    },
    VxeUpload: {
        renderFormItemContent: defaultItemRender
    },
    // 以下已废弃
    $input: {
        formItemAutoFocus: 'input',
        renderFormItemContent: oldItemRender
    },
    $textarea: {
        formItemAutoFocus: 'textarea',
        renderFormItemContent: oldItemRender
    },
    $button: {
        renderFormItemContent: oldButtonItemRender
    },
    $buttons: {
        renderFormItemContent: oldButtonsItemRender
    },
    $select: {
        formItemAutoFocus: 'input',
        renderFormItemContent(h, renderOpts, params) {
            const { data, field } = params;
            const { options, optionProps, optionGroups, optionGroupProps } = renderOpts;
            const itemValue = XEUtils.get(data, field);
            return [
                h(getOldComponent(renderOpts), {
                    props: getComponentFormItemProps(renderOpts, params, itemValue, { options, optionProps, optionGroups, optionGroupProps }),
                    on: getItemOns(renderOpts, params)
                })
            ];
        }
    },
    $radio: {
        renderFormItemContent: oldFormItemRadioAndCheckboxRender
    },
    $checkbox: {
        renderFormItemContent: oldFormItemRadioAndCheckboxRender
    },
    $switch: {
        renderFormItemContent: oldItemRender
    }
    // 以上已废弃
});
