import { useCallback, useEffect, useRef, useState } from 'react';

// Parse polygon CSS string to points array
const parsePolygon = (polygonString) => {
  if (!polygonString || !polygonString.startsWith('polygon(')) {
    return [
      { x: 0, y: 0 },
      { x: 100, y: 0 },
      { x: 100, y: 100 },
      { x: 0, y: 100 },
    ];
  }

  const match = polygonString.match(/polygon\(([^)]+)\)/);
  if (!match) {
    return [
      { x: 0, y: 0 },
      { x: 100, y: 0 },
      { x: 100, y: 100 },
      { x: 0, y: 100 },
    ];
  }

  const pointsStr = match[1];
  const points = pointsStr.split(',').map((point) => {
    const [x, y] = point.trim().split(/\s+/);
    return {
      x: parseFloat(x),
      y: parseFloat(y),
    };
  });

  return points;
};

// Convert points array to polygon CSS string
const toPolygonString = (points) => {
  const pointsStr = points.map((p) => `${p.x}% ${p.y}%`).join(', ');
  return `polygon(${pointsStr})`;
};

// Calculate distance from point to line segment
const distanceToSegment = (px, py, x1, y1, x2, y2) => {
  const dx = x2 - x1;
  const dy = y2 - y1;
  const lengthSquared = dx * dx + dy * dy;

  if (lengthSquared === 0) {
    return Math.sqrt((px - x1) ** 2 + (py - y1) ** 2);
  }

  let t = ((px - x1) * dx + (py - y1) * dy) / lengthSquared;
  t = Math.max(0, Math.min(1, t));

  const nearestX = x1 + t * dx;
  const nearestY = y1 + t * dy;

  return {
    distance: Math.sqrt((px - nearestX) ** 2 + (py - nearestY) ** 2),
    point: { x: nearestX, y: nearestY },
    t,
  };
};

