import React, { useRef, useState, useEffect } from 'react';
import { WidgetData } from '../types';
import { CogwheelIcon } from './CogwheelIcon';
import { useAtom, useAtomValue } from 'jotai';
import { draggableState } from '../state/draggable.state';

interface WidgetProps {
  widget: WidgetData;
  gridSize: { width: number; height: number };
  children: React.ReactNode;
  settingsContent?: React.ReactNode;
  updateWidget: (id: string, data: Partial<WidgetData>) => void
}

export const Widget: React.FC<WidgetProps> = ({ widget, gridSize, children, settingsContent, updateWidget }) => {
  const widgetRef = useRef<HTMLDivElement>(null);
  const modalRef = useRef<HTMLDivElement>(null);
  const [isDragging, setIsDragging] = useState(false);
  const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
  const [isSettingsOpen, setIsSettingsOpen] = useState(false);
  const [widthInput, setWidthInput] = useState(widget.gridWidth);
  const [heightInput, setHeightInput] = useState(widget.gridHeight);

  const isDraggable = useAtomValue(draggableState)
  const snapToGrid = (pos: number, grid: number) => Math.round(pos / grid);

  const handleMouseDown = (e: React.MouseEvent) => {
    if(!isDraggable || isSettingsOpen){
      return
    }

    if (widgetRef.current && e.target === widgetRef.current) {
      setIsDragging(true);
      const rect = widgetRef.current.getBoundingClientRect();
      setDragOffset({
        x: e.clientX - rect.left,
        y: e.clientY - rect.top
      });
    }
  };

  const handleMouseMove = (e: MouseEvent) => {
    if (isDragging && widgetRef.current) {
      e.preventDefault();
      const newGridX = snapToGrid(e.clientX - dragOffset.x, gridSize.width);
      const newGridY = snapToGrid(e.clientY - dragOffset.y, gridSize.height);

      widgetRef.current.style.left = `${newGridX * gridSize.width}px`;
      widgetRef.current.style.top = `${newGridY * gridSize.height}px`;
    }
  };

  const handleMouseUp = () => {
    if (isDragging && widgetRef.current) {
      setIsDragging(false);
      const rect = widgetRef.current.getBoundingClientRect();
      const newGridX = snapToGrid(rect.left, gridSize.width);
      const newGridY = snapToGrid(rect.top, gridSize.height);
      updateWidget(widget.id, { gridX: newGridX, gridY: newGridY });
    }
  };

  const handleClickOutside = (e: MouseEvent) => {
    if (modalRef.current && !modalRef.current.contains(e.target as Node)) {
      setIsSettingsOpen(false);
    }
  };

  const stopPropagation = (e: React.MouseEvent) => {
    e.stopPropagation();
  };

  const handleSizeChange = () => {
    const newWidth = Math.max(1, widthInput);
    const newHeight = Math.max(1, heightInput);
    updateWidget(widget.id, { gridWidth: newWidth, gridHeight: newHeight });
    setWidthInput(newWidth);
    setHeightInput(newHeight);
    setIsSettingsOpen(false);
  };

  useEffect(() => {
    if (isDragging) {
      window.addEventListener('mousemove', handleMouseMove);
      window.addEventListener('mouseup', handleMouseUp);
      document.body.style.userSelect = 'none';
    }
    return () => {
      window.removeEventListener('mousemove', handleMouseMove);
      window.removeEventListener('mouseup', handleMouseUp);
      document.body.style.userSelect = '';
    };
  }, [isDragging, dragOffset, gridSize]);

  useEffect(() => {
    if (isSettingsOpen) {
      document.addEventListener('mousedown', handleClickOutside);
    }
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, [isSettingsOpen]);

  useEffect(() => {
    if (widgetRef.current && !isDragging) {
      widgetRef.current.style.left = `${widget.gridX * gridSize.width}px`;
      widgetRef.current.style.top = `${widget.gridY * gridSize.height}px`;
      widgetRef.current.style.width = `${(widget.gridWidth) * gridSize.width}px`;
      widgetRef.current.style.height = `${(widget.gridHeight) * gridSize.height}px`;
    }
  }, [widget.gridX, widget.gridY, widget.gridWidth, widget.gridHeight, gridSize, isDragging]);

  const genericSettingsContent = (
    <>
      <label>
        Width (grid cells):
        <input
          type="number"
          min="1"
          value={widthInput}
          onChange={(e) => setWidthInput(parseInt(e.target.value) || 1)}
        />
      </label>
      <label>
        Height (grid cells):
        <input
          type="number"
          min="1"
          value={heightInput}
          onChange={(e) => setHeightInput(parseInt(e.target.value) || 1)}
        />
      </label>
      <button onClick={handleSizeChange}>Apply</button>
    </>
  );

  return (
    <div
      ref={widgetRef}
      className="container"
      onMouseDown={handleMouseDown}
      style={{ cursor: isDraggable && !isSettingsOpen ? 'grab' : 'default' }}
    >
      <button className="close-button" onClick={() => undefined /*removeWidget(widget.id)*/} onMouseDown={stopPropagation}>×</button>
      <button
        className="settings-button"
        onClick={() => setIsSettingsOpen(!isSettingsOpen)}
        onMouseDown={stopPropagation}
      >
        <CogwheelIcon size={24} />
      </button>
      {children}
      {isSettingsOpen && (
        <div className="widget-settings-modal" onMouseDown={stopPropagation}>
          <div ref={modalRef} className="widget-modal-content">
            <button className="close-button" onClick={() => setIsSettingsOpen(false)} onMouseDown={stopPropagation}>×</button>
            {settingsContent}
            {genericSettingsContent}
          </div>
        </div>
      )}
    </div>
  );
};