import * as THREE from "three";

export function handleAssetRotationSnap({
    object,
    pointerDeltaX,
    keyEvent,
    snapBaseRef,
    prevRotationRef,
    wasShiftHeldRef
}: {
    object: THREE.Object3D;
    pointerDeltaX: number;
    keyEvent: string;
    snapBaseRef: React.MutableRefObject<number | null>;
    prevRotationRef: React.MutableRefObject<number | null>;
    wasShiftHeldRef: React.MutableRefObject<boolean>;
}): number {
    const SHIFT_SPEED = 0.5;  // Fine rotation speed
    const NORMAL_SPEED = 5;   // Normal rotation speed
    const CTRL_SNAP_DEG = 15;     // 15 degrees
    const CTRL_SHIFT_SNAP_DEG = 5; // 5 degrees

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

    const speedFactor = isShiftHeld ? SHIFT_SPEED : NORMAL_SPEED;
    let deltaAngle = pointerDeltaX * speedFactor;

    // Track if modifier changed
    const modifierChanged = isShiftHeld !== wasShiftHeldRef.current;
    if (modifierChanged) {
        wasShiftHeldRef.current = isShiftHeld;
        if (isCtrlHeld) snapBaseRef.current = null;
    }

    if (isCtrlHeld) {
        const snapDeg = isShiftHeld ? CTRL_SHIFT_SNAP_DEG : CTRL_SNAP_DEG;
        const snapRad = THREE.MathUtils.degToRad(snapDeg);

        // Get current Y rotation from object's quaternion
        const euler = new THREE.Euler().setFromQuaternion(object.quaternion, 'YXZ');
        let currentAngle = euler.y;

        // Initialize snap base on first frame
        if (snapBaseRef.current === null) {
            snapBaseRef.current = currentAngle;
            prevRotationRef.current = currentAngle;
        }

        // Accumulate the total rotation from the base
        const totalRotation = snapBaseRef.current + deltaAngle;

        // Snap to nearest increment
        const snappedAngle = Math.round(totalRotation / snapRad) * snapRad;

        // Calculate the delta needed to reach the snapped angle from current rotation
        let targetDelta = snappedAngle - currentAngle;

        // Handle wrapping around 360 degrees
        if (Math.abs(targetDelta) > Math.PI) {
            targetDelta = targetDelta - Math.sign(targetDelta) * 2 * Math.PI;
        }

        // Update snap base for next frame
        snapBaseRef.current = totalRotation;

        return targetDelta;
    } else {
        // Reset snapping when Ctrl is not held
        snapBaseRef.current = null;
        prevRotationRef.current = null;
        return deltaAngle;
    }
}