import React, {CSSProperties} from 'react';
import {
    BasicConfig, BasicContainer, BasicContainerPropsInterface
} from '../../render/core/Container/types';
import {TreeSelect} from '@native-ads/antd';
import {isExpression, parseExpressionString} from '../../render/util/vm';
import componentLoader from '../../render/util/componentLoader';
import {TreeNodeConfig} from '../Tree/Tree';
import * as _ from 'lodash';

const TreeNode = TreeSelect.TreeNode;

export class TreeSelectConfig extends BasicConfig {
    /**
     * 同步的数据模型Key
     */
    name: string;

    /**
     * 子节点配置
     */
    options: TreeNodeConfig[];

    /**
     * 显示清除按钮
     */
    allowClear?: boolean;

    /**
     * 默认值
     */
    defaultValue?: string | string[];

    /**
     * 是否禁用
     */
    disabled?: boolean;

    /**
     * 下拉菜单和选择器同宽
     */
    dropdownMatchSelectWidth?: boolean;

    /**
     * 下拉菜单的样式
     */
    dropdownStyle?: CSSProperties;

    /**
     * 输入项过滤
     */
    filterTreeNode?: boolean | string;

    /**
     * 是否把每个选项的 label 包装到 value 中
     */
    labelInValue?: boolean;

    /**
     * checkable 状态下节点选择完全受控（父子节点选中状态不再关联），会使得 labelInValue 强制为 true
     */
    treeCheckStrictly?: boolean;

    /**
     * 是否多选
     */
    multiple?: boolean;

    /**
     * 选择框默认文字
     */
    placeholder?: string;

    /**
     * 搜索框默认文字
     */
    searchPlaceholder?: string;

    /**
     * 定义选中项回填的方式
     *
     * SHOW_ALL: 显示所有选中节点(包括父节点)
     * SHOW_PARENT: 只显示父节点(当父节点下所有子节点都选中时).
     * SHOW_CHILD: 只显示子节点. (默认)
     */
    showCheckedStrategy?: 'SHOW_ALL' | 'SHOW_PARENT' | 'SHOW_CHILD';

    /**
     * 是否显示搜索框
     */
    showSearch?: boolean;

    /**
     * 选择框大小
     */
    size?: 'default' | 'large' | 'small';

    /**
     * checkbox多选
     */
    treeCheckable?: boolean;

    /**
     * 默认展开所有的节点
     */
    treeDefaultExpandAll?: boolean;

    /**
     * 默认展开的节点
     */
    treeDefaultExpandedKeys?: string[];
}

export class TreeSelectPropsInterface extends BasicContainerPropsInterface {
    info: TreeSelectConfig;
}

export class AbstractTreeSelect extends BasicContainer<TreeSelectPropsInterface, {}> {
    constructor(props: TreeSelectPropsInterface) {
        super(props);
    }

    componentDidMount() {
        let info = this.getPropsInfo(this.props.info);

        if (info.defaultValue && this.props.$setData && info.name) {
            this.props.$setData(info.name, info.defaultValue);
        }

        this.handleTreeChange = this.handleTreeChange.bind(this);
        this.parseFilterTreeNode = this.parseFilterTreeNode.bind(this);
    }

    private handleTreeChange(value: any) {
        let info = this.getPropsInfo(this.props.info);
        if (this.props.$setData) {
            this.props.$setData(info.name, value);
        }
        this.commonEventHandler('onChange', {
            value: value
        });
    }

    private parseFilterTreeNode(inputValue: string, treeNode: any) {
        let info = this.props.info;
        let runTime = this.getRuntimeContext();

        if (typeof info.filterTreeNode === 'boolean') {
            return info.filterTreeNode;
        }

        if (typeof info.filterTreeNode === 'string' && isExpression(info.filterTreeNode)) {
            return parseExpressionString(info.filterTreeNode, {
                ...runTime,
                $args: {
                    inputValue,
                    treeNode
                }
            });
        }

        return true;
    }

    private renderTreeNode(options: TreeNodeConfig[]): React.ReactNode[] {
        return options.map((op, index) => {
            let title = op.title;
            let key = op.key || index;
            let isLeaf = op.isLeaf;
            let disabled = op.disabled;
            let disabledCheckbox = op.disableCheckbox;
            let selectable = typeof op.selectable === 'boolean' ? op.selectable : true;
            let children;

            if (_.isArray(op.children) && op.children.length > 0) {
                children = this.renderTreeNode(op.children);
            }

            return React.createElement(TreeNode, {
                title,
                key,
                value: key,
                isLeaf,
                disabled,
                selectable,
                disabledCheckbox
            }, children);
        });
    }

    render() {
        let info = this.getPropsInfo(this.props.info, this.props, ['filterTreeNode']);

        if (!info.name) {
            return <div>name property is required for TreeSelect Component</div>;
        }

        if (!this.isUnderContainerEnv()) {
            console.error('TreeSelect is not under container control, please it inside of container component');
            return <TreeSelect />;
        }

        let value = this.getValueFromDataStore(info.name);
        let options = info.options;

        if (!options || !(options instanceof Array)) {
            options = [];
        }

        if ((info.treeCheckStrictly || info.labelInValue) && !value) {
            value = [];
        }

        return (
            <TreeSelect
                allowClear={info.allowClear}
                onChange={this.handleTreeChange}
                onSelect={(...args: any[]) => {
                    let val = args[0];
                    let event = args[2];
                    this.commonEventHandler('onSelect', {
                        value: val,
                        checked: event.checked
                    });
                }}
                onSearch={(val: any) => {
                    this.commonEventHandler('onSearch', {
                        value: val
                    });
                }}
                value={value}
                disabled={info.disabled}
                dropdownMatchSelectWidth={info.dropdownMatchSelectWidth}
                dropdownStyle={info.dropdownStyle}
                labelInValue={info.labelInValue}
                multiple={info.multiple}
                placeholder={info.placeholder}
                searchPlaceholder={info.searchPlaceholder}
                showCheckedStrategy={info.showCheckedStrategy}
                size={info.size}
                showSearch={info.showSearch}
                style={{ width: 300 }}
                treeCheckable={info.treeCheckable}
                treeDefaultExpandAll={info.treeDefaultExpandAll}
                treeDefaultExpandedKeys={info.treeDefaultExpandedKeys}
                treeCheckStrictly={info.treeCheckStrictly}
            >
                {this.renderTreeNode(options)}
            </TreeSelect>
        );
    }
}

componentLoader.addComponent('treeSelect', AbstractTreeSelect, TreeSelectPropsInterface);
