import { createContext, ReactNode, useContext, useMemo, useState } from "react";
import { SCALE_FACTOR, UP_SCALE } from "./Constants";


const TransformContext = createContext<{
    position: { x: number, y: number },
    scale: number,
    rotation: number,
    screenCenter?: { x: number, y: number },

    setPosition: React.Dispatch<React.SetStateAction<{ x: number, y: number }>>,
    setScale: React.Dispatch<React.SetStateAction<number>>,
    setRotation: React.Dispatch<React.SetStateAction<number>>,
	screenToLocal: (x: number, y: number) => { x: number, y: number },
	localToScreen: (x: number, y: number) => { x: number, y: number },
	rotateToAngle: (to: number, fromPosition?: {x: number, y: number}) => void,
	setTransform: (latitude: number, longitude: number, rotationDegrees?: number, scale?: number) => void,
    setScreenCenter: React.Dispatch<React.SetStateAction<{ x: number, y: number } | undefined>>
}>({
    position: { x: 0, y: 0 },
    scale: 1,
    rotation: 0,
    screenCenter: undefined,
    setPosition: () => {},
    setScale: () => {},
    setRotation: () => {},
	screenToLocal: () => ({ x: 0, y: 0 }),
	localToScreen: () => ({ x: 0, y: 0 }),
	rotateToAngle: () => {},
	setTransform: () => {},
    setScreenCenter: () => {}
});

// Provider component
export const TransformProvider = ({ children }: { children: ReactNode }) => {
    const [position, setPosition] = useState({ x: 0, y: 0 });
    const [scale, setScale] = useState(1);
    const [rotation, setRotation] = useState(0);
    const [screenCenter, setScreenCenter] = useState<{x: number, y: number}>();

    function screenToLocal(screenX: number, screenY: number) {
        // Translate point relative to current pan position
        const translatedX = (screenX - position.x) / scale;
        const translatedY = (screenY - position.y) / scale;

        // Rotate point around center
        const cosRotation = Math.cos(-rotation); // Negative rotation to reverse transform
        const sinRotation = Math.sin(-rotation);
        const rotatedX = translatedX * cosRotation - translatedY * sinRotation;
        const rotatedY = translatedX * sinRotation + translatedY * cosRotation;

        return {
            x: rotatedX / UP_SCALE,
            y: rotatedY / UP_SCALE
        };
    }

    // Inverse of screenToLocal
    function localToScreen(localX: number, localY: number) {

        const upscaledX = localX * UP_SCALE;
        const upscaledY = localY * UP_SCALE;

        const cosRotation = Math.cos(rotation);
        const sinRotation = Math.sin(rotation);
        const rotatedX = upscaledX * cosRotation - upscaledY * sinRotation;
        const rotatedY = upscaledX * sinRotation + upscaledY * cosRotation;

        const translatedX = rotatedX*scale + position.x;
        const translatedY = rotatedY*scale + position.y;

        return {
            x: translatedX,
            y: translatedY
        };
    }
    


	function rotateToAngle(to: number, fromPosition?: {x: number, y: number}) {
        setRotation(to);
        const rotationDiff = to - rotation;
        
		const center = screenCenter ?? {x: 0, y: 0};
		const cosDelta = Math.cos(rotationDiff);
		const sinDelta = Math.sin(rotationDiff);

        fromPosition ??= position;

		setPosition({
			x: center.x * (1 - cosDelta) + fromPosition.x * cosDelta + (center.y - fromPosition.y) * sinDelta,
			y: center.y * (1 - cosDelta) + fromPosition.y * cosDelta + (fromPosition.x - center.x) * sinDelta
		});
	}

    function setTransform(latitude: number, longitude: number, rotationDegrees?: number, useScale   ?: number) {
        const selectedRotation = rotationDegrees ? (rotationDegrees * Math.PI / 180) : rotation;
        const selectedScale = useScale ? useScale/SCALE_FACTOR : scale;
        const center = screenCenter ?? {x: 0, y: 0};
        console.log("center", center.x, center.y);
        const newPosition = {
            x: -latitude * UP_SCALE * selectedScale,
            y: -longitude * UP_SCALE * selectedScale
        };

        const cos = Math.cos(selectedRotation);
        const sin = Math.sin(selectedRotation);
        
        // Translate point relative to center, rotate, then translate back
        const dx = newPosition.x;
        const dy = newPosition.y;
        newPosition.x = (dx * cos - dy * sin) + center.x;
        newPosition.y = (dx * sin + dy * cos) + center.y;

        
        setPosition(newPosition);
        setRotation(selectedRotation);
        setScale(selectedScale);
    }

    const value = useMemo(() => ({
        position,
        scale,
        rotation,
        screenCenter,
        setPosition,
        setScale,
        setRotation,
        rotateToAngle,
		screenToLocal,
        localToScreen,
        setTransform,
        setScreenCenter
    }), [position, scale, rotation, screenCenter]);

    return (
        <TransformContext.Provider value={value}>
            {children}
        </TransformContext.Provider>
    );
};

// Custom hook for easy access to transform values
export const useTransform = () => {
    const context = useContext(TransformContext);
    if (!context) {
        throw new Error('useTransform must be used within a TransformProvider');
    }
    return context;
};