import React from 'react';
import ReactTooltip from 'react-tooltip'; //https://www.npmjs.com/package/react-tooltip
import CreatableSelect from 'react-select/creatable';
import { components } from 'react-select';

import IDUtil from '../../util/IDUtil';
import ComponentUtil from '../../util/ComponentUtil';
import FlexModal from '../FlexModal';
import FieldCategoryCreator from './FieldCategoryCreator';

export default class FieldCategorySelector extends React.Component {

	constructor(props) {
		super(props);

		this.state = {
			showModal : false,
            clusterName : null
		};
		this.CLASS_PREFIX = 'fcs';
	}

	onComponentOutput = (componentClass, data) => {
		if(componentClass === 'FieldCategoryCreator') {
			this.onCustomFieldsSelected(data);
		}
	};

	onOutput(data) {
		if(this.props.onOutput) {
			if(data !== null) {
                this.props.onOutput(this.constructor.name, data);
			} else {
                this.props.onOutput(this.constructor.name, null);
            }
		}
	}

    handleChange = ({ options }) => {
    	let found = false;
    	const tmp = {};
    	for(let i=0;i<options.length;i++) {
    		const fc = options[i];
    		if(tmp[fc.id]) {
    			found = true;
    			break;
    		}
    		tmp[fc.id] = true;
    	}
		if(!found) {
			this.onOutput(options);
	    }
    }

    onCustomFieldsSelected(data) {
    	ComponentUtil.hideModal(this, 'showBookmarkModal', 'fields__modal', true, () => {
    		const fields = this.props.fieldCategory || [];
    		if(data) { //when nothing was selected, it is no use to update the owner
	    		fields.push(data);
	    		this.onOutput(fields)
	    	}
    	});
    }

    onSelectFieldCategories = (options, { action }) => {
        if(['select-option', 'remove-value'].indexOf(action) !== -1) {
            let found = false;
            const tmp = {};
            for(let i=0;i<options.length;i++) {
                const fc = options[i];
                if(tmp[fc.value]) {
                    found = true;
                    break;
                }
                tmp[fc.value] = true;
            }
            if(!found) {
                this.onOutput(options);
            }
        }
    };

    //TODO finish properly wiring up the custom field cluster stuff
    openFieldClusterCreator = inputValue => {
        this.setState({ showModal: true, clusterName : inputValue});
    };

    renderSelector = (queryId, collectionConfig, allOptions, selectedOptions) => {
        //console.debug('NOW THESE ARE ALL OPTIONS', allOptions, selectedOptions);
        const onTopOfSearchResults = {
            menu: styles => ({ ...styles, 'z-index': 999999 })
        }
        return (
            <CreatableSelect
                isMulti
                //placeholder="Type to find or create a new search filter"
                options={allOptions}
                value={selectedOptions}
                components={{MultiValueLabel}}
                onCreateOption={this.openFieldClusterCreator}
                onChange={this.onSelectFieldCategories}
                styles={onTopOfSearchResults}
            />
        )
    };

    renderSelectionModal = (collectionConfig, fcCreatorCallback, clusterName) => {
        const allTextFields = collectionConfig ? collectionConfig.getStringFields() : null;
        if(!allTextFields) return null;

        return (
            <FlexModal
                size="large"
                elementId="fields__modal"
                stateVariable="showModal"
                owner={this}
                title="Create a new cluster of metadata fields to narrow down search">
                <FieldCategoryCreator clusterName={clusterName} data={
                    allTextFields.map(field => (
                        {'value': field, 'prettyName': collectionConfig.toPrettyFieldName(field)}
                    ))
                } onOutput={fcCreatorCallback}/>
            </FlexModal>
        );
    };

