import React from "react";
import invariant from "invariant";
import _isObject from "lodash.isobject";

import store from "./redux/store";

export default function(identifier, configure) {
    return function(Component) {
        const displayName = Component.displayName
            || Component.name
            || "Component";

        invariant(
            identifier && (typeof identifier === "string"
                || typeof identifier === "symbol"
                || typeof identifier === "function"),
            "Expected identifier to be string, symbol or function. See %s",
            displayName
        );

        if (configure) {
            invariant(
                typeof configure === "function",
                "Expected configure to be a function. See %s",
                displayName
            );
        }


        return React.createClass({
            displayName: `${displayName}ContextMenuLayer`,
            getDefaultProps() {
                return {
                    renderTag: "div",
                    attributes: {}
                };
            },
            mouseDown: false,
            handleMouseDown(event) {
                if (this.props.holdToDisplay >= 0 && event.button === 0) {
                    event.persist();

                    this.mouseDown = true;
                    setTimeout(() => {
                        if (this.mouseDown) this.handleContextClick(event);
                    }, this.props.holdToDisplay);
                }
            },
            handleTouchstart(event) {
                if (this.props.holdToDisplay >= 0) {
                    event.persist();

                    this.mouseDown = true;
                    setTimeout(() => {
                        if (this.mouseDown) this.handleContextClick(event);
                    }, this.props.holdToDisplay);
                }
            },
            handleTouchEnd(event) {
                event.preventDefault();
                this.mouseDown = false;
            },
            handleMouseUp(event) {
                if (event.button === 0) {
                    this.mouseDown = false;
                }
            },
            handleContextClick(event) {
                let currentItem = typeof configure === "function"
                    ? configure(this.props)
                    : {};

                invariant(
                    _isObject(currentItem),
                    "Expected configure to return an object. See %s",
                    displayName
                );

                event.preventDefault();

                const xPos = event.clientX || (event.touches && event.touches[0].pageX),
                    yPos = event.clientY || (event.touches && event.touches[0].pageY);

                store.dispatch({
                    type: "SET_PARAMS",
                    data: {
                        x: xPos,
                        y: yPos,
                        currentItem,
                        isVisible: typeof identifier === "function" ? identifier(this.props) : identifier
                    }
                });
            },
            render() {
                let { attributes: {className = "", ...attributes}, renderTag, ...props } = this.props;

                attributes.className = `react-context-menu-wrapper ${className}`;
                attributes.onContextMenu = this.handleContextClick;
                attributes.onMouseDown = this.handleMouseDown;
                attributes.onMouseUp = this.handleMouseUp;
                attributes.onTouchStart = this.handleTouchstart;
                attributes.onTouchEnd = this.handleTouchEnd;
                attributes.onMouseOut = this.handleMouseUp;
                attributes.ref = (c) => (this.target = c);

                return React.createElement(
                    renderTag,
                    attributes,
                    React.createElement(Component, props)
                );
            }
        });
    };
}
