import React from 'react';
import PropTypes from 'prop-types';
import IDUtil from '../../../util/IDUtil';
import IconUtil from '../../../util/IconUtil';
import { InformationCardUtil } from '../AnnotationClient';

/*
TODO (old comment):
	- validate the config that is passed, see the metadata block in e.g. arttube-item-details.json
	- gracefully deal with the fact that the template is not stored in the annotation (which makes it impossible to fill
	the dropdown box with the template that was used to create the annotation)
*/

const NO_TEMPLATE = 'NO_TEMPLATE';

export default class MetadataForm extends React.PureComponent {
    constructor(props) {
        super(props);

        const activeCard = this.props.card
            ? JSON.parse(JSON.stringify(this.props.card)) // deep copy
            : null;

        const templates = InformationCardUtil.determinePossibleTemplates(
            this.props.annotationClient.config.motivationConfig['metadata'],
            this.props.annotation
        );

        let activeTemplate = templates ? templates[0] : ''; //default
        if (activeCard && activeCard.annotationTemplate) {
            activeTemplate = this.getTemplateById(
                templates,
                activeCard.annotationTemplate
            );
        }

        //TODO also fetch these from the annotation client rather than adding it to the state
        this.state = {
            new: !activeCard,
            activeCard: activeCard || this.createEmptyCard(activeTemplate),
            templates: templates, //list of templates
            activeTemplate: activeTemplate,
            singleCardMode: InformationCardUtil.determineSingleCardMode(
                this.props.annotationClient.config.motivationConfig['metadata'],
                this.props.annotation
            )
        };
        this.CLASS_PREFIX = 'icf';
    }

    /* --------------- RELATED TO (ACTIVE) TEMPLATES --------------*/

    setActiveTemplate = e => {
        // template
        const templateId = e.target.value;
        const activeTemplate =
            templateId === NO_TEMPLATE
                ? ''
                : this.getTemplateById(this.state.templates, templateId);

        // create a new empty card with the active template
        const activeCard = this.createEmptyCard(activeTemplate);

        // add additional property fields
        this.state.activeCard.properties.forEach(property => {
            if (
                !activeCard.properties.some(p => {
                    if (p.key == property.key) {
                        // update value
                        p.value = property.value;
                        return true;
                    }
                    return false;
                })
            ) {
                // add missing property
                activeCard.properties.push(property);
            }
        });

        this.setState({
            activeTemplate,
            activeCard
        });
    };

    getTemplateById(templates, templateId) {
        if (templates) {
            const temp = templates.filter(t => {
                return t.id == templateId;
            });
            if (temp.length > 0) {
                return temp[0];
            }
        }
        return '';
    }

    // If the card is based on a template (and has the annotationTemplate property), check if there is a
    // type configured for the kind of input field
    getInputFieldType(configuredTemplates, card, property) {
        let fieldType = 'string';
        if (card && card.annotationTemplate) {
            const t = configuredTemplates[card.annotationTemplate];
            if (t && t.properties) {
                const tmp = t.properties.filter(p => {
                    return p.key == property;
                });
                if (tmp.length == 1 && tmp[0].type) {
                    fieldType = tmp[0].type;
                }
            }
        }
        return fieldType;
    }

    isTemplateLocked(template) {
        return template && template.locked;
    }

    /* --------------- CRUD ON CARDS -------------------- */

    async saveCard(card) {
        //(if there is an active template) attach the selected template ID to the annotation/card (otherwise remove it)
        if (this.state.activeTemplate) {
            card.annotationTemplate = this.state.activeTemplate.id;
        } else if (card.hasOwnProperty('annotationTemplate')) {
            delete card['annotationTemplate'];
        }

        const saveData = await this.props.annotationClient.saveBodyElement(
            Object.assign({ annotationType: 'metadata' }, card),
            false,
            true,
            this.props.annotation
        );

        return new Promise(resolve => {
            resolve(saveData);
        });
    }

    setCard(activeCard) {
        this.setState({ activeCard });
    }

    /* --------------- CRUD ON PROPERTIES -------------------- */

    addProperty = e => {
        e.preventDefault();
        const card = Object.assign({}, this.state.activeCard);
        card.properties.push({ key: '', value: '' });
        this.setCard(card);
    };

    createEmptyCard(template) {
        return template
            ? {
                  annotationTemplate: template,
                  properties: template.properties.map(prop => {
                      return { key: prop.key, value: '' };
                  })
              }
            : { annotationTemplate: template, properties: [] };
    }

    updateProperty(index, isKey, e) {
        const card = Object.assign({}, this.state.activeCard);

        if (isKey) {
            card.properties[index].key = e.target.value;
        } else {
            card.properties[index].value = e.target.value;
        }
        this.setCard(card);

        // save on enter key
        if (e.keyCode === 13) {
            this.saveCard(card).then(() => {
                this.props.onSave();
            });
        }
    }

