import React, { Component } from 'react'
import { Card, Checkbox, Descriptions, Empty, Popover, Spin, Tooltip } from 'antd'
import { AntIcon } from 'components'
import { EMPTY_ID } from 'util/global'

function generateList(data) {
    data.forEach(item => {
        if (item.children && item.children.length) {
            generateList.call(this, item.children)
        }
        this.list.push(item)
    })
}

function getVisible() {
    const checked = this.list.filter(item => item.checked)
    const caseChildren = checked.filter(item => item.visibleParent || item.type != 2)
    const visibleParents = []
    // 递归寻找父级
    const findVisibleParents = children => {
        const parents = []
        children.forEach(item => {
            if (item.parentId) {
                const parent = this.list.find(p => p.id === item.parentId)
                if (parent) {
                    parents.push(parent)
                    visibleParents.push(parent)
                }
            }
        })
        if (parents.length) {
            findVisibleParents(parents)
        }
    }

    findVisibleParents(caseChildren)

    const checkedIds = checked.map(item => item.id)
    const visibleParentsIds = visibleParents.map(item => item.id)

    const result = checkedIds
    visibleParentsIds.forEach(item => {
        if (!result.includes(item)) {
            result.push(item)
        }
    })

    return result
}

function renderDescriptions(data) {
    return data.map(item => {
        return item.children && item.children.length
            ? renderItem.call(this, item)
            : renderCheckbox.call(this, item)
    })
}

function renderItem(data) {
    return (
        <Descriptions bordered column={1} contentStyle={{ padding: 0 }}>
            <Descriptions.Item
                label={
                    <Checkbox
                        value={data.id}
                        checked={data.checked}
                        indeterminate={data.indeterminate}
                        onChange={e => this.onChange(e, data)}
                    >
                        {data.title}
                    </Checkbox>
                }
            >
                <Card bordered={false}>{renderDescriptions.call(this, data.children)}</Card>
            </Descriptions.Item>
        </Descriptions>
    )
}

function renderCheckbox(data) {
    const grid = (
        <label className="ant-card-grid ant-card-grid-hoverable">
            <Checkbox value={data.id} checked={data.checked} onChange={e => this.onChange(e, data)}>
                {data.title}
            </Checkbox>
            {data.visibleParent && data.type == 2 && (
                <Tooltip placement="bottom" title="选中此项才会显示菜单">
                    <AntIcon type="eye" style={{ color: '#1890ff' }} className="mr-xxs" />
                </Tooltip>
            )}
            <div className="text-gray">{data.permission}</div>
        </label>
    )
    return data.remark ? (
        <Popover placement="topLeft" content={data.remark}>
            {grid}
        </Popover>
    ) : (
        grid
    )
}

export default class AuthorityView extends Component {
    state = {
        loading: false,
        dataSource: [],
    }

    list = []

    constructor(props) {
        super(props)

        this.autoLoad = typeof this.props.autoLoad === 'boolean' ? this.props.autoLoad : true
        this.loadData =
            typeof this.props.loadData === 'function' ? this.props.loadData : async () => {}
    }

    /**
     * 自动加载数据
     */
    componentDidMount() {
        if (this.autoLoad) {
            this.onLoadData()
        }
    }

    onLoadData = async () => {
        this.setState({ loading: true })

        const res = await this.loadData()

        this.list = []
        generateList.call(this, res)

        if (this.props.defaultSelectedKeys) {
            this.list.map(item => {
                if (
                    this.props.defaultSelectedKeys.includes(item.id) &&
                    (!item.children || !item.children.length)
                ) {
                    this.onSelect(true, item)
                }
            })
        }

        this.setState({
            dataSource: res,
            loading: false,
        })

        this.onChange()
    }

    onReloadData = () => {
        this.onLoadData()
    }

    onChange = (e, item) => {
        if (e && item) {
            this.onSelect(e.target.checked, item)
        }

        const visible = getVisible.call(this)

        if (this.props.onSelect) {
            this.props.onSelect(
                // 返回所有选中
                this.list.filter(p => p.checked).map(p => p.id),
                // 返回所有选中和半选
                this.list.filter(p => p.checked || p.indeterminate).map(p => p.id),
                // 返回所有选中和半选,但是不返回没有子级选中visibleParent的半选
                visible
            )
        }
    }

    onSelect = (check, item) => {
        item.checked = check
        item.indeterminate = false
        if (item.children && item.children.length) {
            this.onChangeChildren(item.checked, item.children)
        }
        if (item.parentId) {
            this.onChangeParent(item.checked, item.parentId)
        }

        this.setState({
            dataSource: this.list.filter(p => p.parentId === EMPTY_ID),
        })
    }

    onChangeParent = (checked, parentId) => {
        const parent = this.list.find(p => p.id === parentId)
        if (parent) {
            const checkedCount = parent.children.filter(p => p.checked).length
            const indeterminateCount = parent.children.filter(p => p.indeterminate).length
            if (checkedCount === parent.children.length) {
                // 全选
                parent.checked = true
                parent.indeterminate = false
            } else if (!checkedCount && !indeterminateCount) {
                // 全不选
                parent.checked = false
                parent.indeterminate = false
            } else {
                // 半选
                parent.checked = false
                parent.indeterminate = true
            }
            this.onChangeParent(checked, parent.parentId)
        }
    }

    onChangeChildren = (checked, children) => {
        children.forEach(p => {
            p.checked = checked
            p.indeterminate = false
            if (p.children && p.children.length) {
                this.onChangeChildren(checked, p.children)
            }
        })
    }

    render() {
        return (
            <div className="yo-authority-view">
                <Spin spinning={this.state.loading} indicator={<AntIcon type="loading" />}>
                    {!this.state.loading ? (
                        <Descriptions bordered column={1} className="yo-authority-view--container">
                            {this.state.dataSource.map(item => {
                                return (
                                    <Descriptions.Item
                                        label={
                                            <Checkbox
                                                value={item.id}
                                                checked={item.checked}
                                                indeterminate={item.indeterminate}
                                                onChange={e => this.onChange(e, item)}
                                            >
                                                {item.title}
                                            </Checkbox>
                                        }
                                    >
                                        {renderDescriptions.call(this, item.children)}
                                    </Descriptions.Item>
                                )
                            })}
                        </Descriptions>
                    ) : (
                        <Empty className="mt-lg mb-lg" />
                    )}
                </Spin>
            </div>
        )
    }
}
