import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import IDUtil from '../../../util/IDUtil';
import TargetHeader from './TargetHeader';
import Segment from './Segment';
import SelectionTemporalForm from './SelectionTemporalForm';
import SelectionSpatialForm from './SelectionSpatialForm';
import Strings from '../_Strings';

import { AnnotationEvents } from '../AnnotationClient';
import {
    SELECTION_TEMPORAL,
    SELECTION_SPATIAL,
    ANNOTATION_COLUMN_SEGMENT_ID
} from './Constants';

export default class SegmentAnnotations extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            showForm: false,
            selectionType: this.getSelectionType(this.props.mediaObject)
        };

        this.lastActiveAnnotationId = '';
    }

    componentDidMount() {
        this.props.annotationClient.events.bind(
            AnnotationEvents.ON_SET_ANNOTATION,
            this.onUpdate
        );
    }

    componentWillUnmount() {
        this.props.annotationClient.events.unbind(
            AnnotationEvents.ON_SET_ANNOTATION,
            this.onUpdate
        );
    }

    onUpdate = data => {
        if (data && data.annotation && data.annotation.id) {
            // skip if already active
            if (this.lastActiveAnnotationId == data.annotation.id) {
                return;
            }

            // scroll segment into view
            const elem = document.getElementById(
                ANNOTATION_COLUMN_SEGMENT_ID + data.annotation.id
            );
            if (elem) {
                elem.scrollIntoView();
                this.lastActiveAnnotationId = data.annotation.id;
            }
        }
    };

    getSelectionType(mediaObject) {
        const mimeType = mediaObject.mimeType;
        switch (true) {
            case mimeType.startsWith('video'):
            case mimeType.startsWith('audio'):
                return SELECTION_TEMPORAL;
            case mimeType.startsWith('image'):
                return SELECTION_SPATIAL;
            default:
                console.error(
                    'Could not create selection from mimeType: ' + mimeType
                );
                return '';
        }
    }

    toggle = () => {
        this.props.toggle(this.props.target);
    };

    // Create a new segment, set it to 0:00
    async createSegment(selection) {
        // set activeAnnotation to null, so a new root annotation is created & activated (in saveSelection)
        this.props.annotationClient.activeAnnotation = null;

        // Create and activate a new segment
        await this.props.annotationClient.saveSelection(selection);
    }

    // Update segment with given selection
    // If the selection is null, delete the segment
    async updateSegment(segment, selection) {
        // When the selection is null: delete the segment
        if (selection == null) {
            this.props.annotationClient.delete(segment);
            return;
        }

        // make the segment the active annotation, so it will be updated
        this.props.annotationClient.activeAnnotation = segment;

        // set the active selection
        this.props.annotationClient.activeSelection = selection;

        // Update the segment
        await this.props.annotationClient.saveSelection(selection);
    }

    onUpdateSegment = (segment, selection) => {
        console.debug('UPDATE SEGMENT', segment, selection);
        this.updateSegment(segment, selection);
    };

    onAddSegment = selection => {
        this.createSegment(selection);
    };

    createTemporalSelection = (start, end) => ({
        type: 'temporal',
        start,
        end
    });

    createSpatialSelection = (x, y, w, h) => ({
        type: 'spatial',
        rect: { x, y, w, h }
    });

    createSelection(selectionType) {
        switch (selectionType) {
            case SELECTION_TEMPORAL:
                return this.createTemporalSelection(0, 0);
            case SELECTION_SPATIAL:
                return this.createSpatialSelection(0, 0, 0, 0);
            default:
                console.error(
                    'Could not create selection for type',
                    selectionType
                );
        }
    }

    toggleForm = () => {
        this.setState({ showForm: !this.state.showForm });
    };

    renderForm(selection) {
        switch (selection.type) {
            case SELECTION_TEMPORAL:
                return (
                    <SelectionTemporalForm
                        selection={selection}
                        onUpdate={this.onAddSegment}
                    />
                );
            case SELECTION_SPATIAL:
                return (
                    <SelectionSpatialForm
                        selection={selection}
                        onUpdate={this.onAddSegment}
                    />
                );
            default:
                console.error('Could not render form for type ', selectionType);
        }
    }

    sortSegments = (segments, selectionType) => {
        switch (selectionType) {
            case SELECTION_TEMPORAL:
                // start -> end
                return segments.sort((a, b) => {
                    a = a.target.selector.refinedBy;
                    b = b.target.selector.refinedBy;
                    if (a.start == b.start) {
                        return a.end - b.end;
                    }
                    return a.start - b.start;
                });
            case SELECTION_SPATIAL:
                // top -> down
                return segments.sort((a, b) => {
                    a = a.target.selector.refinedBy.rect;
                    b = b.target.selector.refinedBy.rect;
                    if (a.y == b.y) {
                        return a.x - b.x;
                    }
                    return a.y - b.y;
                });
            default:
                console.error('Could not sort on selectionType', selectionType);
                return segments;
        }
    };

    render() {
        // count

        const count = this.props.segments
            ? this.props.segments.reduce(
                  (c, segment) => c + (segment.body ? segment.body.length : 0),
                  0
              )
            : 0;

        // header
        const header = (
            <TargetHeader
                active={this.props.active}
                onToggle={this.toggle}
                title={this.props.title}
                count={count}
                icon={this.props.icon}
            />
        );

        // Actions/layer top level
        const actions = this.props.active ? (
            <div className="actions">
                <span>My Segments</span>
                <div
                    className={classNames('add', {
                        active: this.state.showForm
                    })}
                    onClick={this.toggleForm}
                    title={
                        this.state.showForm
                            ? Strings.SEGMENT_ADD_STOP
                            : Strings.SEGMENT_ADD
                    }
                ></div>
            </div>
        ) : null;

        // Form
        const form =
            this.props.active && this.state.showForm
                ? this.renderForm(
                      this.createSelection(this.state.selectionType)
                  )
                : null;

        // All segments
        const segments = this.props.active
            ? this.sortSegments(
                  this.props.segments,
                  this.state.selectionType
              ).map(segment => (
                  <Segment
                      key={segment.id}
                      segment={segment}
                      updateSegment={this.onUpdateSegment}
                      {...this.props}
                  />
              ))
            : null;

        return (
            <div
                className={classNames(
                    IDUtil.cssClassName('segment-annotations')
                )}
            >
                {header}
                {actions}
                {form}
                {segments}
            </div>
        );
    }
}

SegmentAnnotations.propTypes = {
    annotationClient: PropTypes.object.isRequired,
    title: PropTypes.string.isRequired,
    icon: PropTypes.object.isRequired,
    toggle: PropTypes.func.isRequired,
    active: PropTypes.bool.isRequired,
    activeTypes: PropTypes.arrayOf(PropTypes.string).isRequired,
    segments: PropTypes.arrayOf(PropTypes.object),
    mediaObject: PropTypes.object.isRequired
};
