import React from 'react';
import PropTypes from 'prop-types';

import classNames from 'classnames';
import IDUtil from '../../util/IDUtil';
import ReactTooltip from 'react-tooltip';
import debounce from 'debounce';

class AggregationBox extends React.PureComponent {

    constructor(props) {
        super(props);

        this.state = {
            sortMode: this.determineSortMode(),
            showAll: this.determineShowAll(),
            currentOptions: this.props.data.facets,
            showExtraOptions: false,
        };
        this.CLASS_PREFIX = "agb";
        this.minToShow = this.props.minToShow || 5;
        this.maxToShow = this.props.maxToShow || 10;
        this.SORT_BUTTON_TITLES = { alpha: "Alphanumeric", numeric: "Numeric" };

        this.updateKeywordFilter = debounce(this.updateKeywordFilter, 150)
    }

    determineSortMode = () => {
        //load the sort mode from the desired facet corresponding
        //to this facet in the query, otherwise use the default
        const desiredFacet = this.props.desiredFacets[this.props.desiredFacets.findIndex(desiredFacet => desiredFacet.field === this.props.data.field)]
        let sortMode = {
                alpha: "asc",
                numeric: "asc",
                active: "alpha"
            }
        if(desiredFacet!=null && "sortMode" in desiredFacet)
        {
            sortMode = desiredFacet["sortMode"]
        }
        return sortMode;
    }

    determineShowAll = currentFacet => {
        //load the showAll value from the desired facet corresponding
        //to this facet in the query, otherwise use the default
       const desiredFacet = this.props.desiredFacets[this.props.desiredFacets.findIndex(desiredFacet => desiredFacet.field === this.props.data.field)]
        let showAll = false;
        if(desiredFacet!=null && "showAll" in desiredFacet)
        {
            showAll = desiredFacet["showAll"]
        }

        return showAll;
    }

    saveSortMode = (newSortMode) => {
        //save the changed sort mode to the equivalent desired facet
        //so that it will be stored in the query
        const desiredFacet = this.props.desiredFacets[this.props.desiredFacets.findIndex(desiredFacet => desiredFacet.field === this.props.data.field)]
        desiredFacet["sortMode"] = newSortMode
    }

    saveShowAllValue = (newShowAllValue) => {
        //save the changed show all value to the equivalent desired facet
        //so that it will be stored in the query
        const desiredFacet = this.props.desiredFacets[this.props.desiredFacets.findIndex(desiredFacet => desiredFacet.field === this.props.data.field)]
        desiredFacet["showAll"] = newShowAllValue
    }

    sortData = (data, sortMode) => {
        let newSortedList = [...data];
        const disabledFields = 'Empty field';
        if (sortMode.active === 'alpha') {
            if (sortMode['alpha'] === 'desc') {
                newSortedList.sort((a, b) => {
                    if(a.key === disabledFields) {
                        return -2;
                    } else if(typeof(a.key) == 'number') {
                        return b.key - a.key
                    } else if(typeof(a.key) == 'string') {
                        return a.key.toLowerCase() < b.key.toLowerCase() ? 1 : (b.key.toLowerCase() < a.key.toLowerCase() ? -1 : 0);
                    }
                });
            } else { //asc
                newSortedList.sort((a, b) => {
                    if(a.key === disabledFields) {
                        return -2;
                    } else if(typeof(a.key) == 'number') {
                        return a.key - b.key;
                    } else if(typeof(a.key) == 'string') {
                        return a.key.toLowerCase() > b.key.toLowerCase() ? 1 : (b.key.toLowerCase() > a.key.toLowerCase() ? -1 : 0);
                    }
                });
            }

            return newSortedList;
        } else if (sortMode.active === 'numeric') {
            if (sortMode['numeric'] === 'desc') {
                newSortedList.sort((a, b) => {
                    if(a.key === disabledFields){
                        return -2;
                    }
                    return  b.count - a.count;
                });
            } else { //asc
                newSortedList.sort((a, b) => {
                    if(a.key === disabledFields){
                        return -2;
                    }
                    return a.count - b.count;
                });
            }
            return newSortedList;
        } else {
            return null;
        }
    };

    // puts selected elements on top
    getSelectedAggregation = aggr => {
        const selectedFirst = [];
        aggr.forEach(item => {
            if (item.selected) {
                selectedFirst.unshift(item)
            } else {
                selectedFirst.push(item)
            }
        });
        return selectedFirst;
    };

    toggleSelectedFacet = e => this.props.onToggleSelectedFacet(
        this.props.data.field,
        e.currentTarget.getAttribute('value')
    );

