import React from 'react';
import { FormControl, InputGroup, ListGroup } from 'react-bootstrap';
import { deepClone } from '../../../lib/helpers/objectMethods';

export interface SelecitonProps<T> {
    selection: Array<{
        groupName: string,
        items: SelectionItem<T>[]
    } | SelectionItem<T>>,
    onItemSelected?: (item: T) => void;
    allowUserSelect?: boolean;
}

export interface SelectionItem<T> {
    label: string,
    keywords: string,
    item: T,
    id: string | number,
    color?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'light'
}

export interface LayoutState<T> {
    selected: string | number;
    search: string;
}

class Selection<T> extends React.Component<SelecitonProps<T>, LayoutState<T>> {

    constructor(props) {
        super(props);
        this.state = {
            search: '',
            selected: null
        }
    }

    /**
     * Function to Filter the Selection.
     * @param search The Search Term.
     */
    protected _filter(search: string) {
        this.setState({
            search: search.toLocaleLowerCase(),
            selected: this.state.selected
        });
    }

    /**
     * Function used to Select an item
     * @param item which will be selected 
     */
    protected _select(item: SelectionItem<T>) {
        this.setState({
            search: this.state.search,
            selected: this.props.allowUserSelect ? item.id : -1
        });

        if (this.props.allowUserSelect && typeof this.props.onItemSelected === "function") {
            this.props.onItemSelected(item.item);
        }
    }

    public render() {
        const _this = this;

        // Filter only Valid items.
        // Therefore iterate over the Groups and
        // Filter the Items with the Search String
        // and there Labels / Keywords.
        // Afterwards filter the groups and remove
        // Empty Groups
        const items = deepClone(this.props).selection.map(item => {

            if ((item as {
                groupName: string,
                items: SelectionItem<T>[]
            }).items !== undefined) {

                // Filter the Items, that match the Selection
                (item as {
                    groupName: string,
                    items: SelectionItem<T>[]
                }).items = (item as {
                    groupName: string,
                    items: SelectionItem<T>[]
                }).items.filter(value =>
                    // Filter the Keywords
                    value.keywords.toLowerCase().includes(_this.state.search) ||
                    // Filter the Lable.
                    value.label.toLowerCase().includes(_this.state.search)
                );
            }

            // Return the Item
            return item;
        }).filter(
            item => {
                // Filter the Element by the lenght of the contained elements.
                if ((item as {
                    groupName: string,
                    items: SelectionItem<T>[]
                }).items !== undefined) {
                    // Filter the Keywords
                    return (item as {
                        groupName: string,
                        items: SelectionItem<T>[]
                    }).items.length > 0;
                } else {
                    // Filter the Keywords
                    return (item as SelectionItem<T>).keywords.toLowerCase().includes(_this.state.search) ||
                        // Filter the Lable.
                        (item as SelectionItem<T>).label.toLowerCase().includes(_this.state.search)
                }
            }

        );

        let idx = 0;
        return (<>
            {/* A Search Field. */}
            {this.props.allowUserSelect ?
                <InputGroup size="sm" className="mb-3">
                    <InputGroup.Prepend>
                        <InputGroup.Text id="inputGroup-sizing-sm" >Search</InputGroup.Text>
                    </InputGroup.Prepend>
                    <FormControl aria-label="Small" aria-describedby="inputGroup-sizing-sm" onChange={(event) => {
                        _this._filter(event.currentTarget.value);
                    }} />
                </InputGroup> : ''
            }
            {
                items.length > 0 ?
                    items.map(item => {
                        idx++;

                        if ((item as {
                            groupName: string,
                            items: SelectionItem<T>[]
                        }).items !== undefined) {
                            return (
                                <div key={idx}>
                                    <hr />
                                    <h4>{(item as {
                                        groupName: string,
                                        items: SelectionItem<T>[]
                                    }).groupName}</h4>
                                    <hr />
                                    <ListGroup>
                                        {(item as {
                                            groupName: string,
                                            items: SelectionItem<T>[]
                                        }).items.map(template => {
                                            // Raise the ID
                                            idx++;
                                            // Store the Item Index
                                            const idxOfItem = idx;

                                            // Based on the selected Item assign the Color
                                            // dark = selected
                                            // light = unselected
                                            const variant = _this.props.allowUserSelect ?
                                                (template.id === _this.state.selected ? "dark" : "light") :
                                                template.color || 'light';

                                            // Return the Template variant={variant}
                                            return (
                                                <ListGroup.Item key={idxOfItem} action variant={variant} onClick={e => {
                                                    _this._select(template)
                                                }}>{template.label}</ListGroup.Item>
                                            );
                                        })}
                                    </ListGroup>
                                </div>
                            );
                        } else {
                            // Store the Item Index
                            const idxOfItem = idx;

                            // Based on the selected Item assign the Color
                            // dark = selected
                            // light = unselected
                            const variant = _this.props.allowUserSelect ?
                                ((item as SelectionItem<T>).id === _this.state.selected ? "dark" : "light") :
                                (item as SelectionItem<T>).color || 'light';
                            // Return the Template variant={variant}
                            return (
                                <ListGroup.Item key={idxOfItem} action variant={variant} onClick={e => {
                                    _this._select(item as SelectionItem<T>)
                                }}>{(item as SelectionItem<T>).label}</ListGroup.Item>
                            )
                        }
                    }) :
                    <code>Nothing Found</code>
            }
        </>);
    }
}

export default Selection;