import { useEffect, useState } from "react";
import Paper from "@mui/material/Paper";
import Box from "@mui/material/Box";

function Pointer({
  direction,
  size,
  setSize,
  position,
  setPosition,
  children,
  minSize,
  maxSize,
  ...props
}) {
  const [origin, setOrigin] = useState(null);

  function handlePointerDown(e) {
    e.target.setPointerCapture(e.pointerId);
    setOrigin({
      x: position.x,
      y: position.y,
      w: size.w,
      h: size.h,
      clientX: e.clientX,
      clientY: e.clientY,
    });
  }

  function handlePointerMove(e) {
    if (origin) {
      const dx = e.clientX - origin.clientX;
      const dy = e.clientY - origin.clientY;
      let x = position.x;
      let y = position.y;
      let w = size.w;
      let h = size.h;

      switch (direction) {
        case "Header":
          x = origin.x + dx;
          y = origin.y + dy;
          break;
        case "TopLeft":
          x = origin.x + dx;
          y = origin.y + dy;
          w = origin.w - dx;
          h = origin.h - dy;
          break;
        case "Top":
          y = origin.y + dy;
          h = origin.h - dy;
          break;
        case "TopRight":
          y = origin.y + dy;
          w = origin.w + dx;
          h = origin.h - dy;
          break;
        case "Left":
          x = origin.x + dx;
          w = origin.w - dx;
          break;
        case "Right":
          w = origin.w + dx;
          break;
        case "BottomLeft":
          x = origin.x + dx;
          w = origin.w - dx;
          h = origin.h + dy;
          break;
        case "Bottom":
          h = origin.h + dy;
          break;
        case "BottomRight":
          w = origin.w + dx;
          h = origin.h + dy;
          break;
        default:
      }

      if (w < minSize.w) {
        w = minSize.w;
        x = position.x;
      }
      if (w > maxSize.w) {
        w = maxSize.w;
        x = position.x;
      }
      if (h < minSize.h) {
        h = minSize.h;
        y = position.y;
      }
      if (h > maxSize.h) {
        h = maxSize.h;
        y = position.y;
      }

      setPosition({ x, y });
      setSize({ w, h });
    }
  }

  function handlePointerUp(e) {
    setOrigin(null);
  }

  return (
    <div
      {...props}
      onPointerDown={handlePointerDown}
      onPointerMove={handlePointerMove}
      onPointerUp={handlePointerUp}
    >
      {children}
    </div>
  );
}

export default function DraggableResizable({
  header,
  children,
  defaultPosition = {
    x: 0,
    y: 0,
  },
  defaultSize = {
    w: 600,
    h: 400,
  },
  minSize = {
    w: 300,
    h: 200,
  },
  maxSize = {
    w: 1200,
    h: 1200,
  },
  onChangeSize,
  onChangePosition,
}) {
  const lineWidth = 4;
  const [position, setPosition] = useState(defaultPosition);
  const [size, setSize] = useState(defaultSize);

  const opts = {
    size,
    setSize,
    position,
    setPosition,
    minSize,
    maxSize,
  };

  useEffect(() => {
    onChangeSize && onChangeSize(size);
  }, [size, onChangeSize]);

  useEffect(() => {
    onChangePosition && onChangePosition(position);
  }, [position, onChangePosition]);

  return (
    <Box
      style={{
        position: "fixed",
        left: position.x,
        top: position.y,
        display: "grid",
        gridTemplateColumns: `${lineWidth * 2}px auto ${lineWidth * 2}px`,
        gridTemplateRows: `${lineWidth * 2}px auto ${lineWidth * 2}px`,
        zIndex: 2147483647,
      }}
    >
      <Pointer
        direction="TopLeft"
        style={{
          transform: `translate(${lineWidth}px, ${lineWidth}px)`,
          cursor: "nw-resize",
        }}
        {...opts}
      />
      <Pointer
        direction="Top"
        style={{
          margin: `0 ${lineWidth}px`,
          transform: `translate(0px, ${lineWidth}px)`,
          cursor: "row-resize",
        }}
        {...opts}
      />
      <Pointer
        direction="TopRight"
        style={{
          transform: `translate(-${lineWidth}px, ${lineWidth}px)`,
          cursor: "ne-resize",
        }}
        {...opts}
      />
      <Pointer
        direction="Left"
        style={{
          margin: `${lineWidth}px 0`,
          transform: `translate(${lineWidth}px, 0px)`,
          cursor: "col-resize",
        }}
        {...opts}
      />
      <Paper elevation={4}>
        <Pointer direction="Header" style={{ cursor: "move" }} {...opts}>
          {header}
        </Pointer>
        <div
          style={{
            width: size.w,
            height: size.h,
            overflow: "hidden auto",
          }}
        >
          {children}
        </div>
      </Paper>
      <Pointer
        direction="Right"
        style={{
          margin: `${lineWidth}px 0`,
          transform: `translate(-${lineWidth}px, 0px)`,
          cursor: "col-resize",
        }}
        {...opts}
      />
      <Pointer
        direction="BottomLeft"
        style={{
          transform: `translate(${lineWidth}px, -${lineWidth}px)`,
          cursor: "ne-resize",
        }}
        {...opts}
      />
      <Pointer
        direction="Bottom"
        style={{
          margin: `0 ${lineWidth}px`,
          transform: `translate(0px, -${lineWidth}px)`,
          cursor: "row-resize",
        }}
        {...opts}
      />
      <Pointer
        direction="BottomRight"
        style={{
          transform: `translate(-${lineWidth}px, -${lineWidth}px)`,
          cursor: "nw-resize",
        }}
        {...opts}
      />
    </Box>
  );
}
