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

import IDUtil from "../../util/IDUtil";
import QueryInfoBlock from "./helpers/QueryInfoBlock";
import QueryComparisonLineChart from "./QueryComparisonLineChart";
import ComparisonHistogram from "./ComparisonHistogram";

import CollectionUtil from "../../util/CollectionUtil";
import SearchAPI from "../../api/SearchAPI";
import Query from "../../model/Query";
import ComponentUtil from "../../util/ComponentUtil";
import ElasticsearchDataUtil from "../../util/ElasticsearchDataUtil";

export default class QueriesTimelinePlotter extends React.Component {

    constructor(props) {
        super(props);
        this.layout = document.querySelector("body");
        this.state = {
            chartType : 'histogram',

            //all populated by processQueryInput()
            queryStats: null,
            lineChartData: null, //contains all the retrieved stats per queryId (for all queries)
            barChartData: null,
            namedQueries: null
        }

        //maybe handle these somewhere else
        this.layout = document.querySelector("body");
        this.COLORS = [
            'darkturquoise', 'goldenrod', 'deeppink', 'cadetblue', 'crimson',
            'lime', 'violet', 'seagreen', 'yellowgreen', 'dodgerblue', 'mediumpurple',
            'blue', 'lightcoral', 'olivedrab', 'sienna', 'gold', 'darkslategrey'
        ];
    }

    componentDidMount = () => {
        this.processQueryInput(this.props.namedQueries);
    };

    switchGraphType = () => this.setState(
        {chartType: this.state.chartType === 'lineChart' ? 'histogram' : 'lineChart'}
    );

    /* -------- FUNCTIONS THAT GENERATE UI DATA BASED ON SELECTED QUERIES ------------- */

    processQueryInput = namedQueries => {
        if(namedQueries && namedQueries.length > 0) {
            this.layout.classList.add("spinner");
            this.__fetchData(namedQueries).then(data => this.__generateChartData(data, namedQueries));
        } else {
            this.setState({queryStats: null, lineChartData: null, barChartData: null, namedQueries: null});
        }
    };

    __fetchData = async (namedQueries) => await Promise.all(
        namedQueries.filter(q => q.query).map(q => this.__getData(q))
    );

    __getData = namedQuery => new Promise((resolve, reject) => {
        CollectionUtil.generateCollectionConfig(
            this.props.clientId, this.props.user, namedQuery.query.collectionId, (collectionConfig) => {
            const dateField = collectionConfig.getPreferredDateField() || null;
            if (namedQuery.query.dateRange == null && dateField !== null) {
                namedQuery.query.desiredFacets.push({
                    "field": dateField,
                    "id": dateField,
                    "title": collectionConfig.toPrettyFieldName(dateField),
                    "type": "date_histogram"
                });
            }
            SearchAPI.search(
                Query.construct(namedQuery.query, collectionConfig),
                collectionConfig,
                data => {
                    //just resolve everything, even if the data is null or has errors. Handle this later
                    resolve(data);
                },
                false
            )
        });
    }).catch(err => console.log('No data returned from query', err));

    __generateChartData = (resultsObjects, namedQueries) => {
        const queryStats = {}; //keep status information for the QueryInfoBlock
        resultsObjects.forEach((resultsObj, index) => {
            queryStats[resultsObj.searchId] = {
                hasDateInformation: this.__hasDateInformation(resultsObj),
                error: !resultsObj || resultsObj.error ? true : false,
                totalHits: resultsObj ? resultsObj.totalHits || 0 : 0,
                collectionConfig: resultsObj && resultsObj.collectionConfig ? resultsObj.collectionConfig : null,
                color: this.COLORS[index] || 'black',
                queryIndex: index + 1,
                searchId: resultsObj.searchId
            };

            // Filter weird dates from returned query.
            ComponentUtil.filterWeirdDates(
                resultsObj.aggregations,
                resultsObj.query.dateRange,
                resultsObj.collectionConfig
            );
        });

        const barChartData = resultsObjects.filter(this.__hasDateInformation);
        const lineChartData = {};

        barChartData.forEach(resultsObj => {
            if (resultsObj && resultsObj.query) {
                const timelineData = ElasticsearchDataUtil.searchResultsToTimeLineData(
                    resultsObj.searchId,
                    resultsObj.query,
                    resultsObj.aggregations
                );
                if (timelineData) { //avoid feeding the graph with null data
                    lineChartData[resultsObj.searchId] = {
                        data: timelineData,
                        comparisonId: resultsObj.searchId,
                        query: resultsObj.query,
                        collectionConfig: resultsObj.collectionConfig
                    };
                }
            }
        });
        this.setState({
            queryStats: queryStats,
            lineChartData: lineChartData,
            barChartData: barChartData,
            namedQueries: namedQueries
        }, () => {
            this.layout.classList.remove("spinner") // hide the loading graphic
        });
    };

    __hasDateInformation = item => {
        if (item.query && item.aggregations) {
            if (item.query.dateRange && item.query.dateRange.field) {
                return item.aggregations[item.query.dateRange.field] != null && item.aggregations[item.query.dateRange.field].length > 0
            }
        }
        return false;
    };

    /* ----------------------- RENDER FUNCTIONS -------------------------- */

    render() {
        const queryInfoBlock = this.state.queryStats ?
            <QueryInfoBlock queries={this.props.namedQueries} queryStats={this.state.queryStats}/> :
            null
        ;
        let graphTypeBtn = null;
        let chart = null;

        if (this.state.lineChartData && Object.keys(this.state.lineChartData).length > 0) {
            graphTypeBtn = (
                <button
                    onClick={this.switchGraphType}
                    type="button"
                    className="switch-view-btn">
                    {this.state.chartType === 'lineChart' ? 'Histogram' : 'Line Chart'}
                </button>
            );

            chart = this.state.chartType === 'lineChart' ?
                <QueryComparisonLineChart data={this.state.lineChartData} queryStats={this.state.queryStats}/> :
                <ComparisonHistogram data={this.state.barChartData} queryStats={this.state.queryStats}/>
            ;
        }
        return (
            <div className={IDUtil.cssClassName('query-timeline-plotter')}>
                {graphTypeBtn}
                {chart}
                {queryInfoBlock}
            </div>
        )
    };
}

QueriesTimelinePlotter.propTypes = {
    clientId : PropTypes.string.isRequired, //should be part of a context object
    user: PropTypes.shape({ //should be part of a context object
        id: PropTypes.string.isRequired,
        name: PropTypes.string,
        attributes: PropTypes.shape({
            allowPersonalCollections: PropTypes.bool
        })
    }).isRequired,
    namedQueries: PropTypes.array.isRequired
};
