import React from 'react';
import * as Tools from 'jad-tool';

type OptionType = {
    value: string | number,
    name?: string,
    fullName?: (string)[],
    leaf: number, // 从 0 开始
    parent?: OptionType,
    children?: OptionType[],
    checked: boolean,
    indeterminate: boolean,
};
type PropsKeyValue = {
    propPValue: string,
    propValue: string,
    propName: string,
}
export function initOptions(initValue: (string | number)[], initOptions: OptionType[]) {
    if (!initOptions) return console.warn(`MultiCascaderPanel initOptions has some problems`)
    const { propValue, propName } = this.keyValue;
    const { optionsFlat } = this.state;
    const { selectedMap, options } = getSelectedMapOptions.bind(this)(initValue, initOptions, propValue);
    const newValues = selectedMap.map(item => item[propValue]);
    const newOptionsFlat = options ? transform2FlatData(options, propName) : optionsFlat;

    return { selectedMap, options, optionsFlat: newOptionsFlat, selectedValue: newValues }
}

// 无论 showCheckedStrategy 策略是什么，都只展示 initValue 中的选项，因为一般 selectedMap，其实对应的也是接口接受的入参 需要传的
// 获取初始的 selectedMap、options walk
export function getSelectedMapOptions(value: (string | number)[], options: OptionType[]) {
    if (!options || !options.length) {
        console.warn(`MultiCascaderPanel getSelectedMapOptions options has some problems`)
        return { options: [], selectedMap: [] };
    }
    if (!value || !value.length) {
        return { options: options, selectedMap: [] };;
    }
    const { showCheckedStrategy } = this.props; // 定制回填方式
    const { propValue } = this.keyValue; // 定制回填方式
    let newOptions = options; // clone 一份
    let newSelectedMap = [];
    function walk(walkValue, walkOptions: OptionType[]) {
        return walkOptions.map((item: OptionType, index) => {
            if (Tools.isExist(item[propValue]) && walkValue.includes(item[propValue])) { //TODO
                onCheckHigh2Low(true, item);
                onCheckLow2High(true, item);
                // 如果是 所有选中的节点都展示，那么 该层及其子层们都要查一遍
                if (showCheckedStrategy === 'SHOW_ALL' && item['children'] && item['children'].length) {
                    const newChildren = walk(walkValue, item['children']);
                    const newItem = item;
                    newItem['children'] = newChildren;
                    newSelectedMap[newSelectedMap.length] = newItem;
                    return newItem;
                } else {
                    newSelectedMap[newSelectedMap.length] = item;
                    return item;
                };
            } else if (Tools.isExist(item[propValue]) && !walkValue.includes(item[propValue]) && item['children'] && item['children'].length) {
                const newChildren = walk(walkValue, item['children']);
                let newChildrenCheeckedLength = 0;
                let newChildrenIndeterminateLength = 0;
                newChildren.forEach(child => {
                    if(child['checked']) ++newChildrenCheeckedLength;
                    if(child['indeterminate']) ++newChildrenIndeterminateLength;
                });
                const newItem = item;
                newItem['checked'] = newChildrenCheeckedLength && newChildrenCheeckedLength === newChildren.length ? true : false  ;
                newItem['indeterminate'] = newChildrenCheeckedLength && newChildrenCheeckedLength < newChildren.length || newChildrenIndeterminateLength ? true : false;
                newItem['children'] = newChildren;
                return newItem;
            } else if (Tools.isExist(item[propValue]) && !walkValue.includes(item[propValue])) {
                return item
            } else console.log(`MultiCascaderPanel selectedMapOptions walk walkOptions item(${index}) has some problems`)
        })
    }
    newOptions = walk(value, newOptions);
    if (value.length !== newSelectedMap.length) console.warn(`MultiCascaderPanel selectedMapOptions walk value.length !== newSelectedMap.length`)
    return { options: newOptions, selectedMap: newSelectedMap };
}
// 从低到高
export function onCheckLow2High(checked: boolean, record: OptionType) {
    record['checked'] = checked;
    if (!record['parent']) {
        return
    } else {
        let parentChildren = record['parent']['children'];
        let flag = false;
        if (parentChildren.every(item => item.checked)) {
            flag = true;
        }
        if (!flag && parentChildren.some(item => item.checked || item.indeterminate)) {
            record['parent']['indeterminate'] = true;
        } else {
            record['parent']['indeterminate'] = false;
        }
        record['parent']['checked'] = flag;
        onCheckLow2High(flag, record['parent'])
    };
}
// 从高到低
export function onCheckHigh2Low(checked: boolean, record: OptionType) {
    record['checked'] = checked;
    record['indeterminate'] = false; // 从高到低，indeterminate其实可直接设置为 checked 的值，不需要遍历children 的 checked
    if (record['children'] && record['children'].length) {
        record['children'].forEach(child => {
            onCheckHigh2Low(checked, child)
        })
    }
}

// 给 record 新增属性 fullName 代表完整层级 的 name
export function getFullName(record: OptionType, propName: string) {
    return record['fullName'] ? record['fullName'] : (record['parent'] ? [...record['parent']['fullName'], record[propName]] : [record[propName]]);
}

export function transform2FlatData(treeData: OptionType[], propName?) {
    if (!treeData.length) return [];
    let platData = [];
    const tree2Flat = (data) => data.map(e => {
        platData[platData.length] = e;
        if (!e['fullName'] && propName) {
            e['fullName'] = getFullName(e, propName)
        }
        if (e['children'] && e['children'].length) {
            tree2Flat(e['children'])
        }
    });
    tree2Flat(treeData).filter(e => e);
    return platData
};

export const transform2TreeData = (platData, keyValue: PropsKeyValue) => {
    const { propPValue, propValue, propName } = keyValue;
    if (!platData.length) return [];
    const plat2Tree = (parentData: OptionType[], excptParentData: OptionType[], leaf: number, parent?: OptionType) => {
        return parentData.map(e => {
            const hasChildrenData = excptParentData.filter(d => d[propPValue] == e[propValue]);
            e['leaf'] = leaf;
            e['checked'] = false;
            e['indeterminate'] = false;
            if (e && parent)
                e['parent'] = parent;
            if (e && !e['fullName']) {
                e['fullName'] = getFullName(e, propName)
            }
            if (hasChildrenData && hasChildrenData.length)
                e['children'] = plat2Tree(hasChildrenData, excptParentData, leaf + 1, e);
            return e;
        }).filter(e => e);
    }
    return plat2Tree(platData.filter(e => e[propPValue] == 0), platData.filter(e => e[propPValue] != 0), 0);
};