import React from "react";
import PropTypes from "prop-types";

import IconUtil from "../../../util/IconUtil";
import IDUtil from "../../../util/IDUtil";
import SessionStorageHandler from "../../../util/SessionStorageHandler";

import Strings from "../_Strings";
import Info from "../../shared/Info";

import { AnnotationEvents } from "../AnnotationClient";

import SingleAnnotationTarget from "./SingleAnnotationTarget";
import AnnotationFilter from "./AnnotationFilter";
import SegmentAnnotations from "./SegmentAnnotations";
import TargetHeader from "./TargetHeader";

import {
    ANNOTATION_TARGET,
    SESSION_STORAGE_ACTIVE_TARGETS,
} from "../../../util/AnnotationConstants";

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

        // get active targets from session storage
        const activeTargets = SessionStorageHandler.getSplit(
            SESSION_STORAGE_ACTIVE_TARGETS
        );

        // initial state
        this.state = {
            activeTargets,
            activeLayers: [],
        };

        // Annotation events to listen to
        this.annotationEvents = [
            AnnotationEvents.ON_SET_ANNOTATION,
            AnnotationEvents.ON_SAVE,
            AnnotationEvents.ON_DELETE,
            AnnotationEvents.ON_CHANGE_TARGET,
        ];

        this.segmentTitleInput = React.createRef();
    }

    componentDidMount() {
        // Bind to annotation updates
        this.annotationEvents.forEach((event) => {
            this.props.annotationClient.events.bind(event, this.onUpdate);
        });
    }

    componentWillUnmount() {
        // Unbind annotation updatess
        this.annotationEvents.forEach((event) => {
            this.props.annotationClient.events.unbind(event, this.onUpdate);
        });
    }

    onUpdate = () => this.forceUpdate();

    // Wrapper function for retrieving an annotation / all annotations for a given target
    getAnnotationsForTarget(allAnnotations, resource, mediaObject) {
        return (target) => {
            const annotations = allAnnotations.filter(
                (annotation) =>
                    // only with target type
                    annotation.target && annotation.target.type === target
            );

            // the checks on current resource/mediaobject are needed
            // as sometimes other annotations from the project seem to slip in
            switch (target) {
                case ANNOTATION_TARGET.RESOURCE: {
                    const result = annotations.filter(
                        (annotation) =>
                            // current resource
                            annotation.target.source == resource.resourceId
                    );
                    // check number of annotations
                    if (result.length > 1) {
                        console.error(
                            "Multiple root annotations for target " +
                                target +
                                ". Expecting 1 or 0"
                        );
                        console.debug(result);
                        // this.props.annotationClient.delete(result[1]);
                    }
                    if (result.length > 0) {
                        return result[0];
                    }
                    return null;
                }
                case ANNOTATION_TARGET.MEDIAOBJECT: {
                    let result = annotations.filter(
                        (annotation) =>
                            // current mediaObject
                            mediaObject &&
                            annotation.target.source == mediaObject.assetId
                    );

                    // // DEV: remove duplicate MediaObject annotations
                    // // You'll need this if you accidentially messed up selection creation and create multiple
                    // // annotations directly on the MediaObject (only 1 allowed)
                    // console.log(result);
                    // // The Media Object id tou want to keep
                    // const validMediaObjectAnnotationId =
                    //     "19f47bb8-5fe0-4452-9d78-78da9514ee77";
                    // // Delete unwanted
                    // result.forEach((r) => {
                    //     if (r.id !== validMediaObjectAnnotationId) {
                    //         console.log(r);
                    //         this.props.annotationClient.delete(r);
                    //     }
                    // });
                    // // Filter out unwanted for displaying
                    // result = result.filter(
                    //     (r) => r.id == validMediaObjectAnnotationId
                    // );

                    // check number of annotations
                    if (result.length > 1) {
                        console.error(
                            "Multiple root annotations for target " +
                                target +
                                ". Expecting 1 or 0"
                        );
                        console.debug(result);
                        // this.props.annotationClient.delete(result[1]);
                    }
                    if (result.length > 0) {
                        return result[0];
                    }
                    return null;
                }
                case ANNOTATION_TARGET.SEGMENT:
                    // can return multiple in an array
                    return annotations.filter((annotation) =>
                        // segment from current mediaObject
                        resource.playableContent.some(
                            (mo) => annotation.target.source == mo.assetId
                        )
                    );
                default:
                    console.error(
                        "Could not find annotations for type ",
                        target
                    );
                    return [];
            }
        };
    }

    /* ---------------------------------- UI FUNCTIONS -------------------------------- */

    // Toggle given target
    // Persist the state in session storage
    toggleTarget = (target) => {
        this.setState(
            {
                activeTargets: this.state.activeTargets.includes(target)
                    ? this.state.activeTargets.filter((l) => l != target)
                    : [target, ...this.state.activeTargets],
            },
            () => {
                // store active targets to session storage
                SessionStorageHandler.set(
                    SESSION_STORAGE_ACTIVE_TARGETS,
                    this.state.activeTargets.join(",")
                );
            }
        );
    };

    toggleSegmentsTarget = () => {
        this.toggleTarget(ANNOTATION_TARGET.SEGMENT);
    };

    toggleLayer = (layerId) => {
        this.setState({
            activeLayers: this.state.activeLayers.includes(layerId)
                ? this.state.activeLayers.filter((l) => l != layerId)
                : [layerId, ...this.state.activeLayers],
        });
    };

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

    renderNewSegmentLayer() {
        return (
            <div className="segment-actions">
                <input ref={this.segmentTitleInput} />

                <div
                    key="new-layer-button"
                    className="button-new-layer btn btn-primary"
                    onClick={() => {
                        this.props.annotationClient.segmentLayers.addLayer(
                            this.segmentTitleInput.current.value
                        );
                        this.segmentTitleInput.current.value = "";
                    }}
                >
                    {Strings.BUTTON_ADD_USER_LAYER}
                </div>
            </div>
        );
    }

    render() {
        const { resource, mediaObject, annotationClient } = this.props;

        // at least a resource is required
        if (!resource) {
            return null;
        }

        // all annotations for this project
        const annotations = annotationClient.annotations;

        // create a wrapper for getting all annotations per target
        // for the RESOURCE and MEDIAOBJECT targets, there should only be 1 annotation
        // for the SEGMENTS, there will be multiple
        const getAnnotations = this.getAnnotationsForTarget(
            annotations,
            resource,
            mediaObject
        );

        // Props used by all targets
        const defaultTargetProps = {
            annotationClient: annotationClient,
            activeTypes: this.props.activeAnnotationTypes,
            toggle: this.toggleTarget,
        };

        // Resource target annotations
        const resourceAnnotation = getAnnotations(ANNOTATION_TARGET.RESOURCE);
        const resourceActive = this.state.activeTargets.includes(
            ANNOTATION_TARGET.RESOURCE
        );
        const resourceTarget = (
            <SingleAnnotationTarget
                target={ANNOTATION_TARGET.RESOURCE}
                icon={
                    <Info
                        id="annotation-target-resource-help"
                        text={Strings.ANNOTATION_TARGET_HELP_RESOURCE}
                        className="black left"
                    />
                }
                title={Strings.ANNOTATION_TARGET_TITLE_RESOURCE}
                active={resourceActive}
                annotation={resourceAnnotation}
                {...defaultTargetProps}
            />
        );

        // Mediaobject target annotations
        const mediaObjectAnnotation = getAnnotations(
            ANNOTATION_TARGET.MEDIAOBJECT
        );
        const mediaObjectActive = this.state.activeTargets.includes(
            ANNOTATION_TARGET.MEDIAOBJECT
        );
        const mediaObjectTarget = this.props.mediaObject ? (
            <SingleAnnotationTarget
                target={ANNOTATION_TARGET.MEDIAOBJECT}
                icon={
                    <span
                        title={Strings.ANNOTATION_TARGET_HELP_MEDIAOBJECT}
                        className={IconUtil.getMimeTypeIcon(
                            this.props.mediaObject.mimeType,
                            false,
                            false,
                            false
                        )}
                    />
                }
                title={this.props.mediaObject.assetId}
                active={mediaObjectActive}
                annotation={mediaObjectAnnotation}
                {...defaultTargetProps}
            />
        ) : null;

        let segmentHeader = null;
        let segmentTargets = null;

        const segmentsActive = this.state.activeTargets.includes(
            ANNOTATION_TARGET.SEGMENT
        );
        // Segment header
        if (this.props.mediaObject) {
            segmentHeader = (
                <>
                    <TargetHeader
                        active={segmentsActive}
                        onToggle={this.toggleSegmentsTarget}
                        title={Strings.ANNOTATION_TARGET_TITLE_SEGMENT}
                        count={getAnnotations(ANNOTATION_TARGET.SEGMENT).length}
                        icon={
                            <Info
                                id="annotation-target-segment-help"
                                text={Strings.ANNOTATION_TARGET_HELP_SEGMENT}
                                className="black left"
                            />
                        }
                    />
                    {segmentsActive && this.renderNewSegmentLayer()}
                </>
            );
        }

        // Segments per layer
        if (this.props.mediaObject && segmentsActive) {
            // Segment target annotations per segment layer
            const layers = annotationClient.segmentLayers.getLayersSorted();

            segmentTargets = layers.map((layer) => {
                return (
                    <SegmentAnnotations
                        key={layer.id}
                        target={ANNOTATION_TARGET.SEGMENT}
                        layerId={layer.id}
                        title={layer.title}
                        active={this.state.activeLayers.includes(layer.id)}
                        segments={annotationClient.segmentLayers.getSegments(
                            layer.id
                        )}
                        mediaObject={this.props.mediaObject}
                        annotationClient={annotationClient}
                        activeTypes={this.props.activeAnnotationTypes}
                        toggle={this.toggleLayer}
                    />
                );
            });
        }

        // Full annotation list
        return (
            <div className={IDUtil.cssClassName("annotation-list")}>
                {/* All annotation targets */}
                <div className="targets">
                    {resourceTarget}
                    {mediaObjectTarget}
                    {segmentHeader}
                    {segmentTargets}
                </div>

                {/* Filter*/}
                <AnnotationFilter />
            </div>
        );
    }
}

AnnotationList.propTypes = {
    annotationClient: PropTypes.object.isRequired,
    activeAnnotationTypes: PropTypes.arrayOf(PropTypes.string).isRequired,

    mediaObject: PropTypes.object,
    resource: PropTypes.object,
};
