import * as React from 'react';
import {
    BasicConfig, BasicContainer, BasicContainerPropsInterface,
} from '../../render/core/Container/types';
import {IsDefined, IsString} from 'class-validator';
import componentLoader from '../../render/util/componentLoader';
import {Tree} from '@native-ads/antd';
import * as _ from 'lodash';
import {TreeProps} from '@native-ads/antd/es/tree';

const TreeNode = Tree.TreeNode;

export class TreeConfig extends BasicConfig {
    /**
     * 数据模型Key
     */
    @IsString()
    @IsDefined()
    name: string;

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

    /**
     * 自动展开树节点
     */
    autoExpandParent?: boolean;

    /**
     * 支持多选
     */
    checkable?: boolean;

    /**
     * 节点可拖拽
     */
    // draggable?: boolean;

    /**
     * checkable状态下节点选择完全受控（父子节点选中状态不再关联）
     */
    checkStrictly?: boolean;

    /**
     * 支持点选多个节点（节点本身）
     */
    multiple?: boolean;

    /**
     * 显示连接线
     */
    showLine?: boolean;
}

export class TreeNodeConfig {
    /**
     * 标题
     */
    title: string;

    /**
     * 节点的值
     */
    key: string;

    /**
     * 是否是子节点
     */
    isLeaf?: boolean;

    /**
     * 禁掉 checkbox
     */
    disableCheckbox?: boolean;

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

    /**
     * 设置节点是否可被选中
     */
    selectable?: boolean;

    /**
     * 子节点
     */
    children?: TreeNodeConfig[];
}

export class TreePropsInterface extends BasicContainerPropsInterface {
    info: TreeConfig;
}

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

        this.handleSelect = this.handleSelect.bind(this);
    }

    private handleSelect(selectedKeys: Array<string>, event: any) {
        const info = this.getPropsInfo(this.props.info);
        if (this.props.$setData && info.name) {
            this.props.$setData(info.name, selectedKeys);
        }

        this.commonEventHandler('onSelect', {
            selectedKeys,
            selected: event.selected
        });
    }

    private renderTreeNode(options: TreeNodeConfig[]): React.ReactNode[] {
        return options.map(op => {
            let title = op.title;
            let key = op.key;
            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,
                isLeaf,
                disabled,
                selectable,
                disabledCheckbox
            }, children);
        });
    }

    private mapTreeOptions(info: TreeConfig): TreeProps {
        return {
            className: info.className,
            checkStrictly: info.checkStrictly,
            style: info.style,
            autoExpandParent: info.autoExpandParent || true,
            checkable: info.checkable,
            multiple: info.multiple,
            showLine: info.showLine
        };
    }

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

        if (!info.name) {
            return this.errorReport('name property is required for tree element', 'div');
        }

        if (!this.isUnderContainerEnv()) {
            return this.errorReport('tree component should be under container component', 'div');
        }

        let options: TreeNodeConfig[] = info.options;

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

        let treeNodes = this.renderTreeNode(options);
        let treeOptions = this.mapTreeOptions(info);

        return (
            <Tree
                {...treeOptions}
                onCheck={(checkedKeys: Array<string>, event: any) => {
                    let checked = event.checked;
                    this.commonEventHandler('onCheck', {
                        checkedKeys,
                        checked: checked
                    });
                }}
                onSelect={this.handleSelect}
            >
                {treeNodes}
            </Tree>
        );
    }
}

componentLoader.addComponent('tree', AbstractTree, TreePropsInterface);