    renderAggregationBlock = data => {
        const sortedData = this.sortData(data, this.state.sortMode);
        const selectedAggregation = this.getSelectedAggregation(sortedData);
        const nrOfSelectedTerms = this.props.selectedFacets[this.props.data.field] ?
            this.props.selectedFacets[this.props.data.field].length :
            0
        ;
        const disabledFields = 'Empty field';

        const sortedFacets = selectedAggregation.map((f, index) => {
            return (
                <li
                    key={"facet__" + data.index + "__" + index}
                    id={this.props.data.field}
                    value={f.key}
                    title={f.key}
                    hidden={this.state.showAll ?
                        index > this.state.currentOptions.length :
                        index > this.minToShow + nrOfSelectedTerms
                    }
                    className={classNames(
                        {selected: f.selected, exclude: this.props.data.exclude, disabled : f.key === disabledFields},
                        IDUtil.cssClassName('facet-list-item', this.CLASS_PREFIX)
                    )}
                    onClick={f.key !== disabledFields ? this.toggleSelectedFacet : null}
                >
                    {f.key !== disabledFields ?
                        <span className={IDUtil.cssClassName("checkbox", this.CLASS_PREFIX)}/> :
                        null
                    }
                    <span className="elem-label">{f.key}</span>
                    <span className={IDUtil.cssClassName('count', this.CLASS_PREFIX)}>{f.count}</span>
                </li>
            )

        });

        return (
            <ul className={IDUtil.cssClassName('facet-list', this.CLASS_PREFIX)}>
                {sortedFacets}
            </ul>
        );
    };

    toggleShow = () => {
    this.setState({ showAll: !this.state.showAll })
    this.saveShowAllValue(!this.state.showAll); //save the changed value in the desired facet so it will be saved in the query
    this.props.onOutput(this.props.desiredFacets, this.props.selectedFacets);
    };

    renderToggleShowMore = () => {
        const currentStatus = this.state.showAll
            ? {
                text: "Show Less",
                symbol: "switchIcon fas fa-minus"
            }
            : {
                text: "Show More",
                symbol: "switchIcon fas fa-plus"
            };

        if(this.state.currentOptions.length <= this.minToShow + (this.props.selectedFacets[this.props.data.field]
            ? this.props.selectedFacets[this.props.data.field].length
            : 0 )
        ) {
            return null;
        }

        return (
            <a className={IDUtil.cssClassName('switch-view', this.CLASS_PREFIX)} onClick={this.toggleShow}>
                <span className="switchViewText">{currentStatus.text}</span>
                <span className={currentStatus.symbol} aria-hidden="true" />
            </a>
        );
    };

    setFacetSortMode = (sortType, direction) => {
        const sortModes = this.state.sortMode;
        const newSortModes = {
            alpha : sortType === 'alpha' ? direction  : sortModes.alpha,
            numeric : sortType === 'numeric' ? direction : sortModes.numeric,
            active : sortType
        }
        //save new sort mode in the query
        this.setState({ sortMode: newSortModes }, () => this.sortData(this.state.currentOptions, this.state.sortMode));
        this.saveSortMode(newSortModes); //save the changed value in the desired facet so it will be saved in the query
        this.props.onOutput(this.props.desiredFacets, this.props.selectedFacets);
    };

    renderSortButton = (aggr, sortType) => {
        //alpha || numeric
        const sortMode = this.state.sortMode;
        const title = sortMode[sortType] === "desc"
                ? this.SORT_BUTTON_TITLES[sortType] + " descending"
                : this.SORT_BUTTON_TITLES[sortType] + " ascending";
        const newDirection = sortMode[sortType] === "desc" ? "asc" : "desc";
        const classNames = [
            "fa",
            "fa-lg",
            "fa-sort-" + sortType + "-" + sortMode[sortType]
        ];

        if (sortMode.active === sortType) {
            classNames.push(
                IDUtil.cssClassName("sort-active", this.CLASS_PREFIX)
            );
        }

        return (
            <div
                className={IDUtil.cssClassName("sort-btn", this.CLASS_PREFIX)}
                title={title}
                onClick={() => this.setFacetSortMode(sortType, newDirection)}
            >
                <i aria-hidden="true" className={classNames.join(" ")}/>
            </div>
        );
    };

    toggleExcludeFacets = () => {
        this.props.desiredFacets[this.props.data.index]["exclude"] =
            !this.props.desiredFacets[this.props.data.index]["exclude"];
        this.props.onOutput(this.props.desiredFacets, this.props.selectedFacets);
    };


