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

//TODO fix autosuggest https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html
import Autosuggest from 'react-autosuggest'; //See: https://github.com/moroshko/react-autosuggest
import QuickEntityViewer from './QuickEntityViewer';


import Entity from './Types/Entity';
import FlexModal from '../FlexModal';
import IDUtil from '../../util/IDUtil';
import SearchAPI from '../../api/SearchAPI'
import debounce from 'debounce';

import classNames from 'classnames';

export default class SearchTermInput extends React.PureComponent {

    constructor(props) {
        super(props);
        this.xhrs = [];
        this.getSuggestions = debounce(this.getSuggestions.bind(this), 400); //no debouncing as gives annoying behaviour when e.g. type 'thom' quite fast, and only get results for 'tho'

        this.state = {
            vocabulary: this.__getAutocompleteParam('person', 'autocompleteVocabulary', ''),
            value: this.props.term, //the label of the selected classification (autocomplete)
            suggestions: [], //current list of suggestions shown
            isLoading: false, //loading the suggestions from the server
            entityID : null,
            showMoreInfoModal : false,
            entities: this.props.entities
            //TODO add property that holds the entity type!! Now it's rigged for persons only
        };
    }

    __getAutocompleteMapping = entityType => {
        if(!this.props.collectionConfig || !this.props.collectionConfig.getEntityConfig() ||
            !this.props.collectionConfig.getEntityConfig()[entityType]) {
            return null;
        }
        return this.props.collectionConfig.getEntityConfig()[entityType]['autocompleteConfig'];
    };

    __getAutocompleteParam = (entityType, param, defaultNullValue=null) => {
        const mapping = this.__getAutocompleteMapping(entityType);
        return mapping ? mapping[param] : defaultNullValue;
    };

    /* --------------- ANNOTATION CLIENT EVENT HANDLING -------------- */

    componentWillUnmount = () => {
        //cancel all previous outgoing requests
        for (let x = this.xhrs.length; x > 0; x--) {
            this.xhrs[x - 1].abort();
            this.xhrs.pop();
        }
    };

    /* ------------------- CRUD / loading of classifications ------------------- */

    getSuggestions = (value, callback) => {
        //cancel all previous outgoing requests
        for (let x = this.xhrs.length; x > 0; x--) {
            this.xhrs[x - 1].abort();
            this.xhrs.pop();
        }

        const autocompleteParams = this.__getAutocompleteParam('person', 'autocompleteParams')

        //get autocomplete results for persons
        const xhr = SearchAPI.autocomplete(
            this.state.vocabulary,
            value,
            autocompleteParams && autocompleteParams['Method'] ?
                autocompleteParams['Method'] :
                '',
            autocompleteParams && autocompleteParams['Fields'] ?
                autocompleteParams['Fields'] :
                '',
            autocompleteParams && autocompleteParams['Lang'] ?
                autocompleteParams['Lang'] :
                '',
            callback
        );

        this.xhrs.push(xhr);
    };

    /* ------------------- REACT-AUTOSUGGEST FUNCTIONS ------------------- */

    //when the user clicks on the icon in the autocomplete information, show more information
    onMoreInfo = e => {
        const button = e.currentTarget;
        e.stopPropagation(); //avoid the suggestion being selected
        this.setState({
            entityID: button.value,
            showMoreInfoModal : true
        });
    };

    loadSuggestions = value => {
        this.setState({
            isLoading: true,
            suggestions: [],
        });
        if (value.value === this.state.chosenValue) {
            this.setState({
                isLoading: false,
            });
        } else {
            this.getSuggestions(value.value, (data) => {
                if (!data || data.error || !Array.isArray(data)) {
                    this.setState({
                        isLoading: false,
                        suggestions: [],
                    });
                    //console.error("Autocomplete failed");
                } else {

                    this.setState({
                        isLoading: false,
                        suggestions: data,
                    });
                }
            });
        }
    };

    onSuggestionsFetchRequested = inputValue => {

        //currently not checking field categories as autocomplete is always on
        //Leaving the code here so that if we later have autocomplete for
        //more than just persons, then we can select the best autocomplete given
        //the selected field cluster
        //if(!this.props.fieldCategories) return;
        //check if the a person-related field category has been selected
        //const selection = this.props.fieldCategories.map(({ value }) => value);
        //const personFieldCategories = this.__getAutocompleteParam('person', 'fieldClusters', []);

        if (!this.state.vocabulary) return;

        this.loadSuggestions(inputValue)

    };

    onSuggestionsClearRequested = () => this.setState({ suggestions: [] });

