import _ from "lodash";
import React, { Component } from "react";
import { DragSource } from "react-dnd";
import ReactJson from "react-json-view";
import LazyLoad from "react-lazyload";

import { MainObject } from "./MainObject";
import ResizeHandles from "./ResizeHandles";

const CURSOR_ID = 1111;

const boxSource = {
  beginDrag(props) {
    // place hover cursor where original object is
    props.addHoverCursor(props.settings.id);
    props.updateDragState(true);

    return {
      settings: props.settings,
      moveThisByThat: props.moveThisByThat,
    };
  },

  endDrag(props) {
    props.moveThisByThat(props.settings.id, CURSOR_ID);
    setTimeout(() => {
      props.updateDragState(false);
    }, 250);

    console.log("END DRAG!", props.settings);
  },

  canDrag(props) {
    if (!props.getCanDrag() || props.show === "preview") return false;
    return (
      props.settings.state === "hover" || props.settings.state === "active"
    );
  },
};

const DragSourceHOC = DragSource("box", boxSource, (connect, monitor) => ({
  connectDragSource: connect.dragSource(),
  connectDragPreview: connect.dragPreview(),
  isDragging: monitor.isDragging(),
}))(MainObject);

class EditorObject extends Component {
  constructor(props) {
    super(props);

    this.state = {
      showResize: false,
    };

    this.handleKeyPress = this.handleKeyPress.bind(this);
    this.handleMouseEvent = this.handleMouseEvent.bind(this);
  }

  handleKeyPress(e) {
    e.stopPropagation();

    const {
      removeItem,
      settings,
      pageContent,
      isEditing,
      changeState,
    } = this.props;

    if (!isEditing && e.keyCode === 46) {
      // delete key
      // get active id
      const activeKey = pageContent.findIndex((itm) => itm.state === "active");
      const activeObj = pageContent[activeKey];
      if (activeObj) {
        const activeId = activeObj.id;
        if (!activeObj.preventDelete) removeItem(activeId);
      }
    }

    if (e.keyCode === 27) {
      changeState(settings.id, "normal");
    }
  }

  handleMouseEvent(e, type) {
    const { settings, changeState, isDragInProgress, isEditing } = this.props;

    // determine if any property windows are showing
    const windows = _.get(this.props, "getActivePropertyWindows", () => null)();
    const activeObject = this.props.pageContent.filter(
      (itm) => itm.state === "active"
    );

    // is the id of this active object in one of the stored active property windows?
    // if so, it means the property window is showing right now
    const isShowingAnyPropertyWindows = activeObject.length
      ? windows.findIndex((id) => id === activeObject[0].id) > -1
      : false;

    switch (type) {
      case "enter":
        if (this.props.hasOwnProperty("onMouseEnter")) {
          this.props.onMouseEnter(e);
        } else if (isShowingAnyPropertyWindows) {
          // do this when there's a property window open
          if (!isDragInProgress && !isEditing) {
            e.stopPropagation();
            changeState(settings.id, "hover");
          }
        }
        break;

      case "leave":
        if (this.props.hasOwnProperty("onMouseLeave")) {
          this.props.onMouseLeave(e);
        } else if (!isDragInProgress && !isEditing) {
          e.stopPropagation();
          changeState(settings.id, "normal");
        }
        break;

      case "move":
        if (this.props.hasOwnProperty("onMouseMove")) {
          this.props.onMouseMove(e);
        } else {
          if (isShowingAnyPropertyWindows) break;

          if (!isDragInProgress && !isEditing) {
            // do this when NO property windows are open
            e.stopPropagation();
            if (settings.state !== "hover") changeState(settings.id, "hover");
          }
        }

        break;

      case "click":
        if (this.props.hasOwnProperty("onClick")) {
          this.props.onClick(e);
        } else {
          e.stopPropagation();
          if (!isDragInProgress && !isEditing) {
            changeState(settings.id, "active");
          }
        }
        break;

      case "mousedown":
        if (this.props.hasOwnProperty("onMouseDown")) {
          this.props.onMouseDown(e);
        }
        break;

      case "doubleClick":
        if (this.props.hasOwnProperty("onDoubleClick")) {
          this.props.onDoubleClick(e);
        } else {
          e.stopPropagation();
          if (!isDragInProgress && !isEditing) {
            this.props.showProperties();
          }
        }
        break;

      default:
        break;
    }
  }

  render() {
    const {
      settings,
      PropertiesView,
      showingProperties,
      showProperties,
      hideProperties,
      debug = false,
      isResizable = false,
      show,
      showResize,
    } = this.props;

    const displayStyle = {
      display: _.get(settings, "properties.display"),
      position: _.get(settings, "properties.position", "relative"),
      width: _.get(settings, "properties.width"),
      height: _.get(settings, "properties.height"),
    };

    const propertiesViewComponent = PropertiesView ? (
      <PropertiesView
        {...this.props}
        id={settings.id}
        showProperties={showProperties}
        hideProperties={hideProperties}
        onClick={(e) => {
          e.preventDefault();
          e.stopPropagation();
        }}
        onMouseDown={(e) => {
          e.preventDefault();
          e.stopPropagation();
        }}
        style={{ cursor: "default" }}
      />
    ) : null;

    return (
      <>
        <div
          style={{ height: "100%", ...displayStyle, ...this.props.style }}
          onMouseLeave={(e) => this.handleMouseEvent(e, "leave")}
          onMouseEnter={(e) => this.handleMouseEvent(e, "enter")}
          onMouseMove={(e) => this.handleMouseEvent(e, "move")}
          onClick={(e) => this.handleMouseEvent(e, "click")}
          onDoubleClick={(e) => this.handleMouseEvent(e, "doubleClick")}
          onKeyUp={this.handleKeyPress}
          ref={(node) => {
            this.editorObject = node;
          }}
          tabIndex="0"
        >
          {(_.get(settings, "state") === "active" ||
            _.get(settings, "state") === "hover" ||
            this.state.showResize) &&
          isResizable &&
          show !== "preview" ? (
            <ResizeHandles {...this.props} />
          ) : null}

          {showingProperties &&
          _.get(settings, "state") === "active" &&
          show !== "preview"
            ? propertiesViewComponent
            : null}
          {debug && <ReactJson src={settings} collapsed />}

          <DragSourceHOC
            {...this.props}
            displayStyle={displayStyle}
            showProperties={showProperties}
            showResize={showResize}
          >
            <LazyLoad unmountIfInvisible offset={900} height={100}>
              {this.props.children}
            </LazyLoad>
          </DragSourceHOC>
        </div>
      </>
    );
  }
}

EditorObject.defaultProps = {
  showOverlay: false,
  // isResizable: false,
  resizeHandles: [],
  color: "#8b6e9a",
  dragHandle: true,
};

export default EditorObject;
