import React, { Component } from 'react'
import { Breadcrumb, Button, Col, Empty, Input, Layout, Row, Spin, Tooltip, Tree } from 'antd'
import { AntIcon, Container } from 'components'
import { SIDER_BREAK_POINT } from 'util/global'

function generateKey(data, level) {
    const n = level || [0]
    n.push(0)
    data.forEach((p, i) => {
        n[n.length - 1] = i
        p.key = n.join('-')
        p.scopedSlots = { title: 'title' }
        if (p[this.replaceFields.children]) {
            generateKey.call(this, p[this.replaceFields.children], Object.assign([], n))
        }
    })
    return data
}

function generateList(data) {
    // 这里获取不到Key
    for (let i = 0; i < data.length; i++) {
        const { key } = data[i]
        this.list.push({
            key,
            [this.replaceFields.value]: data[i][this.replaceFields.value],
            [this.replaceFields.title]: data[i][this.replaceFields.title],
        })
        if (data[i][this.replaceFields.children]) {
            generateList.call(this, data[i][this.replaceFields.children])
        }
    }
}

function getParentKey(key, tree) {
    let parentKey
    for (let i = 0; i < tree.length; i++) {
        const node = tree[i]
        if (node[this.replaceFields.children]) {
            if (node[this.replaceFields.children].some(item => item.key === key)) {
                parentKey = node.key
            } else if (getParentKey.call(this, key, node[this.replaceFields.children])) {
                parentKey = getParentKey.call(this, key, node[this.replaceFields.children])
            }
        }
    }
    return parentKey
}

function renderTitle(nodeData) {
    const title = nodeData[this.replaceFields.title]
    if (this.state.searchValue && title.indexOf(this.state.searchValue) > -1) {
        return (
            <>
                {title.substr(0, title.indexOf(this.state.searchValue))}
                <span style={{ color: '#f50' }}>{this.state.searchValue}</span>
                {title.substr(
                    title.indexOf(this.state.searchValue) + this.state.searchValue.length
                )}
            </>
        )
    }
    return <>{title}</>
}

function renderBreadcrumbItem() {
    const path = ['顶级']

    const findPath = (data, level) => {
        level = level || 1
        for (let i = 0; i < data.length; i++) {
            const item = data[i]

            path[level] = item[this.replaceFields.title]

            if (item[this.replaceFields.value] === this.state.selectedKey) {
                path.length = level + 1
                return true
            }

            if (item[this.replaceFields.children] && item[this.replaceFields.children].length) {
                const found = findPath(item[this.replaceFields.children], level + 1)
                if (found) {
                    return true
                }
            }
        }
    }

    if (this.state.selectedKey) {
        findPath(this.state.dataSource)
    }

    return path.map((p, i) => <Breadcrumb.Item key={i}>{p}</Breadcrumb.Item>)
}

export default class QueryTreeLayout extends Component {
    state = {
        loading: false,
        dataSource: [],
        expandedKeys: [],
        selectedKey: '',
        autoExpandParent: true,
        searchValue: '',

        collapsed: false,
        showSider: false,
    }

    list = []

    defaultExpandedKeys = []

    replaceFields = {
        value: 'id',
        title: 'title',
        children: 'children',
    }

    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 () => {}

        this.defaultExpanded =
            typeof this.props.defaultExpanded === 'boolean' ? this.props.defaultExpanded : false

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

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

