import { CSSProperties } from "react";
import { XYCoord } from "react-dnd";

import { theme } from "constants/DefaultTheme";
import { WidgetProps, WidgetRowCols } from "widgets/BaseWidget";
import { isDropZoneOccupied } from "utils/WidgetPropsUtils";
import { OccupiedSpace } from "constants/editorConstants";

export type UIElementSize = { height: number; width: number };

export const RESIZABLE_CONTAINER_BORDER_THEME_INDEX = 1;

const RESIZE_HANDLE_HOVER_AREA_WIDTH = 12;

export const getHandleSyles = (): {
  top: CSSProperties;
  bottom: CSSProperties;
  right: CSSProperties;
  left: CSSProperties;
  bottomRight: CSSProperties;
  bottomLeft: CSSProperties;
} => {
  const hoverWidth = RESIZE_HANDLE_HOVER_AREA_WIDTH;
  const hoverWidthHalf = hoverWidth / 2;
  const halfBorder =
    theme.borders[RESIZABLE_CONTAINER_BORDER_THEME_INDEX].thickness / 2;
  const shiftedHoverWidthHalf = hoverWidthHalf + halfBorder;
  const hoverCornerWidth = hoverWidth + hoverWidth / 4;

  return {
    top: {
      height: hoverWidth + "px",
      top: "-" + shiftedHoverWidthHalf + "px",
      zIndex: 1,
      cursor: "ns-resize",
    },
    bottomRight: {
      height: hoverCornerWidth + "px",
      width: hoverCornerWidth + "px",
      zIndex: 1,
      cursor: "nwse-resize",
    },
    bottomLeft: {
      height: hoverCornerWidth + "px",
      width: hoverCornerWidth + "px",
      zIndex: 1,
      cursor: "nesw-resize",
    },
    bottom: {
      height: hoverWidth + "px",
      bottom: "-" + shiftedHoverWidthHalf + "px",
      zIndex: 1,
      cursor: "ns-resize",
    },
    left: {
      width: hoverWidth + "px",
      left: "-" + shiftedHoverWidthHalf + "px",
      zIndex: 1,
      cursor: "ew-resize",
    },
    right: {
      width: hoverWidth + "px",
      right: "-" + shiftedHoverWidthHalf + "px",
      zIndex: 1,
      cursor: "ew-resize",
    },
  };
};

export const computeUpdatedRowCols = (
  isColliding: boolean,
  delta: UIElementSize,
  position: XYCoord,
  props: WidgetProps,
): WidgetRowCols | false => {
  if (isColliding) return false;
  const newRowCols: WidgetRowCols = {
    leftColumn: props.leftColumn + position.x / props.parentColumnSpace,
    topRow: props.topRow + position.y / props.parentRowSpace,

    rightColumn:
      props.rightColumn + (delta.width + position.x) / props.parentColumnSpace,
    bottomRow:
      props.bottomRow + (delta.height + position.y) / props.parentRowSpace,
  };

  if (
    props.leftColumn !== newRowCols.leftColumn ||
    props.topRow !== newRowCols.topRow ||
    props.bottomRow !== newRowCols.bottomRow ||
    props.rightColumn !== newRowCols.rightColumn
  ) {
    return newRowCols;
  }
  return false;
};

export const hasCollision = (
  delta: UIElementSize,
  position: XYCoord,
  props: WidgetProps,
  occupiedSpaces?: OccupiedSpace[],
): boolean => {
  const left = props.leftColumn + position.x / props.parentColumnSpace;
  const top = props.topRow + position.y / props.parentRowSpace;

  const right =
    props.rightColumn + (delta.width + position.x) / props.parentColumnSpace;
  const bottom =
    props.bottomRow + (delta.height + position.y) / props.parentRowSpace;

  return isDropZoneOccupied(
    {
      left,
      top,
      bottom,
      right,
    },
    props.widgetId,
    occupiedSpaces,
  );
};

// TODO(abhinav): Memoize this?
export const getBorderStyles = (
  isWidgetFocused: boolean,
  isColliding: boolean,
  padding: number,
): CSSProperties => {
  const selectedColor = theme.colors.containerBorder;
  const collisionColor = theme.colors.error;

  // To fix the widget select/unselect size descripancy: Issue #127
  // Always have the border, just toggle the opacity.
  const unselectedColor = "transparent";

  const borderThickness =
    theme.borders[RESIZABLE_CONTAINER_BORDER_THEME_INDEX].thickness + "px";
  const borderStyle =
    theme.borders[RESIZABLE_CONTAINER_BORDER_THEME_INDEX].style;

  let borderColor = unselectedColor;
  if (isWidgetFocused) {
    borderColor = selectedColor;
  }
  if (isColliding && isWidgetFocused) {
    borderColor = collisionColor;
  }

  return {
    border: [borderThickness, borderStyle, borderColor].join(" "),
    padding: padding + "px",
  };
};