    //returns all possible options for the user, react-select will figure out what remains in the drop-down list
    getAllOptions = (collectionConfig, selectedOptions) => {
        //include the configured options
        const allOptions = collectionConfig && collectionConfig.getMetadataFieldCategories() ?
            collectionConfig.getMetadataFieldCategories() :
            []
        ;
        const allMetadataOption = this.__generateAllMetadataFieldCategory(this.props.collectionConfig)
        if(allMetadataOption) {
            allOptions.unshift(allMetadataOption);
        }

        allOptions.push(...this.__extractCustomOptions(selectedOptions));

        //map the options to the desired object
        return this.__toOptionGroups(allOptions);
    };

    __extractCustomOptions = selectedOptions => {
        if(!selectedOptions)return [];

        return selectedOptions.filter(fc => fc.value && fc.value.indexOf('customfc__') !== -1);
    };

    //this function should return ALL possible options and not care about which are selected
    __toOptionGroups = allOptions => {
        const enrichments = allOptions.filter(fc => fc.enrichment);
        const metadataFields = allOptions.filter(fc => !fc.enrichment);

        const METADATA_LABEL = "-- Archive's metadata --";
        const ENRICHMENT_LABEL = "-- Enrichments --";

        const optionGroups = [];

        if(metadataFields.length > 0) {
            optionGroups.push({'label' : METADATA_LABEL, 'options' : metadataFields.map(this.__toFilterOption)});
        }
        if(enrichments.length > 0) {
            optionGroups.push({'label' : ENRICHMENT_LABEL, 'options' : enrichments.map(this.__toFilterOption)});
        }
        return optionGroups;
    }

    __toFilterOption = fieldCategory => ({
        value: fieldCategory.value ? fieldCategory.value : fieldCategory.id,
        label: fieldCategory.label,
        fields: fieldCategory.fields,
        nestedPath : fieldCategory.nestedPath
    });

    //based on the available string fields and configured enrichments fields, yields a list of all metadata fields
    __generateAllMetadataFieldCategory = collectionConfig => {
        const allTextFields = collectionConfig ? collectionConfig.getStringFields() : null;
        if(!allTextFields || allTextFields.length <= 0) return null;

        //now filter out the known (configured) enrichment fields out of the list of all string fields
        const configuredOptions = collectionConfig && collectionConfig.getMetadataFieldCategories() ?
            collectionConfig.getMetadataFieldCategories() :
            []
        ;
        const fieldsToIgnore =  [...configuredOptions.filter(el => el.enrichment)].map(i => i.fields).flat();
        const nonEnrichedMetadata = fieldsToIgnore.length ? fieldsToIgnore.map(
            ignoreItem => allTextFields.indexOf(ignoreItem) !== -1 ?
                allTextFields.filter(e => e !== ignoreItem)
                : null
            ).flat() :
            null
        ;
        return {
            value: "allMetadata",
            label: "All metadata fields",
            fields: nonEnrichedMetadata ? nonEnrichedMetadata : allTextFields
        }
    }

	render() {
        //render the modal for creating new field clusters
        const fieldSelectionModal = this.state.showModal ? this.renderSelectionModal(
            this.props.collectionConfig,
            this.onComponentOutput,
            this.state.clusterName
        ) : null;

        const allOptions = this.getAllOptions(this.props.collectionConfig, this.props.fieldCategory)

		const fieldCategorySelector = this.renderSelector(
            this.props.queryId,
            this.props.collectionConfig,
            allOptions, //all possible options (with "value")
            this.props.fieldCategory //selected optoins
        );


		return (
            <div className={IDUtil.cssClassName('field-category-selector')}>
                {fieldCategorySelector}
                <ReactTooltip id={'__fs__tt' + this.props.queryId} />
                {fieldSelectionModal}
            </div>
        )
	}
}

//custom component, representing a selected field categories WITH tooltips for enclosed metadata fields
export const MultiValueLabel = props => {
    const optionId = 'tt__' + props.data.value;
    return (
        <components.MultiValueLabel {...props}>
            <a data-tip="true" data-for={optionId}>{props.data.label}</a>
            <ReactTooltip id={optionId}>
                    {props.data.fields.map(f => <span key={f}>{f}<br/></span>)}
            </ReactTooltip>
        </components.MultiValueLabel>

    );
};
