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 Classification from './Types/Classification';
import IDUtil from '../../../util/IDUtil';
import ExternalAPI from '../../../api/ExternalAPI';
import debounce from 'debounce';
import { AnnotationEvents } from '../AnnotationClient';

export default class ClassificationForm extends React.PureComponent {
    constructor(props) {
        super(props);
        this.config = this.props.annotationClient.config.motivationConfig[
            'classification'
        ];
        this.xhrs = [];
        this.getSuggestions = debounce(this.getSuggestions.bind(this), 400);

        this.state = {
            vocabulary: this.config.vocabularies
                ? this.config.vocabularies[0]
                : null,
            value: '', //the label of the selected classification (autocomplete)
            suggestionId: null, //stores the id/uri of the selected classification (e.g. GTAA URI)
            suggestions: [], //current list of suggestions shown
            isLoading: false //loading the suggestions from the server
        };
    }

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

    componentDidMount() {
        this.props.annotationClient.events.bind(
            AnnotationEvents.ON_SAVE,
            this.onSave
        );
    }

    componentWillUnmount() {
        this.props.annotationClient.events.unbind(
            AnnotationEvents.ON_SAVE,
            this.onSave
        );
    }

    onSave = () => {
        this.forceUpdate();
    };

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

    addClassification = e => {
        if (this.state.value != '') {
            let suggestionId = this.state.suggestionId;
            if (this.state.vocabulary && this.state.vocabulary == 'custom') {
                suggestionId = IDUtil.guid();
            }
            const classification = {
                id: suggestionId,
                label: this.state.value,
                vocabulary: this.state.vocabulary,
                annotationType: 'classification'
            };
            //after setting the state save the (annotation) body
            this.setState(
                {
                    value: '',
                    suggestionId: suggestionId
                },
                () => {
                    this.props.annotationClient.saveBodyElement(
                        classification,
                        false,
                        true,
                        this.props.annotation
                    );
                }
            );
        }
    };

    setVocabulary = event => this.setState({ vocabulary: event.target.value });

    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 xhr = ExternalAPI.autocomplete(
            this.state.vocabulary,
            value,
            callback
        );
        this.xhrs.push(xhr);
    }

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

    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) {
                    this.setState({
                        isLoading: false,
                        suggestions: []
                    });
                } else {
                    this.setState({
                        isLoading: false,
                        suggestions: data
                    });
                }
            });
        }
    };

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

    getSuggestionValue = suggestion => {
        this.setState({ suggestionId: suggestion.value });
        return suggestion.label.split('|')[0];
    };

    //TODO the rendering should be adapted for different vocabularies
    renderSuggestion = suggestion => {
        const arr = suggestion.label.split('|');
        let label = arr[1];
        const scopeNote = arr[2] ? '(' + arr[2] + ')' : '';
        if (this.state.vocabulary == 'GTAA') {
            switch (arr[1]) {
                case 'Persoon':
                    label = (
                        <span className="label label-warning">Persoon</span>
                    );
                    break;
                case 'Maker':
                    label = <span className="label label-warning">Maker</span>;
                    break;
                case 'Geografisch':
                    label = (
                        <span className="label label-success">Locatie</span>
                    );
                    break;
                case 'Naam':
                    label = <span className="label label-info">Naam</span>;
                    break;
                case 'Onderwerp':
                    label = (
                        <span className="label label-primary">Onderwerp</span>
                    );
                    break;
                case 'Genre':
                    label = <span className="label label-default">Genre</span>;
                    break;
                case 'B&G Onderwerp':
                    label = (
                        <span className="label label-danger">
                            B&G Onderwerp
                        </span>
                    );
                    break;
                default:
                    label = (
                        <span className="label label-default">Concept</span>
                    );
                    break;
            }
        } else if (this.state.vocabulary == 'DBpedia') {
            label = <span className="label label-default">Concept</span>;
        } else if (this.state.vocabulary == 'UNESCO') {
            switch (arr[1]) {
                case 'Education':
                    label = (
                        <span className="label label-warning">{arr[1]}</span>
                    );
                    break;
                case 'Science':
                    label = (
                        <span className="label label-warning">{arr[1]}</span>
                    );
                    break;
                case 'Social and human sciences':
                    label = (
                        <span className="label label-success">{arr[1]}</span>
                    );
                    break;
                case 'Information and communication':
                    label = <span className="label label-info">{arr[1]}</span>;
                    break;
                case 'Politics, law and economics':
                    label = (
                        <span className="label label-primary">{arr[1]}</span>
                    );
                    break;
                case 'Countries and country groupings':
                    label = (
                        <span className="label label-default">{arr[1]}</span>
                    );
                    break;
                default:
                    label = (
                        <span className="label label-default">{arr[1]}</span>
                    );
                    break;
            }
        }
        return (
            <span>
                {arr[0]}&nbsp;{label}&nbsp;{scopeNote}
            </span>
        );
    };

    onChange(event, { newValue }) {
        this.setState({
            chosenValue: newValue,
            value: newValue
        });
    }

    // after selection a suggestion, add it immediately
    onSelect = (e, { suggestionValue }) => {
        this.setState(
            {
                chosenValue: suggestionValue,
                value: suggestionValue
            },
            () => {
                this.addClassification();
            }
        );
    };

    onSubmit = e => {
        e.preventDefault();
        this.addClassification();
    };

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

    renderVocabularySelector = (
        vocabularies,
        activeVocabulary,
        setVocabFunc
    ) => {
        const options = vocabularies.map((v, index) => (
            <option key={'__v__' + index} value={v}>
                {v}
            </option>
        ));
        options.push(
            <option key="__v__custom" value="custom">
                Custom (no external lookup)
            </option>
        );
        return (
            <select value={activeVocabulary} onChange={setVocabFunc}>
                {options}
            </select>
        );
    };

    render() {
        const vocabSelector = this.renderVocabularySelector(
            this.config.vocabularies,
            this.state.vocabulary,
            this.setVocabulary
        );
        const inputProps = {
            placeholder: 'Search',
            value: this.state.value,
            onChange: this.onChange.bind(this)
        };

        return (
            <div className={IDUtil.cssClassName('classification-form')}>
                <form onSubmit={this.onSubmit}>
                    <div className="filter">
                        <strong>Vocabulary:</strong>
                        {vocabSelector}
                    </div>
                    <Autosuggest
                        ref={input => (this.classifications = input)}
                        suggestions={this.state.suggestions}
                        onSuggestionsFetchRequested={
                            this.onSuggestionsFetchRequested
                        }
                        onSuggestionsClearRequested={
                            this.onSuggestionsClearRequested
                        }
                        getSuggestionValue={this.getSuggestionValue}
                        renderSuggestion={this.renderSuggestion}
                        inputProps={inputProps}
                        onSuggestionSelected={this.onSelect}
                    />
                </form>
            </div>
        );
    }
}

ClassificationForm.propTypes = {
    annotationClient: PropTypes.object.isRequired,
    annotation: PropTypes.object.isRequired
};
