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

import AggregationCreator from './AggregationCreator';
import FlexModal from '../FlexModal';
import IDUtil from '../../util/IDUtil';
import ComponentUtil from '../../util/ComponentUtil';
import ReactTooltip from 'react-tooltip';
import classNames from 'classnames';
import AggregationBox from './AggregationBox';

//this component draws the aggregations (a.k.a. facets) and merely outputs
//the user selections to the parent component
export default class AggregationList extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            showModal: false,
            showModalWarning: false,
            //TODO merge these three states into one, since they all keep state information per aggregation box
            showAllModes: {}
        };
        this.CLASS_PREFIX = "agl";
        this.minToShow = 5;
        this.currentFacet = null;
    }

    //communicates the selected facets back to the parent component
    onOutput = (desiredFacets, selectedFacets) => {
        if(!selectedFacets) {
            selectedFacets = this.props.selectedFacets;
        }
        if (this.props.onOutput) {
            this.props.onOutput(this.constructor.name, {
                desiredFacets: desiredFacets,
                selectedFacets: selectedFacets
            });
        }
    };

    onComponentOutput = (componentClass, data) => {
        if (componentClass === "AggregationCreator" && data) {
            const desiredFacets = this.props.desiredFacets;
            desiredFacets.unshift(data);
            this.onOutput(desiredFacets, this.props.selectedFacets);
            ComponentUtil.hideModal(
                this,
                "showModal",
                "field_select__modal",
                true
            );
        }
    };

    /* ------------------------------------- FACET SELECTION -------------------------------- */
    toggleSelectedFacet = (key, value) => {
        const facets = this.props.selectedFacets;
        if (facets) {
            if (facets[key]) {
                const index = facets[key].indexOf(value);
                if (index === -1) {
                    facets[key].push(value); //add the value
                } else {
                    facets[key].splice(index, 1); // remove the value
                    if (facets[key].length === 0) {
                        delete facets[key];
                    }
                }
            } else {
                facets[key] = [value];
            }
            //output to the parent component
            this.onOutput(this.props.desiredFacets, facets);
        }
    };

    /*------------------------------------- REMOVE DIALOG (TODO MAKE NICER) ----------------------------*/

    showRemoveDialog = (key, index) => {
        this.currentFacet = key;

        //FIXME this part is still nasty, but for now it's necessary to prevent
        //toggling the header menu when clicking the "X"
        if (document.querySelector("#index__" + index)) {
            document.querySelector("#index__" + index).addEventListener(
                "click",
                function(event) {
                    event.preventDefault();
                },
                { once: true }
            );
            ComponentUtil.showModal(
                this,
                "showModalWarning",
                "field_select_facet__modal",
                true
            );
        }
    };

    removeAggregation = () => {
        //first remove the entry from the desiredFacets
        const desiredFacets = this.props.desiredFacets;
        for (let i = desiredFacets.length - 1; i >= 0; i--) {
            if (desiredFacets[i].field === this.currentFacet) {
                desiredFacets.splice(i, 1);
                break;
            }
        }
        //then throw away any selected value from the selectedFacets
        if (this.props.selectedFacets) {
            delete this.props.selectedFacets[this.currentFacet];
        }

        ComponentUtil.hideModal(
            this,
            "showModalWarning",
            "field_select_facet__modal",
            true
        );
        this.onOutput(desiredFacets, this.props.selectedFacets);
    };

    //makes sure to filter out heavy facets that will freeze the screen
    //(in case the search term is smaller than 3 characters long)
    filterHeavyFacets = (desiredFacets, allowHeavyFacets) => {
        const lightFacets = this.props.collectionConfig.getFacetSelectionList(false).map(f => f.value);
        return allowHeavyFacets ? desiredFacets : desiredFacets.filter(df => lightFacets.indexOf(df.field) !== -1)
    };

    /*------------------------------------- FUNCTION FOR GENERATING UI FRIENDLY DATA OBJECT --------------*/
    //returns render friendly object based on the data supplied in the props
    generateUIData = () => {
        //will be ultimately returned containing a list of ui data per "desired aggregation"
        const uiData = [];

        const desiredFacets = this.props.desiredFacets ?
            this.filterHeavyFacets(this.props.desiredFacets, this.props.allowHeavyFacets) :
            [];
        //Check if all selected facets are in the desired aggregation list, if not, add doc_count 0
        Object.keys(this.props.selectedFacets).forEach(field => {
            this.props.selectedFacets[field].forEach(facetValue => {
                const found = this.props.aggregations[field].find(
                    aggr => aggr["key"] === facetValue
                );
                if (!found) {
                    this.props.aggregations[field].push({
                        key: facetValue,
                        doc_count: 0
                    });
                }
            });
        });

        //loop through the desired facets, available in the state
        desiredFacets.forEach((da, index) => {
            // skip the date_histogram types, as they shouldn't be converted to a list
            // however, they should be included in this loop in order to keep the facet
            // index intact
            if (da.type === "date_histogram") {
                return;
            }

            //first check if the aggregation has anything in it
            const isEmptyAggr = !(
                this.props.aggregations[da.field] &&
                this.props.aggregations[da.field].length > 0
            );

            //then parse the retrieved facets/buckets
            let facets = [];
            if (!isEmptyAggr) {
                facets = this.props.aggregations[da.field].map(facet => {
                    return {
                        key: facet.key,
                        guid: da.field + "|" + facet.key,
                        count: facet.doc_count,
                        selected: this.props.selectedFacets[da.field] && this.props.selectedFacets[da.field].indexOf(
                            facet.key
                        ) !== -1
                    };
                });
                // move the selected facets to the top of the array, so they always appear on top in the list
                const selectedFacets = facets.filter(f => f.selected);
                facets = facets.filter(f => !f.selected);
                facets.unshift(...selectedFacets);
            }

            //then add them to the convenient UI object (together with the exclusion property)
            uiData.push({
                facets: facets,
                exclude: da.exclude === undefined ? false : da.exclude,
                field: da.field,
                title:// show user generated title or else the automated prettified title
                    da.title ||
                    this.props.collectionConfig.toPrettyFieldName(da.field),
                empty: isEmptyAggr, //does the aggregation have anything in it
                index: index, // temporarily needed for guid
                guid: "facets__" + index
            });
        });
        return uiData;
    };

    /*------------------------------------- FUNCTIONS FOR RENDERING ----------------------------*/
    renderEmptyBlocks = aggr => (
        <div className={IDUtil.cssClassName('empty-facet-block', this.CLASS_PREFIX)}
            key={"facet__" + aggr.index}
            id={"index__" + aggr.index}>
            <div className={IDUtil.cssClassName('title-wrapper', this.CLASS_PREFIX)}>
                <i
                    className='fas fa-info-circle'
                    data-for={'tooltip__' + aggr.index}
                    data-tip={aggr.field}
                    data-html={true}
                />
                <div className={IDUtil.cssClassName('facet-title', this.CLASS_PREFIX)}>
                    (0) {aggr.title}{" "}
                </div>
                <div
                    className='fas fa-times'
                    onClick={this.showRemoveDialog.bind(
                        this,
                        aggr.field,
                        aggr.index
                    )}
                />
            </div>
            <ReactTooltip id={"tooltip__" + aggr.index}/>
        </div>
    );

    renderSelectedFacet = (curAggr, f) => {
        let title = f.key + ' (' + curAggr.title + ')';
        let count = f.count;
        if (curAggr.exclude === true) {
            title = "NOT - " + title;
            count = 0;
        }
        return (
            <div key={'__sf__' + curAggr.field + f.key} className={classNames(
                    { exclude: curAggr.exclude === true },
                    IDUtil.cssClassName('selected-item', this.CLASS_PREFIX)
                )}>
                <span className="elem-label" title={title}>{title}{" "}</span>
                <span className={IDUtil.cssClassName('count', this.CLASS_PREFIX)}>
                    {count}
                </span>
                <span className="fas fa-times" onClick={this.toggleSelectedFacet.bind(this, curAggr.field, f.key)}/>
            </div>
        );
    };

    renderNewFacetModal = (allowHeavyFacets, fieldList, desiredFacets) => {
        const filteredFields = fieldList.filter(
            item => desiredFacets.findIndex(facet => facet.field === item.value) === -1
        );

        return (
            <FlexModal
                size="large"
                elementId="field_select__modal"
                stateVariable="showModal"
                owner={this}
                title="Create a new facet"
            >
                <AggregationCreator
                    allowHeavyFacets={allowHeavyFacets}
                    onOutput={this.onComponentOutput}
                    key={this.props.searchId}
                    fieldList={filteredFields}
                />
            </FlexModal>
        );
    };

    renderRemoveFacetModal = () => (
        <FlexModal
            elementId="field_select_facet__modal"
            stateVariable="showModalWarning"
            owner={this}
            title="Remove current facet?"
        >
            <div>
                <p>
                    You are removing the current facet "
                    <u>{this.props.collectionConfig ?
                        this.props.collectionConfig.toPrettyFieldName(this.currentFacet) :
                        this.currentFacet
                    }</u>". You can bring it back by
                    using the "New" facet option and searching for the same
                    field name again
                </p>
                <br/>
                <button type="button" onClick={this.removeAggregation} className="btn btn-primary">
                    Remove
                </button>
            </div>
        </FlexModal>
    );

    render() {
        //contains all required data for generating the (empty) aggregation blocks and selected facets
        const uiData = this.generateUIData();
        //modals
        const aggregationCreatorModal = this.state.showModal && this.props.collectionConfig
            ? this.renderNewFacetModal(
                this.props.allowHeavyFacets,
                this.props.collectionConfig.getFacetSelectionList(this.props.allowHeavyFacets),
                this.props.desiredFacets
            )
            : null;
        const aggregationModalWarning = this.state.showModalWarning
            ? this.renderRemoveFacetModal()
            : null;

        //for each empty aggregation, add a (rendered) block to the list (of empty aggregations)
        const emptyAggrBlocks = uiData
            .filter(aggr => aggr.empty)
            .map(this.renderEmptyBlocks); //contains aggregations without any results

        const aggregationBlocks = [];
        let selectedFacets = []; //holds the list of selected facets to be displayed at the top
        //loop through the non-empty "desired aggregations" (non-histogram only)
        uiData
            .filter(aggr => !aggr.empty)
            .forEach(curAggr => {
                //add another (rendered) aggregation block to the list
                aggregationBlocks.push(
                    <AggregationBox
                        key={this.props.searchId + '__' + curAggr.guid}
                        showRemoveDialog={this.showRemoveDialog}
                        onOutput={this.onOutput}
                        selectedFacets={this.props.selectedFacets}
                        desiredFacets={this.props.desiredFacets}
                        onToggleSelectedFacet={this.toggleSelectedFacet}
                        data={curAggr}
                    />);
                //add the (rendered) facets that are selected within the current aggregation
                //block (to be displayed at the top)
                selectedFacets = selectedFacets.concat(
                    curAggr.facets.filter(f => f.selected).map(
                        f => {return this.renderSelectedFacet(curAggr, f)}
                    )
                );
            });

        //finally render the whole thing
        return (
            <div className={IDUtil.cssClassName("aggregation-list checkboxes")}>
                {aggregationCreatorModal}
                {aggregationModalWarning}

                {/* Create new facet */}
                <div className={IDUtil.cssClassName("tab-new", this.CLASS_PREFIX)}>
                    <button
                        className="btn"
                        onClick={ComponentUtil.showModal.bind(
                            this,
                            this,
                            "showModal"
                        )}
                    >
                        <i className="fas fa-plus" /> Add a new facet
                    </button>
                </div>

                {/* Selected/active facets */}
                <div
                    className={IDUtil.cssClassName('selected-facets', this.CLASS_PREFIX)}>
                    {selectedFacets}
                </div>
                {/* Empty facets */}
                {emptyAggrBlocks}
                {/* Facet list */}
                {aggregationBlocks}
            </div>
        );
    }
}

AggregationList.propTypes = {
    aggregations: PropTypes.object.isRequired,
    collectionConfig: PropTypes.object.isRequired,
    desiredFacets: PropTypes.array,
    onOutput: PropTypes.func.isRequired,
    queryId: PropTypes.string,
    searchId: PropTypes.string,
    allowHeavyFacets: PropTypes.bool.isRequired, //for determining whether to show heavy facets or not
    selectedFacets: PropTypes.object
};
