export class DraggableResizableClass {
  private container: HTMLElement;
  private items: any[];
  private containerRect: DOMRect;

  constructor(container: HTMLElement, items: any[]) {
    this.container = container;
    this.items = items;
    this.containerRect = this.container.getBoundingClientRect();
    this.init();
  }

  private init() {
    this.updateListeners();
  }

  public updateListeners() {
    const elements = this.container.querySelectorAll(".draggable-resizable");
    elements.forEach((el, index) => {
      const handles = (el as HTMLElement).querySelectorAll(".resize-handle");
      handles.forEach(handle => {
        handle.addEventListener("mousedown", (e) => this.onResizeMouseDown(e, index, handle as HTMLElement));
      });
      (el as HTMLElement).addEventListener("mousedown", (e) => this.onMouseDown(e, index));
    });
  }

  private onMouseDown(event: MouseEvent, index: number) {
    if ((event.target as HTMLElement).classList.contains("resize-handle")) {
      return;
    }

    const item = this.items[index];
    const startX = event.clientX;
    const startY = event.clientY;
    const startLeft = item.x;
    const startTop = item.y;

    const onMouseMove = (e: MouseEvent) => {
      const dx = e.clientX - startX;
      const dy = e.clientY - startY;

      item.x = Math.min(
        Math.max(startLeft + dx, 0),
        this.containerRect.width - item.w
      );
      item.y = Math.min(
        Math.max(startTop + dy, 0),
        this.containerRect.height - item.h
      );

      this.updateStyles(index);
    };

    const onMouseUp = () => {
      document.removeEventListener("mousemove", onMouseMove);
      document.removeEventListener("mouseup", onMouseUp);
    };

    document.addEventListener("mousemove", onMouseMove);
    document.addEventListener("mouseup", onMouseUp);
  }

  private onResizeMouseDown(event: MouseEvent, index: number, handle: HTMLElement) {
    event.stopPropagation(); // Prevent triggering drag event

    const item = this.items[index];
    const startX = event.clientX;
    const startY = event.clientY;
    const startWidth = item.w;
    const startHeight = item.h;
    const startLeft = item.x;
    const startTop = item.y;

    const handleClass = handle.classList[1]; // Get the class of the handle

    const onMouseMove = (e: MouseEvent) => {
      let newWidth = startWidth;
      let newHeight = startHeight;
      let newLeft = startLeft;
      let newTop = startTop;

      switch (handleClass) {
        case 'top-left':
          newWidth = Math.max(startWidth - (e.clientX - startX), 60);
          newHeight = Math.max(startHeight - (e.clientY - startY), 30);
          newLeft = startLeft + (startWidth - newWidth);
          newTop = startTop + (startHeight - newHeight);
          break;

        case 'top-right':
          newWidth = Math.max(startWidth + (e.clientX - startX), 60);
          newHeight = Math.max(startHeight - (e.clientY - startY), 30);
          newTop = startTop + (startHeight - newHeight);
          break;

        case 'bottom-left':
          newWidth = Math.max(startWidth - (e.clientX - startX), 60);
          newHeight = Math.max(startHeight + (e.clientY - startY), 30);
          newLeft = startLeft + (startWidth - newWidth);
          break;

        case 'bottom-right':
          newWidth = Math.max(startWidth + (e.clientX - startX), 60);
          newHeight = Math.max(startHeight + (e.clientY - startY), 30);
          break;

        case 'top':
          newHeight = Math.max(startHeight - (e.clientY - startY), 30);
          newTop = startTop + (startHeight - newHeight);
          break;

        case 'right':
          newWidth = Math.max(startWidth + (e.clientX - startX), 60);
          break;

        case 'bottom':
          newHeight = Math.max(startHeight + (e.clientY - startY), 30);
          break;

        case 'left':
          newWidth = Math.max(startWidth - (e.clientX - startX), 60);
          newLeft = startLeft + (startWidth - newWidth);
          break;
      }

      // Ensure resizing does not go outside container boundaries
      newWidth = Math.min(Math.max(newWidth, 60), this.containerRect.width - newLeft);
      newHeight = Math.min(Math.max(newHeight, 30), this.containerRect.height - newTop);
      newLeft = Math.max(Math.min(newLeft, this.containerRect.width - newWidth), 0);
      newTop = Math.max(Math.min(newTop, this.containerRect.height - newHeight), 0);

      item.w = newWidth;
      item.h = newHeight;
      item.x = newLeft;
      item.y = newTop;

      this.updateStyles(index);
    };

    const onMouseUp = () => {
      document.removeEventListener("mousemove", onMouseMove);
      document.removeEventListener("mouseup", onMouseUp);
    };

    document.addEventListener("mousemove", onMouseMove);
    document.addEventListener("mouseup", onMouseUp);
  }

  private updateStyles(index: number) {
    const item = this.items[index];
    const element = this.container.querySelectorAll(".draggable-resizable")[index] as HTMLElement;

    element.style.left = `${item.x}px`;
    element.style.top = `${item.y}px`;
    element.style.width = `${item.w}px`;
    element.style.height = `${item.h}px`;
  }
}
