import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import IDUtil from '../../../util/IDUtil';
import { timeToString } from '../mediaColumn/timeline/_timeHelpers';

import { MSAnnotationUtil } from '../AnnotationClient';
import {
    SELECTION_TEMPORAL,
    SELECTION_SPATIAL,
    CLASSIFICATION,
    METADATA,
    COMMENT,
    LINK
} from './Constants';
import TimeInput from './TimeInput';
import Strings from '../_Strings';

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

        this.state = {
            edit: false
        };

        this.editSelection = null;
    }

    componentDidUpdate() {
        // stop edit mode when not highlighted
        if (!this.props.highlight && this.state.edit) {
            this.stopEdit();
        }
    }

    // INLINE EDITING

    // return an update function for editing a temporal selection
    updateTemporalEditSelection = field => {
        return value => {
            this.editSelection[field] = value;
        };
    };

    // return an update function for editing a spatial selection
    updateSpatialEditSelection = field => {
        return e => {
            this.editSelection.rect[field] = e.target.value;
        };
    };

    // return a save/setter function for the
    saveSelection = segment => {
        return () => {
            const selection = Object.assign({}, this.editSelection);
            this.props.updateSegment(segment, selection);

            this.stopEdit();
        };
    };

    // delete segment
    deleteSegment = segment => {
        return () => {
            if (!confirm(Strings.SEGMENT_DELETE_CONFIRM)) {
                return;
            }
            // sending null to the update function results in the segment getting deleted
            this.props.updateSegment(segment, null);

            this.stopEdit();
        };
    };

    onTitleClick = e => {
        e.stopPropagation();
        if (!this.props.highlight) {
            this.props.onSelect(this.props.segment);
        }
    };

    onTitleDoubleClick = e => {
        e.stopPropagation();
        this.setState({ edit: true });
    };

    stopEdit = () => {
        this.setState({ edit: false });
    };

    stopEvent = e => {
        e.stopPropagation();
    };

    // Get a title from segment annotations
    getSegmentTitle(segment, activeTypes) {
        if (!segment.body) return '';

        let result = '';

        let rank = 0;

        const ranks = {
            [METADATA]: 4,
            [CLASSIFICATION]: 3,
            [COMMENT]: 2,
            [LINK]: 1
        };

        // get title from
        segment.body
            // only active types, but always keep METADATA to use its title field
            .filter(
                body =>
                    body &&
                    (activeTypes.includes(body.annotationType) ||
                        body.annotationType == METADATA)
            )
            .some(body => {
                // only add if rank is higher or if result is empty
                if (
                    // lower rank
                    ranks[body.annotationType] < rank ||
                    // first run
                    (!result && rank > 0)
                ) {
                    return false;
                }

                let addition = '';
                // add correct title from each annotation type
                switch (body.annotationType) {
                    case METADATA:
                        // get title index
                        let titleIndex = -1;
                        if (
                            body.properties.some((property, index) => {
                                if (property.key == 'title') {
                                    titleIndex = index;
                                    return true;
                                }
                                return false;
                            })
                        ) {
                            if (body.properties[titleIndex].value) {
                                result = body.properties[titleIndex].value;
                                // break loop
                                return true;
                            }
                        }
                        break;
                    case CLASSIFICATION:
                        addition = body.label;
                        break;
                    case COMMENT:
                        addition = body.text ? body.text.slice(0, 100) : '';
                        break;
                    case LINK:
                        addition = body.label;
                        break;
                }

                // add addition to result
                if (result && rank == ranks[body.annotationType]) {
                    // append
                    result += ', ';
                    result += addition;
                } else {
                    // replace
                    result = addition;
                }

                rank = ranks[body.annotationType];
                return false;
            });

        // slice final result
        result = result ? result.slice(0, 100) : '';
        return result;
    }

    // Render form for inline editing
    renderForm = segment => {
        const selection = MSAnnotationUtil.extractSelectionFromTarget(
            segment.target
        );
        if (!selection) {
            console.error(
                'Could not find selection for target',
                segment.target
            );
            return null;
        }

        // store selection that is being edited
        this.editSelection = selection;

        const deleteButton = (
            <span className="delete" onClick={this.deleteSegment(segment)}>
                Delete
            </span>
        );

        switch (selection.type) {
            case SELECTION_TEMPORAL:
                return (
                    <div
                        className="form temporal"
                        onClick={this.stopEvent}
                        title={Strings.SEGMENT_TITLE_EDIT_SUBMIT}
                    >
                        <TimeInput
                            time={selection.start}
                            onUpdate={this.updateTemporalEditSelection('start')}
                            onFinish={this.saveSelection(segment)}
                        />
                        {' - '}
                        <TimeInput
                            time={selection.end}
                            onUpdate={this.updateTemporalEditSelection('end')}
                            onFinish={this.saveSelection(segment)}
                        />
                        {deleteButton}
                    </div>
                );
            case SELECTION_SPATIAL:
                const inputs = ['x', 'y', 'w', 'h'].map(v => (
                    <span key={v}>
                        <input
                            type="number"
                            ref={this[v]}
                            defaultValue={selection.rect[v]}
                            onFocus={e => {
                                e.target.select();
                            }}
                            onChange={this.updateSpatialEditSelection(v)}
                            onKeyDown={e => {
                                if (e.keyCode == 13) {
                                    this.saveSelection(segment)();
                                }
                            }}
                        />
                    </span>
                ));

                return (
                    <div
                        className="form spatial"
                        onClick={this.stopEvent}
                        title={Strings.SEGMENT_TITLE_EDIT_SUBMIT}
                    >
                        {inputs}
                        {deleteButton}
                    </div>
                );
            default:
                return null;
        }
    };

    renderTitle = (segment, activeTypes) => {
        // get selection data
        const selection = MSAnnotationUtil.extractSelectionFromTarget(
            segment.target
        );
        if (!selection) {
            console.error(
                'Could not find selection for target',
                segment.target
            );
            return null;
        }

        // get segment title, and prefix a space if found
        let segmentTitle = this.getSegmentTitle(segment, activeTypes);
        segmentTitle = segmentTitle ? ' ' + segmentTitle : '';

        switch (selection.type) {
            case SELECTION_TEMPORAL: {
                // mm:ss or hh:mm:ss if hours > 0
                return (
                    timeToString(selection.start) +
                    ' - ' +
                    timeToString(selection.end) +
                    segmentTitle
                );
            }
            case SELECTION_SPATIAL:
                const temp = [
                    selection.rect.x,
                    selection.rect.y,
                    selection.rect.w,
                    selection.rect.h
                ];
                return '◰ ' + temp.join(', ') + segmentTitle;
            default:
                return null;
        }
    };

    render() {
        // content is a titletext or an editable form
        const content = this.state.edit ? (
            // edit mode
            this.renderForm(this.props.segment)
        ) : (
            // view mode
            <span
                className="title"
                title={Strings.SEGMENT_TITLE_EDIT}
                onClick={this.onTitleClick}
                onDoubleClick={this.onTitleDoubleClick}
            >
                {this.renderTitle(this.props.segment, this.props.activeTypes)}
            </span>
        );

        return (
            <div
                className={classNames(IDUtil.cssClassName('segment-header'), {
                    active: this.props.active,
                    highlight: this.props.highlight
                })}
                onClick={this.props.onToggle}
            >
                <span className="left">{content}</span>
                <span className="count">
                    {this.props.segment.body
                        ? this.props.segment.body.length
                        : 0}
                </span>
            </div>
        );
    }
}

SegmentHeader.propTypes = {
    segment: PropTypes.object.isRequired,
    active: PropTypes.bool.isRequired,
    highlight: PropTypes.bool.isRequired,
    onToggle: PropTypes.func.isRequired,
    onSelect: PropTypes.func.isRequired,
    updateSegment: PropTypes.func.isRequired,
    activeTypes: PropTypes.array.isRequired
};
