import * as React from 'react';
import {BasicContainer, BasicContainerPropsInterface} from '../../render/core/Container/types';
import componentLoader from '../../render/util/componentLoader';
import {createChild} from '../../render/util/createChild';
import {Form} from '@native-ads/antd';
import {FormConfig} from '../../render/core/Form/Form';
import {SET_FORM_ITEM_PAYLOAD} from '../../render/core/Form/actions';

export class FormPropsInterface extends BasicContainerPropsInterface {
    info: FormConfig;

    /**
     * 当前表单的数据模型
     */
    $form: {
        /**
         * 表单布局
         */
        layout?: 'horizontal' | 'vertical' | 'inline';

        /**
         * 表单下的表单项
         */
        control: {
            [s: string]: SET_FORM_ITEM_PAYLOAD
        };

        /**
         * 提交之后清除表单数据
         */
        clearAfterSubmit?: boolean;

        /**
         * 当某一规则校验不通过时，是否停止剩下的规则的校验
         */
        validateFirst?: boolean;
    };

    /**
     * 更新表单元素的属性
     */
    $setFormItem: (payload: Partial<SET_FORM_ITEM_PAYLOAD>) => void;

    /**
     * 批量更新表单元素属性
     */
    $setFormItems: (payload: Partial<SET_FORM_ITEM_PAYLOAD>[]) => void;
}

export class AbstractForm extends BasicContainer<FormPropsInterface, {}> {
    constructor(props: FormPropsInterface) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    render() {
        let info = this.getPropsInfo(this.props.info, this.props, ['children']);

        if (!this.isUnderContainerEnv()) {
            return <div>form component should be under container component</div>;
        }

        let children = info.children;

        if (!(children instanceof Array)) {
            return <div>children props should be array</div>;
        }

        let childElement = children.map((child, index) => {
            return createChild(child, {
                ...this.props,
                info: child,
                key: `form_element_${index}`,
                $formSubmit: this.handleSubmit
            });
        });

        return (
            <Form
                layout={info.layout}
                className={this.props.info.className}
                style={this.props.info.style}
                onSubmit={this.handleSubmit}
            >
                {childElement}
            </Form>
        );
    }

    public handleSubmit(event: React.FormEvent<HTMLFormElement>) {
        event.preventDefault();
        event.stopPropagation();

        let $form = this.props.$form;
        let info = this.getPropsInfo(this.props.info);
        let control = $form.control;

        let invalidItems: Partial<SET_FORM_ITEM_PAYLOAD>[] = [];
        let submitData = {};

        for (let itemName in control) {
            if (control.hasOwnProperty(itemName)) {
                let item: SET_FORM_ITEM_PAYLOAD = control[itemName];
                let valid = item.valid;

                let data = this.getValueFromDataStore(itemName);
                submitData[itemName] = data;

                // 设置validateFirst只验证第一个表单控件
                if (!valid) {
                    if (info.validateFirst) {
                        this.props.$setFormItem({
                            formItemName: itemName,
                            $validate: true
                        });
                        this.forceUpdate();
                        return;
                    }

                    invalidItems.push({
                        formName: info.name,
                        formItemName: itemName,
                        $validate: true
                    });
                }
            }
        }

        if (invalidItems.length > 0) {
            this.props.$setFormItems(invalidItems);
            this.forceUpdate();
            return;
        }

        if (this.props.info.clearAfterSubmit && this.props.$setMultiData) {
            let items = Object.keys(submitData).map(key => ({
                name: key,
                value: ''
            }));

            this.props.$setMultiData(items);
        }

        this.commonEventHandler('onSubmit', submitData);
    }
}

componentLoader.addComponent('form', AbstractForm, FormPropsInterface);
