// @ts-nocheck
import * as React from "react";
import { head, get } from "lodash";
import { useDimensions } from "@sc/plugins/utilities";
import { useDrop } from "react-dnd";
import { DragTypes, EditorActions } from "../../types";
import { AddTypes } from "../EditorObject/EditorObject";
import { EditorContext } from "../../Editor";
import { listAncestors } from "../../actions";

interface ComponentWrapperProps {
  /**
   * The unique id of the editor object
   */
  id: string;

  /**
   * Whether or not the component is currently showing properties
   */
  isShowingProperties?: Boolean;

  /**
   * TODO: Add a description
   */
  children: React.ReactNode;
}

const xisHovering = (monitor, { content, dispatch, hoverBoundingRect, id }) => {
  // Triggered when an object is on top of me

  // (places a cursor in the location where the drop will occur)
  // Only Proceed If Hovering Directly On The Object (And Not Nested Inside)
  if (!monitor.isOver({ shallow: true })) return;

  // Get the coordinates of the middle of the object
  const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

  // Get the current mouse position
  const clientOffset = monitor.getClientOffset();

  // Get the coorinates with respect to the object being hovered on
  const hoverClientY = clientOffset.y - hoverBoundingRect.top;

  // Add a cursor only when the mouse changes directions
  if (hoverClientY === monitor.getItem().formerClientY) return; // ignore if mouse doesn't move

  const sourceItem = head(
    content.filter((itm) => itm.id === monitor.getItem().id)
  );
  const targetItem = head(content.filter((itm) => itm.id === id));

  // (handle containers)
  if (get(sourceItem, "canHaveChildren", false)) {
    const offLimitObjects = listAncestors(content, targetItem.id); // all the parents of the targetItem
    if (sourceItem.id === targetItem.id) return;

    const offLimitIds = offLimitObjects.map((itm) => itm.parent); // all the ids parents
    if (offLimitIds.findIndex((itm) => itm === sourceItem.id) > -1) return; // if we find the id of the sourceItem in my list, cancel

    // Place at the bottom if the sourceItem tries to drop into itself
    if (sourceItem.id === targetItem.id) {
      dispatch({
        type: EditorActions.ADD_HOVER_CURSOR,
        payload: {
          id: targetItem.id,
          addType: AddTypes.AFTER,
        },
      });
      // addHoverCursor(targetItem.id, AddTypes.AFTER);
    }
  }

  // Add a cursor inside fo the container if it is blank if its empty
  if (get(targetItem, "canHaveChildren", false)) {
    // if the container is empty, add a cursor
    if (content.findIndex((itm) => itm.parent === targetItem.id) === -1) {
      // object is empty
      dispatch({
        type: EditorActions.ADD_HOVER_CURSOR,
        payload: {
          id: targetItem.id,
          addType: AddTypes.INSIDE,
        },
      });

      // console.log("I'm inside an Empty container");
      return;
    }

    if (!get(targetItem, "parent", false)) return;

    // console.log("I'm inside a FULL container");

    const children = content.filter((itm) => itm.parent === targetItem.id);

    // If the container is full, add the cursor after the last inner object
    const twentyPercentFromTheBottom = Math.round(
      hoverBoundingRect.height - hoverBoundingRect.height * 0.2
    );

    if (hoverClientY > twentyPercentFromTheBottom) {
      // console.log("I'm 20% from the bottom of ", targetItem.type);

      dispatch({
        type: EditorActions.ADD_HOVER_CURSOR,
        payload: {
          id: targetItem.id,
          addType: AddTypes.AFTER,
        },
      });

      return;
    }

    // If they're close to the top of the container, add the cursor before the first inner object
    const tenPercentFromTheTop = Math.round(hoverBoundingRect.height * 0.1);

    if (hoverClientY < tenPercentFromTheTop) {
      // console.log("I'm 10% from the top of ", targetItem.type);
      dispatch({
        type: EditorActions.ADD_HOVER_CURSOR,
        payload: {
          id: targetItem.id,
          addType: AddTypes.BEFORE,
        },
      });
      return;
    }

    if (!children.hasOwnProperty(children.length - 1)) return;

    dispatch({
      type: EditorActions.ADD_HOVER_CURSOR,
      payload: {
        id: children[children.length - 1].id,
        addType: AddTypes.AFTER,
      },
    });

    return;
  }

  // Don't work on a root object (ALWAYS HAVE A 'BODY' object as your root!)
  if (!targetItem.parent) return;

  // Determine if the mouse is moving upwards or downwards
  // (this will establish where to place the object when the mouse is released)
  const currentAddType =
    hoverClientY < (monitor.getItem().formerClientY || hoverMiddleY)
      ? AddTypes.BEFORE
      : AddTypes.AFTER;
  monitor.getItem().formerClientY = hoverClientY;

  // Ignore if the mouse is heading in the same direction
  if (currentAddType === monitor.getItem().addType) return;
  monitor.getItem().addType = currentAddType;

  /**
   * At this point, we're ready to drop above or below an object.  However,
   * if the user is hover on top of an object that is the first or last object
   * of the parent element, we should check to see if it is at the top 20 or
   * bottom 20% of the parent element.  if it is, place above or below that
   * parent element
   */

  // Place above (or below) the PARENT element if the mouse is within 20% of the top (or the bottom)

  // Place the cursor

  dispatch({
    type: EditorActions.ADD_HOVER_CURSOR,
    payload: {
      id: targetItem.id,
      addType: currentAddType,
    },
  });
};

const addHoverCursor = (id, dispatch, addType = AddTypes.AFTER) => {
  dispatch({
    type: EditorActions.ADD_HOVER_CURSOR,
    payload: {
      id,
      addType,
    },
  });
};

const isHovering = (monitor, { content, dispatch, hoverBoundingRect, id }) => {
  // Triggered when an object is on top of me
  // (places a cursor in the location where the drop will occur)
  // Only Proceed If Hovering Directly On The Object (And Not Nested Inside)
  if (!monitor.isOver({ shallow: true })) return;

  // [!] can drag up/down and show cursor in right spot (no container)
  const targetItem = head(content.filter((itm) => itm.id === id));
  addHoverCursor(targetItem.id, dispatch);
  console.log("isHovering", id);

  // [!] Can release and replacement happens
  // [!] Dragging a container
  // [!] Dragging into a container
  // [!] Dragging at the top/bottom of a container
};

/**
 * The container that is wrapped around each component in the editor
 */
const ComponentWrapper: React.FC<ComponentWrapperProps> = ({
  children,
  id,
}) => {
  const [ref, hoverBoundingRect] = useDimensions();

  const editor = React.useContext(EditorContext);
  // const { content, addHoverCursor, listAncestors } = editor;
  const { content, dispatch } = editor;

  const [{ canDrop, isOver }, dropRef] = useDrop({
    accept: DragTypes.EDITOROBJECT,
    drop: () => ({ id }),
    hover: (props, monitor) => {
      isHovering(monitor, {
        content,
        dispatch,
        hoverBoundingRect,
        id,
      });
    },
    collect: (monitor) => ({
      isOver: monitor.isOver(),
      canDrop: monitor.canDrop(),
    }),
  });

  return (
    <div key={id} ref={dropRef}>
      <div ref={ref}>{children}</div>
    </div>
  );
};

export default ComponentWrapper;
