import {hasPrintableChars} from '../../utils/hasPrintableChars';
import * as React from 'react';

import debounce from 'lodash/debounce';
import {Tree, ITreeColumn, ITreeNode} from '../../index';
import {Select, IOption, Value, Mode} from './Select';
import * as styles from './select.m.scss';

interface IProps<T> {
    searchFields: string[];
    mode?: Mode;
    onSelectNode: (node: ITreeNode<T>) => void | true; // for stay select open, you should return true from onSelect callback
    onChange?: (value: Value) => void;
    value?: Value;
    options: IOption[];
    nodes: Array<ITreeNode<T>>;
    columns: ITreeColumn[];
    selectedNodes?: string[];
    disabledNodes?: string[];
    allowClear?: boolean;
    showSearch?: boolean;
    placeholder?: string;
    hasError?: boolean;
}

interface IState {
    searchText: string;
}

const defaultProps = {
    searchFields: ['name', 'displayName'],
    mode: 'default',
    allowClear: true
};

// ToDo fix search
export class SelectTree<T> extends React.Component<IProps<T>, IState> {
    static defaultProps = defaultProps;
    readonly MIN_SEARCH_STRING_LENGTH = 3;

    constructor (props: IProps<T>) {
        super(props);

        this.select = this.select.bind(this);
        this.resetSearch = this.resetSearch.bind(this);
        this.onSearch = this.onSearch.bind(this);
        this.renderTable = this.renderTable.bind(this);
        this.updateSearchText = debounce(this.updateSearchText, 300);

        this.state = {
            searchText: ''
        };
    }

    select (onSelect: () => void): (item: ITreeNode<T>) => void {
        return (item: ITreeNode<T>) => {
            const stayShown = this.props.onSelectNode(item);

            if (stayShown !== true) {
                onSelect();
            }
        };
    }

    resetSearch () {
        this.setState({searchText: ''});
    }

    onSearch (text: string) {
        if (text.length >= this.MIN_SEARCH_STRING_LENGTH) {
            this.updateSearchText(text);
        } else {
            if (text.length === 0) {
                this.resetSearch();
            }
        }
    }

    searchFieldsContainValue (node: ITreeNode<T>, value: string): boolean {
        let found = false;

        for (let searchField of this.props.searchFields) {
            let field: string = (node.row as any)[searchField];

            if (field && field.indexOf(value) > -1) {
                found = true;
            }
        }

        return found;
    }

    filterRecursive (data: Array<ITreeNode<T>>, text: string): Array<ITreeNode<T>> {
        let me = this;
        let childrenContainValue: boolean = false;

        if (!hasPrintableChars(text)) {
            return data;
        }

        let filteredNodes = data.filter(function (node) {
            if (node.children) {

                node.children = me.filterRecursive([...node.children], text);
            }

            childrenContainValue = Boolean(node.children && node.children.length > 0);

            return childrenContainValue || me.searchFieldsContainValue(node, text);
        });

        return filteredNodes;
    }

    updateSearchText (text: string) {
        if (text !== this.state.searchText) {
            this.setState({searchText: text});
        }
    }

    renderTable (selectedOptions: IOption[], closeCallback: () => void) {
        let nodes = this.filterRecursive([...this.props.nodes], this.state.searchText);

        return (
            <div className={styles.dropdownContainer}>
                <Tree
                    selectedNodes={this.props.selectedNodes || []}
                    disabledNodes={this.props.disabledNodes}
                    columns={this.props.columns}
                    onNodeSelect={this.select(closeCallback)}
                    nodes={nodes}
                />
            </div>
        );
    }

    override render () {
        return (
            <Select
                options={this.props.options}
                placeholder={this.props.placeholder}
                mode={this.props.mode}
                value={this.props.value}
                showSearch={this.props.showSearch}
                allowClear={this.props.allowClear}
                onSearch={this.onSearch}
                dropdownRender={this.renderTable}
                hasError={this.props.hasError}
            />
        );
    }
}
