import * as THREE from "three";

export function handleAssetPositionSnap({
    rawBasePosition,
    intersectionPoint,
    model,
    axisConstraint,
    keyEvent,
    fineMoveBaseRef,
    lastPointerPositionRef,
    wasShiftHeldRef
}: {
    rawBasePosition: THREE.Vector3;
    intersectionPoint: THREE.Vector3;
    model: THREE.Object3D | undefined;
    axisConstraint: "x" | "z" | null;
    keyEvent: string;
    fineMoveBaseRef: React.MutableRefObject<THREE.Vector3 | null>;
    lastPointerPositionRef: React.MutableRefObject<THREE.Vector3 | null>;
    wasShiftHeldRef: React.MutableRefObject<boolean>;
}): THREE.Vector3 {
    const CTRL_DISTANCE = 0.5;
    const SHIFT_DISTANCE = 0.05;
    const CTRL_SHIFT_DISTANCE = 0.05;

    const isShiftHeld = keyEvent.includes("Shift");

    // Handle Shift toggle state
    if (isShiftHeld !== wasShiftHeldRef.current && model) {
        if (isShiftHeld) {
            fineMoveBaseRef.current = model.position.clone();
            lastPointerPositionRef.current = intersectionPoint.clone();
        } else {
            fineMoveBaseRef.current = null;
        }
        wasShiftHeldRef.current = isShiftHeld;
    }

    // Start from raw
    let baseNewPosition = rawBasePosition.clone();

    // Apply snapping / fine move
    if (keyEvent === "Ctrl") {
        baseNewPosition.set(
            Math.round(baseNewPosition.x / CTRL_DISTANCE) * CTRL_DISTANCE,
            baseNewPosition.y,
            Math.round(baseNewPosition.z / CTRL_DISTANCE) * CTRL_DISTANCE
        );
    } else if (keyEvent === "Ctrl+Shift") {
        if (isShiftHeld && fineMoveBaseRef.current && lastPointerPositionRef.current) {
            const pointerDelta = new THREE.Vector3().subVectors(intersectionPoint, lastPointerPositionRef.current);
            baseNewPosition = fineMoveBaseRef.current.clone().add(pointerDelta.multiplyScalar(SHIFT_DISTANCE));
        }
        baseNewPosition.set(
            Math.round(baseNewPosition.x / CTRL_SHIFT_DISTANCE) * CTRL_SHIFT_DISTANCE,
            baseNewPosition.y,
            Math.round(baseNewPosition.z / CTRL_SHIFT_DISTANCE) * CTRL_SHIFT_DISTANCE
        );
    } else if (isShiftHeld && fineMoveBaseRef.current && lastPointerPositionRef.current) {
        const pointerDelta = new THREE.Vector3().subVectors(intersectionPoint, lastPointerPositionRef.current);
        baseNewPosition = fineMoveBaseRef.current.clone().add(pointerDelta.multiplyScalar(SHIFT_DISTANCE));
    }

    // Apply axis constraint last
    if (axisConstraint && model) {
        const currentBasePosition = model.position.clone();
        if (axisConstraint === 'x') {
            baseNewPosition.set(baseNewPosition.x, currentBasePosition.y, currentBasePosition.z);
        } else if (axisConstraint === 'z') {
            baseNewPosition.set(currentBasePosition.x, currentBasePosition.y, baseNewPosition.z);
        }
    }

    return baseNewPosition;
}