import React, { Component } from 'react'
import { Button, Drawer, message as Message, Modal } from 'antd'
import { cloneDeep, isEqual } from 'lodash'

/**
 * 渲染对话框
 * @param {*} props
 * @param {*} on
 * @param {*} childWithProps
 * @returns
 */
function renderModal(props, on, childWithProps) {
    on = {
        ...on,
        onCancel: () => this.onClose(),
    }

    const { buttons } = this.props

    const _buttons = [
        <Button key="0" onClick={() => on.onCancel()}>
            取消
        </Button>,
        <Button key="1" loading={props.confirmLoading} onClick={() => on.onOk()} type="primary">
            确认
        </Button>,
    ]

    if (Array.isArray(buttons)) {
        for (const { index, button } of buttons) {
            _buttons.splice(index, 0, button(this.getData, this.close))
        }
    }

    return (
        <Modal
            className="yo-modal-form"
            {...props}
            {...on}
            footer={props.footer === false ? false : _buttons}
        >
            {childWithProps}
        </Modal>
    )
}

/**
 * 渲染抽屉
 * @param {*} props
 * @param {*} on
 * @param {*} childWithProps
 * @returns
 */
function renderDrawer(props, on, childWithProps) {
    on = {
        ...on,
        onClose: () => this.onClose(),
    }

    // react在这里会对该组件不存在的props抛出异常
    ;['action', 'onSuccess', 'onOk', 'confirmLoading'].forEach(p => {
        delete props[p]
    })

    return (
        <Drawer className="yo-drawer-form" {...props} onClose={() => on.onClose()}>
            <div className="yo-drawer-form--body">{childWithProps}</div>
            <div className="ant-drawer-footer">
                <Button onClick={on.onClose}>取消</Button>
                <Button loading={this.state.confirmLoading} onClick={on.onOk} type="primary">
                    确定
                </Button>
            </div>
        </Drawer>
    )
}

export default class ModalForm extends Component {
    state = {
        // 弹窗显示/隐藏
        visible: false,
        // 提交状态
        confirmLoading: false,
    }

    // 子元素实例
    childNode = React.createRef()

    // 弹窗类型
    type = 'modal'

    // 从外部传入的数据
    data = null
    // 数据结构调整后的快照
    snapshot = null

    // 完成操作
    action = async () => {}

    // 是否在关闭时校验数据改变
    compareOnClose = true

    constructor(props) {
        super(props)

        if (this.props.type) {
            if (!['modal', 'drawer'].includes(this.props.type))
                throw new Error('props [type] error')
            this.type = this.props.type
        }

        if (this.props.action) {
            this.action = this.props.action
        }

        if (typeof this.props.compareOnClose === 'boolean') {
            this.compareOnClose = this.props.compareOnClose
        }
    }

    /**
     * 打开弹窗
     * @param {*} data
     */
    open = (data = {}) => {
        this.data = data
        this.setState({ visible: true })
    }

    /**
     * 关闭弹窗
     */
    close = () => {
        this.setState({ visible: false })
    }

    getData = async () => {
        const body = this.childNode.current
        if (!body || !body.getData) throw Error('为获取到子表单')

        return await body.getData()
    }

    /**
     * 子元素创建后回调
     * 对子元素数据进行填充,(如需关闭时对比)之后再获取结构调整后的数据快照
     * @returns
     */
    onCreated = async () => {
        const body = this.childNode.current
        if (!body || !body.fillData) return

        await body.fillData(this.data)
        // 保存此时的form内容为快照
        if (this.compareOnClose && body.form && body.form.current) {
            this.snapshot = cloneDeep(body.form.current.getFieldsValue())
        }
    }

    /**
     * 取消编辑
     * (如需关闭时对比)获取当前数据结构与快照对比
     * @returns
     */
    onClose = async () => {
        const body = this.childNode.current
        if (!body) {
            this.close()
            return
        }

        if (this.compareOnClose && body.form && body.form.current) {
            const formData = body.form.current.getFieldsValue()
            if (!isEqual(this.snapshot, formData)) {
                Modal.confirm({
                    title: '是否确认关闭',
                    content: '当前内容已更改，是否确认不保存并且关闭',
                    onOk: () => {
                        this.close()
                    },
                })
                return
            }
        }

        this.close()
    }

    /**
     * 完成编辑
     * 校验并获取结构调整后的数据,调用this.action进行操作
     * @returns
     */
    onOk = async () => {
        const body = this.childNode.current
        if (!body || !this.action || !body.getData) return

        this.setState({ confirmLoading: true })
        try {
            const postData = await body.getData()

            const result = await this.action(postData)
            if (!result || result.success) {
                if (result && result.success) {
                    Message.success(this.props.successMessage || '保存成功')
                }
                this.close()
                if (typeof this.props.onSuccess === 'function') {
                    this.props.onSuccess(postData)
                }
            }
        } finally {
            this.setState({ confirmLoading: false })
        }
    }

    render() {
        const props = {
            ...this.props,
            visible: this.state.visible,
            destroyOnClose: true,

            confirmLoading: this.state.confirmLoading,
        }

        const on = {
            onOk: () => this.onOk(),
        }

        const childWithProps = React.cloneElement(React.Children.only(this.props.children), {
            created: childNode => {
                this.childNode.current = childNode
                this.onCreated()
            },
        })

        return this.type === 'modal'
            ? renderModal.call(this, props, on, childWithProps)
            : renderDrawer.call(this, props, on, childWithProps)
    }
}