const ClippingPathGenerator = ({
  clippingPath = 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)',
  onChange,
  editorBackgroundColor,
}) => {
  const [points, setPoints] = useState(() => parsePolygon(clippingPath));
  const [draggingIndex, setDraggingIndex] = useState(null);
  const [hoveredPoint, setHoveredPoint] = useState(null);
  const [hoveredEdge, setHoveredEdge] = useState(null);
  const containerRef = useRef(null);
  const isDraggingRef = useRef(false);

  // Sync with external clippingPath prop
  useEffect(() => {
    const newPoints = parsePolygon(clippingPath);
    setPoints(newPoints);
  }, [clippingPath]);

  // Notify parent of changes
  const notifyChange = useCallback(
    (newPoints) => {
      if (onChange) {
        onChange(toPolygonString(newPoints));
      }
    },
    [onChange]
  );

  const getRelativePosition = useCallback((e) => {
    const rect = containerRef.current.getBoundingClientRect();
    const clientX = e.touches ? e.touches[0].clientX : e.clientX;
    const clientY = e.touches ? e.touches[0].clientY : e.clientY;

    let x = ((clientX - rect.left) / rect.width) * 100;
    let y = ((clientY - rect.top) / rect.height) * 100;

    // Clamp values
    x = Math.max(0, Math.min(100, x));
    y = Math.max(0, Math.min(100, y));

    return { x: Math.round(x), y: Math.round(y) };
  }, []);

  const handlePointMouseDown = (index, e) => {
    e.preventDefault();
    e.stopPropagation();
    setDraggingIndex(index);
    isDraggingRef.current = true;
  };

  const handleMouseMove = useCallback(
    (e) => {
      if (draggingIndex === null) return;

      const pos = getRelativePosition(e);
      const newPoints = [...points];
      newPoints[draggingIndex] = pos;
      setPoints(newPoints);
    },
    [draggingIndex, points, getRelativePosition]
  );

  const handleMouseUp = useCallback(() => {
    if (draggingIndex !== null) {
      notifyChange(points);
      setDraggingIndex(null);
      // Reset drag flag after a short delay to prevent click from adding point
      setTimeout(() => {
        isDraggingRef.current = false;
      }, 10);
    }
  }, [draggingIndex, points, notifyChange]);

  useEffect(() => {
    if (draggingIndex !== null) {
      window.addEventListener('mousemove', handleMouseMove);
      window.addEventListener('mouseup', handleMouseUp);
      window.addEventListener('touchmove', handleMouseMove);
      window.addEventListener('touchend', handleMouseUp);

      return () => {
        window.removeEventListener('mousemove', handleMouseMove);
        window.removeEventListener('mouseup', handleMouseUp);
        window.removeEventListener('touchmove', handleMouseMove);
        window.removeEventListener('touchend', handleMouseUp);
      };
    }
  }, [draggingIndex, handleMouseMove, handleMouseUp]);

  const removePoint = (index, e) => {
    e.stopPropagation();
    if (points.length <= 3) return;

    const newPoints = points.filter((_, i) => i !== index);
    setPoints(newPoints);
    setHoveredPoint(null);
    notifyChange(newPoints);
  };

  // Handle clicking on edge to add point
  const handleContainerClick = (e) => {
    // Prevent adding point after drag
    if (isDraggingRef.current) return;
    if (draggingIndex !== null) return;
    if (points.length >= 20) return;

    const pos = getRelativePosition(e);

    // Find the closest edge
    let closestEdge = null;
    let minDistance = Infinity;
    let insertPoint = null;

    for (let i = 0; i < points.length; i++) {
      const nextIndex = (i + 1) % points.length;
      const result = distanceToSegment(
        pos.x,
        pos.y,
        points[i].x,
        points[i].y,
        points[nextIndex].x,
        points[nextIndex].y
      );

      if (result.distance < minDistance) {
        minDistance = result.distance;
        closestEdge = i;
        insertPoint = result.point;
      }
    }

    // Only add point if click is close enough to an edge (within 10%)
    if (minDistance < 10 && closestEdge !== null) {
      const newPoints = [...points];
      newPoints.splice(closestEdge + 1, 0, {
        x: Math.round(insertPoint.x),
        y: Math.round(insertPoint.y),
      });
      setPoints(newPoints);
      notifyChange(newPoints);
    }
  };

  // Track hovered edge for visual feedback
  const handleContainerMouseMove = (e) => {
    if (draggingIndex !== null) return;

    const pos = getRelativePosition(e);

    let closestEdge = null;
    let minDistance = Infinity;

    for (let i = 0; i < points.length; i++) {
      const nextIndex = (i + 1) % points.length;
      const result = distanceToSegment(
        pos.x,
        pos.y,
        points[i].x,
        points[i].y,
        points[nextIndex].x,
        points[nextIndex].y
      );

      if (result.distance < minDistance) {
        minDistance = result.distance;
        closestEdge = i;
      }
    }

    if (minDistance < 10) {
      setHoveredEdge(closestEdge);
    } else {
      setHoveredEdge(null);
    }
  };

  // Generate edges for rendering
  const edges = points.map((point, i) => {
    const nextPoint = points[(i + 1) % points.length];
    return {
      x1: point.x,
      y1: point.y,
      x2: nextPoint.x,
      y2: nextPoint.y,
      index: i,
    };
  });

  return (
    <div>
      {/* Outer container with padding for points/edges visibility */}
      <div className='wmx-inline-block wmx-p-4 wmx-bg-gray-200 wmx-rounded-md'>
        {/* Editor */}
        <div
          className='wmx-size-36 2xl:wmx-size-64 wmx-relative wmx-bg-white'
          ref={containerRef}
          onClick={handleContainerClick}
          onMouseMove={handleContainerMouseMove}
          onMouseLeave={() => setHoveredEdge(null)}
          style={{
            cursor: draggingIndex !== null ? 'grabbing' : 'crosshair',
          }}
        >
          {/* Grid background */}
          <div
            className='wmx-absolute wmx-inset-0 wmx-size-full'
            style={{
              backgroundImage: `
                linear-gradient(to right, #ddd 1px, transparent 1px),
                linear-gradient(to bottom, #ddd 1px, transparent 1px)
              `,
              backgroundSize: '10% 10%',
            }}
          />

          {/* Clipped preview */}
          <div
            className='wmx-absolute wmx-inset-0 wmx-size-full'
            style={{
              background: editorBackgroundColor || '#0bc2db',
              clipPath: toPolygonString(points),
            }}
          />

          {/* Edge lines */}
          {edges.map((edge, i) => {
            const length = Math.sqrt((edge.x2 - edge.x1) ** 2 + (edge.y2 - edge.y1) ** 2);
            const angle = Math.atan2(edge.y2 - edge.y1, edge.x2 - edge.x1) * (180 / Math.PI);

            return (
              <div
                key={`edge-${i}`}
                style={{
                  position: 'absolute',
                  left: `${edge.x1}%`,
                  top: `${edge.y1}%`,
                  width: `${length}%`,
                  height: 2,
                  background: hoveredEdge === i ? '#2196F3' : '#333',
                  transformOrigin: '0 50%',
                  transform: `rotate(${angle}deg)`,
                  pointerEvents: 'none',
                }}
              />
            );
          })}

          {/* Draggable points */}
          {points.map((point, index) => (
            <div
              key={index}
              onMouseEnter={() => setHoveredPoint(index)}
              onMouseLeave={() => setHoveredPoint(null)}
              style={{
                position: 'absolute',
                left: `${point.x}%`,
                top: `${point.y}%`,
                width: 40,
                height: 20,
                marginLeft: -10,
                marginTop: -10,
                zIndex: hoveredPoint === index ? 20 : 10,
              }}
            >
              {/* Point circle */}
              <div
                onMouseDown={(e) => handlePointMouseDown(index, e)}
                onTouchStart={(e) => handlePointMouseDown(index, e)}
                style={{
                  position: 'absolute',
                  top: 2,
                  left: 2,
                  width: 16,
                  height: 16,
                  borderRadius: '50%',
                  background: '#fff',
                  border: '2px solid #333',
                  cursor: 'grab',
                  userSelect: 'none',
                  boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
                }}
              />
              {/* Remove button on hover - balloon style */}
              {hoveredPoint === index && points.length > 3 && (
                <button
                  onMouseDown={(e) => e.stopPropagation()}
                  onClick={(e) => removePoint(index, e)}
                  style={{
                    position: 'absolute',
                    top: 2,
                    left: 26,
                    width: 16,
                    height: 16,
                    borderRadius: '50%',
                    border: 'none',
                    background: '#f44336',
                    color: '#fff',
                    fontSize: 10,
                    lineHeight: '14px',
                    cursor: 'pointer',
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    boxShadow: '0 1px 3px rgba(0,0,0,0.3)',
                  }}
                >
                  X
                  <span
                    style={{
                      position: 'absolute',
                      left: -4,
                      top: '50%',
                      transform: 'translateY(-50%)',
                      width: 0,
                      height: 0,
                      borderTop: '4px solid transparent',
                      borderBottom: '4px solid transparent',
                      borderRight: '5px solid #f44336',
                    }}
                  />
                </button>
              )}
            </div>
          ))}
        </div>
      </div>

      {/* Info text */}
      <p
        style={{
          fontSize: 12,
          color: '#666',
        }}
      >
        Click on edge to add point, Hover point to remove
      </p>

      {/* Output */}
      {/* <div style={{ marginTop: 12 }}>
        <label
          style={{
            display: 'block',
            marginBottom: 6,
            fontSize: 14,
            fontWeight: 500,
          }}
        >
          CSS Output
        </label>
        <input
          type='text'
          readOnly
          value={toPolygonString(points)}
          style={{
            width: '100%',
            padding: '8px 12px',
            fontSize: 13,
            fontFamily: 'monospace',
            border: '1px solid #ddd',
            borderRadius: 4,
            background: '#fff',
            boxSizing: 'border-box',
          }}
          onClick={(e) => e.target.select()}
        />
      </div> */}
    </div>
  );
};

export default ClippingPathGenerator;
