import React, { Component } from 'react';
import { is, List, Map } from 'immutable';
import classname from 'classnames'
import * as Tools from 'jad-tool'
import { Checkbox, Icon, Row, Col, AutoComplete, Input, Empty } from 'antd'

import { PageComponent } from '../../../types/index';
import { throttle } from 'jad-tool'
import { Cascader, initOptionsType, cascaderOptionsItemType } from '../util'

const { Option: AutoOption } = AutoComplete;
const { Search } = Input;

export type quickOptionsType = {
    name: string,
    options: cascaderOptionsItemType[],
    index?: number,
}

const ROOT_SHOW_OPTIONS = 0

export class CascaderTree extends Component<PageComponent<{
    options?: initOptionsType[], // 二维数组，flat，尤其是当需要search的时候要用
    onCreateInitOptions?: () => cascaderOptionsItemType[]
    propValue?: string
    propName?: string
    quickOptions?: quickOptionsType[]
    onCreateQuickOptions?: (options: cascaderOptionsItemType[]) => quickOptionsType[],
    value?: string[],
    disabled?: boolean,
    onChange?: (value: string[]) => void,
    showSearch?: boolean,
    searchProps?: { [propName: string]: any },
    showSearchFormat?: 'ALL' | 'SELF', // 默认 ALL —— 放在  search 面板 里面或者展示里面，去 state.selectedMap 中的propName
    [propName: string]: any
}>> {


    cascader = null
    selectWrapRef = null;
    state = {
        selectMap: [],
        showOptions: [],
        showMap: {},
        quickOptions: null,
        flatOptions: [],
        searchFlatOption: [],
        searchValue: undefined
    }

    componentDidMount() {
        this.init()
    }
    UNSAFE_componentWillReceiveProps(nextProps) {
        if (this.props.options && !this.props.options.length && nextProps.options.length) {
            setTimeout(() => this.init())
        }
        if (!this.props.value && nextProps.value) {
            setTimeout(() => this.resetSelect())
        }
    }
    shouldComponentUpdate(nextProps, nextState) {
        const { options, quickOptions, value } = nextProps;
        if ((is(Map(nextProps), Map(this.props)) &&
            is(Map(nextState), Map(this.state)))) {
            return false
        }
        return true
    }
    init() {
        const { options = [], onCreateInitOptions } = this.props
        this.cascader = new Cascader({
            initOptions: options,
            onCreateInitOptions
        })
        this.createQuickOptions()
        this.initShowOptions()
    }
    initShowOptions() {
        var showOptions = []
        showOptions.push(this.cascader.getCollectData())
        this.setState({
            showOptions,
            flatOptions: this.cascader.flatOptions,
        })
    }
    resetSelect() {
        const { value } = this.props
        var { showOptions = [] } = this.state
        const selectMap = this.cascader.resetOptions(value)
        showOptions[0] = this.cascader.getCollectData()
        this.setState({
            selectMap,
            showOptions,
            flatOptions: this.cascader.flatOptions,
        }, () => {
            this.resetQuickStatus()
        })
    }
    createQuickOptions() {
        var { quickOptions, onCreateQuickOptions } = this.props
        if (!quickOptions && !onCreateQuickOptions) return;
        quickOptions = quickOptions ? quickOptions : onCreateQuickOptions(this.cascader.getFlatCollectData())
        quickOptions = quickOptions.sort((a, b) => {
            const preIndex = a.index ? a.index : 0;
            const currentIndex = b.index ? b.index : 0
            return preIndex > currentIndex ? 1 : 0
        })
        this.setState({
            quickOptions
        })
    }
    resetQuickStatus() {
        let { propValue = 'value' } = this.props
        let { quickOptions, selectMap } = this.state
        if (!quickOptions || Tools.isEmptyArray(quickOptions)) {
            return null;
        }
        var selectMapBuff = this.cascader.coolect(selectMap)
        quickOptions = quickOptions.map(item => {
            let checked = item.options.every(e => selectMapBuff.some(i => i[propValue] === e[propValue]))
            let indeterminate = checked ? false : (
                item.options.some(e => selectMapBuff.some(i => i[propValue] === e[propValue])) ? true : false
            );
            return {
                ...item,
                checked,
                indeterminate,
            }
        })
        this.setState({
            quickOptions
        })
    }

    onEmitChange() {
        const { selectMap } = this.state
        const { onChange, propValue = 'value' } = this.props;
        onChange(selectMap.map(e => e[propValue]))
    }
    onSelect(checked, record) {
        const selectMap = this.cascader.activeSelect(checked, record)
         //显示选中的子集
         const newShowMap = {};
         const newShowOptions = [];
         const _this= this;
         //从根节点更新数据
         newShowOptions[ROOT_SHOW_OPTIONS] = this.cascader.getCollectData()
         // 有可能是查询 search到非当前展示list的内容
         function walkParent(r) {
             newShowMap[r['level']] = r;
             if (r && r['children'] && r['children'].length) {
                 newShowOptions[r.level+1] = _this.cascader.getCollectData(r)
             }
             if (r && r['parent']) {
                 walkParent(r['parent'])
             }
         }
         walkParent(record)

        this.setState({
            showMap: newShowMap,
            showOptions: newShowOptions,
            selectMap,
            flatOptions: this.cascader.flatOptions,
        }, () => {
            this.resetQuickStatus()
            this.onEmitChange()
        })
    }
    onQuickSelect(checked, record, index) {
        let { quickOptions, showOptions } = this.state
        var selectMap = []
        record.indeterminate = false;
        record.checked = checked
        record.options.map((item) => {
            selectMap = this.cascader.activeSelect(checked, item)
        })
        quickOptions[index] = record
        //从根节点更新数据
        showOptions[ROOT_SHOW_OPTIONS] = this.cascader.getCollectData()
        this.setState({
            selectMap,
            showOptions,
            quickOptions,
            flatOptions: this.cascader.flatOptions,
        }, () => {
            this.onEmitChange()
        })
    }
    onAddShowOptions(item, index, options) {
        var { showOptions, showMap } = this.state
        const newShowOptions = [...showOptions];
        const newShowMap = {...showMap};
        if (!newShowOptions[index]) {
            newShowOptions.splice(index, 0, options)
        } else {
            newShowOptions.splice(index, newShowOptions.length, options)
        }
        newShowMap[item.level] = item
        this.setState({
            showOptions: newShowOptions,
            showMap: newShowMap
        })
    }
    onClear(record) {
        this.onSelect(false, record)
    }
    onClearAll() {
        var { selectMap } = this.state
        selectMap.forEach(item => {
            selectMap = this.cascader.activeSelect(false, item)
        })
        this.initShowOptions()
        this.setState({
            selectMap,
        }, () => {
            this.resetQuickStatus()
            this.onEmitChange()
        })
    }

    /*
        快捷选择的数据结构只有二级，直接children对应数据最下层children
    */
    renderQuickSelect() {
        let { quickOptions } = this.state;
        const { disabled = false } = this.props
        if (!quickOptions || Tools.isEmptyArray(quickOptions)) {
            return null;
        }
        return (
            <div className='jad-cascaderTree-quick-select-wrap'>
                <span>快捷选择: </span>
                <span className='jad-cascaderTree-quick-selections'>
                    {
                        quickOptions.map((item, index) => (
                            <Checkbox
                                onClick={e => this.onQuickSelect(!item.checked, item, index)}
                                checked={item.checked}
                                key={item.name}
                                disabled={disabled}
                                indeterminate={item.indeterminate}
                            >{item.name}</Checkbox>
                        ))
                    }
                </span>
            </div>
        )
    }
    renderSelectList = () => {
        const { selectMap } = this.state
        const { propName = "name", disabled = false } = this.props
        var selectList = selectMap
        if (!selectList || !selectList.length) return null;
        return (
            <div
                className='jad-cascaderTree-select-wrap'
                ref={(ref) => this.selectWrapRef = ref}
            >
                <div className='jad-cascaderTree-selections'>已选择:</div>
                <div className="container">
                    {
                        selectMap.map(e => {
                            return <span key={e[propName]} className='item' >
                                {e[propName]}
                                {!disabled ? <Icon type="close" onClick={() => this.onClear(e)} /> : <i> </i>}
                            </span>
                        })
                    }
                    <a className={disabled ? 'disabled' : ''} onClick={() => this.onClearAll()}>清空</a>
                </div>
            </div>
        )
    }
    onSearchSelect = (val, option) => {
        if(val === 'no-data') return
        if (option && option.props && option.props.record)
            this.onSelect(true, option.props.record || {})
    }
    @throttle(300)
    onSearch(val) {
        const { propName = "name" } = this.props;
        const { flatOptions } = this.state;
        const searchFlatOption = val ? flatOptions.filter(item => item[propName].includes(val)) : []; // 内容清空时表示不查询
        this.setState({ searchFlatOption, searchValue: val });
    }
    renderSearchDataSource = () => {
        const { searchFlatOption, searchValue } = this.state;
        const { propValue = 'value', propName = "name", showSearchFormat } = this.props;
        if (Tools.isEmptyArray(searchFlatOption)) return [<AutoOption key='no-data'><Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /></AutoOption>]
        if (showSearchFormat === 'ALL') {
            const Node = (searchFlatOption.map(item => {
                const selected = !!item['checked'];
                return <AutoOption key={item[propValue]} {...{ [propName]: item[propName], record: item }} disabled={selected} className={classname('jad-cascaderTree-search-drop-item', selected ? 'selected' : '')}>
                    <span>
                        {item['fullName'].map((f, index) => {
                            return (<span key={f} className={'text-ellipsis'}>
                                {index ? ` / ` : null}
                                {!selected ? f.split(searchValue).map((e, i) => {
                                    return <span key={e + i}>
                                        {i ? <span className='search-drop-matched '>{searchValue}</span> : null}
                                        {e}
                                    </span>
                                }) : f}
                            </span>)
                        })}
                    </span>
                    <Icon type="check" className={'icon-right'} />
                </AutoOption>
            }))
            return Node
        } else {
            const Node = (searchFlatOption.map(item => {
                const selected = !!item['checked'];
                return <AutoOption key={item[propValue]} {...{ [propName]: item[propName], record: item }} disabled={selected} className={classname('jad-cascaderTree-search-drop-item', selected ? 'selected' : '')}>
                    <span>
                        {!selected ? item[propName].split(searchValue).map((e, i) => {
                            return <span key={e + i}>
                                {i ? <span className='search-drop-matched '>{searchValue}</span> : null}
                                {e}
                            </span>
                        }) : item[propName]}
                    </span>
                    <Icon type="check" className={'icon-right'} />
                </AutoOption>
            }))
            return Node
        }
    }
    renderSearch = () => {
        const { searchProps = {}, propValue = 'value', propName = "name", className } = this.props;

        return <AutoComplete
            dataSource={this.renderSearchDataSource()}
            style={{ width: '100%', marginBottom: '8px' }}
            onSelect={this.onSearchSelect}
            onSearch={this.onSearch.bind(this)}
            placeholder="请输入"
            optionLabelProp={propName}
            defaultActiveFirstOption={false}
            {...searchProps}
        >
            <Search enterButton />
        </AutoComplete>
    }
    renderContext = () => {
        const { showOptions } = this.state;
        return <div className='jad-cascaderTree-wrap'>
            <div className='jad-cascaderTree-cascader-select-warp'>
                <Row gutter={24} style={{ margin: '0px' }}>
                    {
                        showOptions.map((item, index) => {
                            return <Col span={Math.round(24 / showOptions.length)} key={index} style={{ padding: '0px' }}>
                                {this.renderItem(item)}
                            </Col>
                        })
                    }
                </Row>
            </div>
        </div>
    }
    renderItem = (options) => {
        const { propValue = 'value', propName = "name", disabled = false } = this.props
        const { showMap } = this.state;
        
        return (
            <ul className='jad-cascaderTree-container'>
                {
                    options.map(item => {
                        const active = !!(showMap[item.level] && showMap[item.level][propValue] === item[propValue])
                        return <li key={item[propValue]} className={active ? 'active' : ''} >
                            <Checkbox
                                disabled={disabled}
                                checked={item.checked}
                                indeterminate={item.indeterminate}
                                onClick={e => { this.onSelect(!item.checked, item) }}
                            ><span>{item[propName]}</span></Checkbox>
                            {
                                !Tools.isEmptyArray(item.children) ?
                                    <span className='icon-right-box' onClick={() => this.onAddShowOptions(item, item.level + 1, item.children)}>
                                        <Icon className='icon-right' type="right" />
                                    </span>
                                    : null
                            }
                        </li>
                    })
                }
            </ul>
        )
    }
    render() {
        const { showSearch, value } = this.props;
        return (
            <div className='jad-cascaderTree-wrap'>
                {this.renderSelectList()}
                {this.renderQuickSelect()}
                {showSearch && this.renderSearch()}
                <div className='jad-cascaderTree-cascader-cascader-warp'>
                    {this.renderContext()}
                </div>
            </div>
        )
    }
}