    getSuggestionValue = suggestion => {
        return ""; //as we do not fill in the selected suggestion in the input, but as a tag
    };

    onSuggestionSelected = (e, suggestion) => {
        this.state.entities.push({
                        id: suggestion.suggestion.value,
                        label: suggestion.suggestion.label.split("|")[0].trim(),
                        type: suggestion.suggestion.label.split("|")[1].trim(),
                        otherLabels: suggestion.suggestion.label.split("|")[3].trim(),
                        });

        if (this.props.onSuggestionOutput) {
            this.props.onSuggestionOutput(this.constructor.name, this.state.entities);
        }
    }

    //TODO the rendering should be adapted for different vocabularies
    renderSuggestion = suggestion => {
        const arr = suggestion.label.split("|");
        const scopeNote = arr[2] ? "(" + arr[2] + ")" : "";
        return (
            <span>
                {arr[0]}&nbsp;{scopeNote}
                 <button
                    className="btn btn-default"
                    onClick={this.onMoreInfo}
                    title="More information"
                    value={suggestion.value}
                >
                    <span className="link-more-info" />
                </button>
            </span>
        );
    };

    deleteEntity = e => {
        const index = this.state.entities.indexOf(e);
        if (index > -1) {
          this.state.entities.splice(index, 1);
        }
        if (this.props.onSuggestionOutput) {
            this.props.onSuggestionOutput(this.constructor.name, this.state.entities);
        }
    }

    onChange(event, { newValue }) {
        //update the state when the user enters text
        this.setState({
            chosenValue: newValue,
            value: newValue,
        });

    }

    onKeyDown = (event) => {
        //search when the user clicks 'Enter'
        if(event.key == "Enter") {
            this.props.newSearch(this.state.value);
        }
    };

    onSubmit = (e) => {
    //search when the user presses the Search button
        e.preventDefault();
        this.props.newSearch(this.state.value);
    };

    /* ------------------- QUICK ENTITY VIEWER ------------------- */

    openMoreInfoModal = entityID => {
        this.setState({
            entityID: entityID,
            showMoreInfoModal : true
        });
    };

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

    //this is the pop-up that appears when a user clicks the 'more info' icon in a search autocomplete suggestion
    renderMoreInfoModal = (entityID, collectionConfig) => {
        return (
            <FlexModal
                elementId="moreinfo__modal"
                stateVariable="showMoreInfoModal"
                owner={this}
                size="medium"
                title={"Person information"}>
                <QuickEntityViewer
                    entityID={entityID}
                    entityType="person"
                    collectionConfig={collectionConfig}
                    fieldCategories={this.props.fieldCategories ? this.props.fieldCategories : []}
                />
            </FlexModal>
        )
    };

    render() {

        const inputProps = {
            placeholder: "Search",
            value: this.state.value,
            onChange: this.onChange.bind(this),
            onKeyDown: this.onKeyDown.bind(this) //add this to detect pressing 'Enter'
        };

        // the selected entities
        const selectedEntities = (
            <div className={"type-annotations"}>
                {this.props.entities.map((entity, index) =>{
                    return (
                        <Entity
                            key={"entity_" + index}
                            entity={entity}
                            delete={this.deleteEntity.bind(this)}
                        />
                    );
                    }
                )}
            </div>
        );

        const moreInfoModal = this.state.showMoreInfoModal && this.state.entityID ? this.renderMoreInfoModal(
            this.state.entityID,
            this.props.collectionConfig
        ) : null;

        return (
            <div className={IDUtil.cssClassName('search-term-input')}>
                <div className="entity-input">
                    <div className="entity-autosuggest">
                        <Autosuggest
                            suggestions={this.state.suggestions}
                            onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
                            onSuggestionsClearRequested={this.onSuggestionsClearRequested}
                            getSuggestionValue={this.getSuggestionValue}
                            renderSuggestion={this.renderSuggestion}
                            inputProps={inputProps}
                            onSuggestionSelected={this.onSuggestionSelected}
                        />
                    </div>
                    <div className="entity-display">
                    {selectedEntities}
                    </div>
                </div>
                <span onClick={this.onSubmit} className="">
				    <i className="fas fa-search" />
				</span>
                {moreInfoModal}
			</div>
        );
    }

}

SearchTermInput.propTypes = {
    fieldCategories: PropTypes.array.isRequired, //which field clusters/categories are selected
    entities: PropTypes.array.isRequired,
    term: PropTypes.string.isRequired,
    collectionConfig: PropTypes.object.isRequired,
    newSearch: PropTypes.func.isRequired,
    onSuggestionOutput: PropTypes.func.isRequired
};