    showRemoveDialog = () => this.props.showRemoveDialog(this.props.data.field, this.props.data.index);

    toggleExtraOptions = () => this.setState({ showExtraOptions: !this.state.showExtraOptions });

    renderHamburgerMenu = aggr => {
        const extraOptions = this.state.showExtraOptions ? (
            <div className={IDUtil.cssClassName('extra-options', this.CLASS_PREFIX)}>
                <div className={IDUtil.cssClassName('exclude-btn', this.CLASS_PREFIX)}>
                    <input
                        type="checkbox"
                        id={this.props.data.field}
                        checked={this.props.desiredFacets[this.props.data.index]['exclude'] || false}
                        onChange={this.toggleExcludeFacets}
                    />
                    &nbsp;<label htmlFor={this.props.data.field} title="Exclude selection from search results">Exclude</label>
                </div>
                <button
                    className={classNames('btn', IDUtil.cssClassName('remove-button', this.CLASS_PREFIX))}
                    onClick={this.showRemoveDialog}
                    title="Remove Facet"
                >
                    Remove
                </button>
                <div className={IDUtil.cssClassName('sort-btn-wrapper', this.CLASS_PREFIX)}>
                    {this.renderSortButton(this.props.data.facets, 'numeric')}
                    {this.renderSortButton(this.props.data.facets, 'alpha')}
                </div>
            </div>
        ) : null;

        return (
            <div className={IDUtil.cssClassName('facet-header', this.CLASS_PREFIX)}>
                <div className={IDUtil.cssClassName('facet-title-bar', this.CLASS_PREFIX)} onClick={this.toggleExtraOptions}>
                    <span className={IDUtil.cssClassName('facet-title', this.CLASS_PREFIX)}>
                        <i
                            className="fas fa-info-circle"
                            data-for={"tooltip__" + this.props.data.index}
                            data-tip={this.props.data.field}
                            data-html={true}
                        />
                        <span>{this.props.data.title}{" "}</span>
                    </span>

                    <div className={IDUtil.cssClassName('menu-icon', this.CLASS_PREFIX)}>⋮</div>
                </div>
                {extraOptions}
                <ReactTooltip id={"tooltip__" + this.props.data.index} />
            </div>
        );
    };

    // Returns items that have the searched term or that have already been selected.
    filterFields = (arr, str) => arr.filter(item => item.key && (item.key.toLowerCase().includes(str.toLowerCase()) || item.selected));

    onKeywordFilter = (e) => {
        this.updateKeywordFilter(e.target.value);
    };

    updateKeywordFilter = (value)=>{
        const newCategorySet = this.filterFields(this.props.data.facets, value);
        this.setState({
            currentOptions: newCategorySet
        });
    }

    render() {
        if (this.state.currentOptions) {
            const selectedTerms = this.props.selectedFacets[this.props.data.field]
                ? this.props.selectedFacets[this.props.data.field].length
                : 0;
            const nrOfTerms = this.state.currentOptions.length - selectedTerms;
            const renderedBlock = this.renderAggregationBlock(this.state.currentOptions);

            return (
                <div className={IDUtil.cssClassName('aggregation-box')} id={"index__" + this.props.data.index}>
                    {this.renderHamburgerMenu(this.props.data.facets)}
                    <div className={IDUtil.cssClassName('search-box', this.CLASS_PREFIX)}>
                        <input
                            className={IDUtil.cssClassName('search-input', this.CLASS_PREFIX)}
                            type="text"
                            placeholder="Search facet ..."
                            name="search"
                            onChange={this.onKeywordFilter}
                        />
                        <div className={IDUtil.cssClassName('search-count', this.CLASS_PREFIX)}>
                            {nrOfTerms} terms
                        </div>
                    </div>
                    {renderedBlock}
                    {this.renderToggleShowMore()}
                </div>
            );
        } else {
            return <div>loading ...</div>
        }
    }
}

AggregationBox.propTypes = {
    clientId: PropTypes.string,

    user: PropTypes.shape({
        id: PropTypes.string.isRequired
    }),

    data: PropTypes.shape({
        empty: PropTypes.boolean,
        field: PropTypes.string.isRequired,
        exclude : PropTypes.boolean,
        facets : PropTypes.array,
        guid : PropTypes.string,
        index: PropTypes.number.isRequired,
        title: PropTypes.string
    }).isRequired,
    desiredFacets : PropTypes.array,
    onOutput: PropTypes.func,
    onToggleSelectedFacet : PropTypes.func,
    selectedFacets : PropTypes.object,
    showRemoveDialog : PropTypes.func
};

export default AggregationBox;
