import { useReactFlow } from "../../../../xyflow/react.js";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { snapPointToGrid } from "../geometry.js";
import { insertWaypoint, materializePathWaypoints, moveSegmentByDelta, moveWaypoint, removeWaypoint, waypointsEqual } from "../waypoints.js";
import { useEdgeWaypointWriter } from "./useEdgeWaypointWriter.js";
function useWaypointEditor(args) {
    const { edgeId, waypoints, pathPoints, enabled, onChange } = args;
    const { screenToFlowPosition } = useReactFlow();
    const writeWaypoints = useEdgeWaypointWriter(edgeId, onChange);
    const [dragState, setDragState] = useState({
        type: 'none'
    });
    const dragStartRef = useRef(null);
    const rafRef = useRef(null);
    const waypointsRef = useRef(waypoints);
    const pathPointsRef = useRef(pathPoints);
    useEffect(()=>{
        waypointsRef.current = waypoints;
        pathPointsRef.current = pathPoints;
    });
    const updateWaypoints = useCallback((next)=>{
        if (waypointsEqual(waypointsRef.current, next)) return;
        writeWaypoints(next);
    }, [
        writeWaypoints
    ]);
    useEffect(()=>{
        if (!enabled || 'none' === dragState.type) return;
        const handleMouseMove = (e)=>{
            if (!dragStartRef.current) return;
            if (null !== rafRef.current) cancelAnimationFrame(rafRef.current);
            rafRef.current = requestAnimationFrame(()=>{
                const start = screenToFlowPosition(dragStartRef.current, {
                    snapToGrid: false
                });
                const current = screenToFlowPosition({
                    x: e.clientX,
                    y: e.clientY
                }, {
                    snapToGrid: false
                });
                const delta = {
                    x: current.x - start.x,
                    y: current.y - start.y
                };
                if ('waypoint' === dragState.type) {
                    const initial = dragState.initialWaypoints[dragState.waypointIndex];
                    if (!initial) return;
                    updateWaypoints(moveWaypoint(dragState.initialWaypoints, dragState.waypointIndex, {
                        x: initial.x + delta.x,
                        y: initial.y + delta.y
                    }));
                } else if ('segment' === dragState.type) updateWaypoints(moveSegmentByDelta(dragState.initialWaypoints, dragState.segment, delta, dragState.initialPathPoints));
            });
        };
        const handleMouseUp = ()=>{
            if (null !== rafRef.current) {
                cancelAnimationFrame(rafRef.current);
                rafRef.current = null;
            }
            setDragState({
                type: 'none'
            });
            dragStartRef.current = null;
        };
        window.addEventListener('mousemove', handleMouseMove);
        window.addEventListener('mouseup', handleMouseUp);
        return ()=>{
            window.removeEventListener('mousemove', handleMouseMove);
            window.removeEventListener('mouseup', handleMouseUp);
            if (null !== rafRef.current) cancelAnimationFrame(rafRef.current);
        };
    }, [
        enabled,
        dragState,
        updateWaypoints,
        screenToFlowPosition
    ]);
    const waypointHandlers = useMemo(()=>({
            onMouseDown: (index, e)=>{
                if (!enabled) return;
                e.stopPropagation();
                e.preventDefault();
                dragStartRef.current = {
                    x: e.clientX,
                    y: e.clientY
                };
                setDragState({
                    type: 'waypoint',
                    waypointIndex: index,
                    initialWaypoints: [
                        ...waypointsRef.current
                    ]
                });
            },
            onDoubleClick: (index)=>{
                if (!enabled) return;
                updateWaypoints(removeWaypoint(waypointsRef.current, index));
            }
        }), [
        enabled,
        updateWaypoints
    ]);
    const segmentHandlers = useMemo(()=>({
            onMouseDown: (segment, e)=>{
                if (!enabled) return;
                e.stopPropagation();
                e.preventDefault();
                dragStartRef.current = {
                    x: e.clientX,
                    y: e.clientY
                };
                const materialized = materializePathWaypoints(pathPointsRef.current, waypointsRef.current);
                setDragState({
                    type: 'segment',
                    segment,
                    initialWaypoints: materialized,
                    initialPathPoints: [
                        ...pathPointsRef.current
                    ]
                });
            },
            onDoubleClick: (segmentIndex, e)=>{
                if (!enabled) return;
                e.stopPropagation();
                e.preventDefault();
                const flowPoint = screenToFlowPosition({
                    x: e.clientX,
                    y: e.clientY
                });
                const snapped = snapPointToGrid(flowPoint);
                updateWaypoints(insertWaypoint(pathPointsRef.current, waypointsRef.current, segmentIndex, snapped));
            }
        }), [
        enabled,
        screenToFlowPosition,
        updateWaypoints
    ]);
    const isDragging = enabled && 'none' !== dragState.type;
    return useMemo(()=>({
            isDragging,
            waypointHandlers,
            segmentHandlers
        }), [
        isDragging,
        waypointHandlers,
        segmentHandlers
    ]);
}
export { useWaypointEditor };