        window.addEventListener('resize', this.onResizeLayout)
        this.onResizeLayout()
    }

    componentWillUnmount() {
        window.removeEventListener('resize', this.onResizeLayout)
    }

    /**
     * 加载数据
     * 调用外部传入的loadData函数,可在loadData中自行改变参数
     */
    onLoadData = async () => {
        this.onLoading()

        const res = await this.props.loadData()
        const data = generateKey.call(this, res)
        this.list = []
        generateList.call(this, data)

        let expandedKeys = []
        if (this.defaultExpanded) {
            expandedKeys = this.list.map(p => p.key)
        }
        this.setState({
            dataSource: data,
            expandedKeys,
        })
        this.onLoaded()
    }

    /**
     * 数据开始加载
     */
    onLoading = () => {
        this.setState({
            loading: {
                indicator: <AntIcon type="loading" />,
            },
        })
    }

    /**
     * 数据加载完成
     */
    onLoaded = () => {
        this.setState({ loading: false })
    }

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

    onExpand = expandedKeys => {
        this.setState({
            expandedKeys,
            autoExpandParent: false,
        })
    }

    onSelect = selectedKeys => {
        const selectedIds = []
        selectedKeys.forEach(p => {
            const data = this.list.find(m => m.key === p)
            selectedIds.push(data[this.replaceFields.value])
        })
        this.setState({
            selectedKey: selectedIds[0],
        })
        if (this.props.onSelect) {
            this.props.onSelect(selectedIds[0])
        }
    }

    onSearch = value => {
        const expandedKeys = this.list
            .map(p => {
                if (p[this.replaceFields.title].indexOf(value) > -1) {
                    return getParentKey.call(this, p.key, this.state.dataSource)
                }
                return null
            })
            .filter((p, i, self) => p && self.indexOf(p) === i)

        this.setState({
            expandedKeys,
            autoExpandParent: !!value,
            searchValue: value,
        })
    }

    onResizeLayout = () => {
        this.setState({
            collapsed: window.innerWidth <= SIDER_BREAK_POINT,
        })
    }

    render() {
        const { loading, dataSource, expandedKeys, autoExpandParent, collapsed, showSider } =
            this.state

        const props = {
            treeData: dataSource,
            expandedKeys,
            autoExpandParent,
        }

        const on = {
            onExpand: expandedKeys => this.onExpand(expandedKeys),
            onSelect: selectedKeys => this.onSelect(selectedKeys),
        }

        return (
            <Layout className="yo-tree-layout">
                <Layout.Sider
                    width="240px"
                    className={[
                        collapsed ? 'yo-tree-layout--collapsed' : '',
                        showSider ? 'open' : '',
                    ]
                        .filter(p => p)
                        .join(' ')}
                    onMouseLeave={() => this.setState({ showSider: false })}
                >
                    <Layout.Header>
                        <div className="header-actions">
                            <Input.Search
                                allowClear={true}
                                placeholder="请输入检索关键字"
                                onSearch={value => this.onSearch(value)}
                            />
                        </div>
                    </Layout.Header>
                    <div className="yo-tree-layout--bar">
                        <Tooltip placement="bottom" title="刷新">
                            <AntIcon type="undo" onClick={() => this.onReloadData()} />
                        </Tooltip>
                        <Tooltip placement="bottom" title="折叠全部">
                            <AntIcon
                                type="switcher"
                                onClick={() => this.setState({ expandedKeys: [] })}
                            />
                        </Tooltip>
                    </div>
                    <div className="yo-tree-layout--content">
                        <Spin
                            spinning={loading}
                            indicator={<AntIcon type="loading" />}
                            wrapperClassName="h-100-p"
                        >
                            {!loading && !dataSource.length ? (
                                <Empty
                                    image={
                                        <div className="text-center pt-md">
                                            <AntIcon className="h3 mt-xl mb-md" type="smile" />
                                            <p>暂无数据</p>
                                        </div>
                                    }
                                    description={false}
                                />
                            ) : (
                                <Tree
                                    {...props}
                                    {...on}
                                    titleRender={nodeData => renderTitle.call(this, nodeData)}
                                />
                            )}
                        </Spin>
                    </div>
                </Layout.Sider>
                <Layout.Content>
                    <Container mode="fluid">
                        <Row gutter={16} align="middle">
                            {collapsed && (
                                <Col>
                                    <Button
                                        type="text"
                                        icon={<AntIcon type="menu" />}
                                        onClick={() => this.setState({ showSider: true })}
                                    />
                                </Col>
                            )}
                            <Col flex="1">
                                <Breadcrumb className="mt-md mb-md">
                                    {renderBreadcrumbItem.call(this)}
                                </Breadcrumb>
                            </Col>
                        </Row>
                    </Container>
                    {this.props.children}
                </Layout.Content>
            </Layout>
        )
    }
}