    removeProperty(index, e) {
        const card = Object.assign({}, this.state.activeCard);
        card.properties.splice(index, 1);
        this.setCard(card);
    }

    onSave = () => {
        this.saveCard(this.state.activeCard).then(saveData => {
            this.props.onSave();
        });
    };

    renderFormFields = (
        activeCard,
        activeTemplate,
        isTemplateLocked,
        updatePropFunc
    ) => {
        const templateProperties = activeTemplate
            ? this.createEmptyCard(activeTemplate)
            : '';

        const formProperties = activeCard
            ? activeCard.properties
            : templateProperties;

        if (!formProperties) return null;

        return formProperties.map((prop, i) => {
            const inputField =
                this.getInputFieldType(
                    this.props.annotationClient.config.motivationConfig[
                        'metadata'
                    ],
                    activeCard,
                    prop.key
                ) === 'markdown' ? (
                    <textarea
                        value={prop.value}
                        rows="5"
                        onChange={updatePropFunc.bind(this, i, false)}
                    ></textarea>
                ) : (
                    <input
                        type="text"
                        value={prop.value}
                        onChange={updatePropFunc.bind(this, i, false)}
                    />
                );

            //only add delete buttons and editable property fields when the template is not locked
            const delPropBtn = !isTemplateLocked ? (
                <div className="remove-prop">
                    <span
                        className={IconUtil.getUserActionIcon(
                            'remove',
                            false,
                            false,
                            true
                        )}
                        onClick={this.removeProperty.bind(this, i)}
                    ></span>
                </div>
            ) : null;

            const propertyField = isTemplateLocked ? (
                <strong>{prop.key}</strong>
            ) : (
                <input
                    type="text"
                    value={prop.key}
                    onChange={updatePropFunc.bind(this, i, true)}
                />
            );
            //assemble the elements into the eventual form
            return (
                <div key={'prop__' + i} className="card-row">
                    <div className="card-key">{propertyField}</div>
                    <div className="card-value">{inputField}</div>
                    {delPropBtn}
                </div>
            );
        });
    };

    renderTemplateSelector = (
        templates,
        activeTemplate,
        setActiveTemplateFunc
    ) => {
        const templateOptions = Object.keys(templates).map(key => {
            const t = templates[key];
            return (
                <option key={t.id + '__option'} value={t.id}>
                    {t.label}
                </option>
            );
        });

        //whenever no template is used/defined
        templateOptions.splice(
            0,
            0,
            <option key="null__option" value={NO_TEMPLATE}>
                No template
            </option>
        );

        return (
            <div className="filter">
                <strong>Template: </strong>
                <select
                    value={activeTemplate ? activeTemplate.id : NO_TEMPLATE}
                    onChange={setActiveTemplateFunc}
                >
                    {templateOptions}
                </select>
            </div>
        );
    };

    render() {
        const isTemplateBlocked = this.isTemplateLocked(
            this.state.activeTemplate
        );

        const formFields = this.renderFormFields(
            this.state.activeCard,
            this.state.activeTemplate,
            isTemplateBlocked,
            this.updateProperty
        );

        //draw the template selector (if any have been defined)
        const templateSelect = this.state.templates
            ? this.renderTemplateSelector(
                  this.state.templates,
                  this.state.activeTemplate,
                  this.setActiveTemplate
              )
            : null;

        //draw the add property button if the template is not locked
        const addPropBtn = !isTemplateBlocked ? (
            <div className="add-property" onClick={this.addProperty}>
                <span
                    className={IconUtil.getUserActionIcon(
                        'add',
                        false,
                        false,
                        true
                    )}
                ></span>
                &nbsp; Add property
            </div>
        ) : null;

        // draw the save button
        const saveBtn = (
            <div className="save-button" onClick={this.onSave}>
                Save
            </div>
        );

        // draw the cancel button
        const cancelBtn = (
            <div className="cancel-button" onClick={this.props.onSave}>
                Cancel
            </div>
        );

        const cardForm = formFields ? (
            <div className="card-form">
                {templateSelect}
                <div className="card-fields">{formFields}</div>
                <div className="actions">
                    {addPropBtn}
                    {cancelBtn}
                    {saveBtn}
                </div>
            </div>
        ) : null;

        return (
            <div className={IDUtil.cssClassName('metadata-form')}>
                {cardForm}
            </div>
        );
    }
}

MetadataForm.propTypes = {
    annotationClient: PropTypes.object.isRequired,
    annotation: PropTypes.object.isRequired,
    card: PropTypes.object,
    onSave: PropTypes.func.isRequired
};
