import React, { useEffect, useRef, useState } from 'react'
import IKInstance from '../ikInstance/ikInstance';
import RoboticArmAnimator from '../animator/roboticArmAnimator';
import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_4.glb";
import { useThree } from "@react-three/fiber";
import useModuleStore from '../../../../../store/useModuleStore';
import * as THREE from "three";
import { useSelectedAction, useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
import { useProductStore } from '../../../../../store/simulation/useProductStore';


function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {

    const [currentPhase, setCurrentPhase] = useState<(string)>("init");
    const [path, setPath] = useState<[number, number, number][]>([]);
    const [ikSolver, setIkSolver] = useState<any>(null);
    const { scene } = useThree();
    const restPosition = new THREE.Vector3(0, 1.75, -1.6);
    const targetBone = "Target";
    const groupRef = useRef<any>(null);
    const pauseTimeRef = useRef<number | null>(null);
    const isPausedRef = useRef<boolean>(false);
    let startTime: number;
    //zustand
    const { addCurrentAction, setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
    const { getActionByUuid } = useProductStore();
    const { selectedProduct } = useSelectedProduct();
    const { activeModule } = useModuleStore();
    const { isPlaying } = usePlayButtonStore();
    const { isReset, setReset } = useResetButtonStore();
    const { isPaused } = usePauseButtonStore();
    const { selectedAction } = useSelectedAction();

    function firstFrame() {
        startTime = performance.now();
        step();
    }
    function step() {
        if (isPausedRef.current) {
            if (!pauseTimeRef.current) {
                pauseTimeRef.current = performance.now();
            }
            requestAnimationFrame(() => step());
            return;
        }
        if (pauseTimeRef.current) {
            const pauseDuration = performance.now() - pauseTimeRef.current;
            startTime += pauseDuration;
            pauseTimeRef.current = null;
        }
        const elapsedTime = performance.now() - startTime;
        if (elapsedTime < 1000) {
            // Wait until 1500ms has passed
            requestAnimationFrame(step);
            return;
        }
        if (currentPhase === "picking") {
            setArmBotActive(armBot.modelUuid, true);
            setArmBotState(armBot.modelUuid, "running");
            setCurrentPhase("start-to-end");
            startTime = 0
            const startPoint = armBot.point.actions[0].process.startPoint;
            const endPoint = armBot.point.actions[0].process.endPoint;
            if (startPoint && endPoint) {
                let curve = createCurveBetweenTwoPoints(
                    new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]),
                    new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]));
                if (curve) {
                    logStatus(armBot.modelUuid, "picking the object");
                    setPath(curve.points.map(point => [point.x, point.y, point.z]))
                }
            }
            logStatus(armBot.modelUuid, "Moving armBot from start point to end position.")
        } else if (currentPhase === "dropping") {
            setArmBotActive(armBot.modelUuid, true);
            setArmBotState(armBot.modelUuid, "running");
            setCurrentPhase("end-to-rest");
            startTime = 0;
            const endPoint = armBot.point.actions[0].process.endPoint;
            if (endPoint) {

                let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition);
                if (curve) {
                    logStatus(armBot.modelUuid, "dropping the object");
                    setPath(curve.points.map(point => [point.x, point.y, point.z]));
                }
            }
            logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.")
        }
    }
    useEffect(() => {
        isPausedRef.current = isPaused;
    }, [isPaused]);

    useEffect(() => {
        if (isReset || !isPlaying) {
            logStatus(armBot.modelUuid, "Simulation Play Reset Successfully")
            removeCurrentAction(armBot.modelUuid)
            setArmBotActive(armBot.modelUuid, false)
            setArmBotState(armBot.modelUuid, "idle")
            setCurrentPhase("init");
            isPausedRef.current = false
            pauseTimeRef.current = null
            startTime = 0
            const targetBones = ikSolver?.mesh.skeleton.bones.find(
                (b: any) => b.name === targetBone
            );
            if (targetBones) {
                let curve = createCurveBetweenTwoPoints(targetBones.position, restPosition)
                if (curve) {
                    setPath(curve.points.map(point => [point.x, point.y, point.z]));
                }
            }
            setReset(false);
            logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.")
        }
    }, [isReset, isPlaying])

    useEffect(() => {
        const targetMesh = scene?.getObjectByProperty("uuid", armBot.modelUuid);
        if (targetMesh) {
            targetMesh.visible = activeModule !== "simulation"
        }
        const targetBones = ikSolver?.mesh.skeleton.bones.find(
            (b: any) => b.name === targetBone
        );
        if (isPlaying) {

            //Moving armBot from initial point to rest position.
            if (!armBot?.isActive && armBot?.state == "idle" && currentPhase == "init") {

                setArmBotActive(armBot.modelUuid, true)
                setArmBotState(armBot.modelUuid, "running")
                setCurrentPhase("init-to-rest");
                if (targetBones) {
                    let curve = createCurveBetweenTwoPoints(targetBones.position, targetBones.position)
                    if (curve) {
                        setPath(curve.points.map(point => [point.x, point.y, point.z]));
                    }
                }
                logStatus(armBot.modelUuid, "Moving armBot from initial point to rest position.")
            }
            //Waiting for trigger.
            else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && !armBot.currentAction) {
                logStatus(armBot.modelUuid, "Waiting to trigger CurrentAction")
                const timeoutId = setTimeout(() => {
                    addCurrentAction(armBot.modelUuid, armBot.point.actions[0].actionUuid);
                }, 3000);
                return () => clearTimeout(timeoutId);
            }
            else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "rest" && armBot.currentAction) {
                if (armBot.currentAction) {

                    setArmBotActive(armBot.modelUuid, true);
                    setArmBotState(armBot.modelUuid, "running");
                    setCurrentPhase("rest-to-start");
                    const startPoint = armBot.point.actions[0].process.startPoint;
                    if (startPoint) {
                        let curve = createCurveBetweenTwoPoints(targetBones.position, new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]));
                        if (curve) {
                            setPath(curve.points.map(point => [point.x, point.y, point.z]));
                        }
                    }
                }
                logStatus(armBot.modelUuid, "Moving armBot from rest point to start position.")
            }
            else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "picking" && armBot.currentAction) {
                requestAnimationFrame(firstFrame);
                // setArmBotActive(armBot.modelUuid, true);
                // setArmBotState(armBot.modelUuid, "running");
                // setCurrentPhase("start-to-end");
                // const startPoint = armBot.point.actions[0].process.startPoint;
                // const endPoint = armBot.point.actions[0].process.endPoint;
                // if (startPoint && endPoint) {
                //     let curve = createCurveBetweenTwoPoints(
                //         new THREE.Vector3(startPoint[0], startPoint[1], startPoint[2]),
                //         new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]));
                //     if (curve) {
                //         setTimeout(() => {
                //             logStatus(armBot.modelUuid, "picking the object");
                //             setPath(curve.points.map(point => [point.x, point.y, point.z]));
                //         }, 1500)
                //     }
                // }
                // logStatus(armBot.modelUuid, "Moving armBot from start point to end position.")
            }
            else if (armBot && !armBot.isActive && armBot.state === "idle" && currentPhase === "dropping" && armBot.currentAction) {
                requestAnimationFrame(firstFrame);
                // setArmBotActive(armBot.modelUuid, true);
                // setArmBotState(armBot.modelUuid, "running");
                // setCurrentPhase("end-to-rest");
                // const endPoint = armBot.point.actions[0].process.endPoint;
                // if (endPoint) {
                //     let curve = createCurveBetweenTwoPoints(new THREE.Vector3(endPoint[0], endPoint[1], endPoint[2]), restPosition);
                //     if (curve) {
                //         setTimeout(() => {
                //             logStatus(armBot.modelUuid, "dropping the object");
                //             setPath(curve.points.map(point => [point.x, point.y, point.z]));
                //         }, 1500)
                //     }
                // }
                // logStatus(armBot.modelUuid, "Moving armBot from end point to rest position.")
            }
        } else {
            logStatus(armBot.modelUuid, "Simulation Play Exited")
            setArmBotActive(armBot.modelUuid, false)
            setArmBotState(armBot.modelUuid, "idle")
            setCurrentPhase("init");
            setPath([])
            isPausedRef.current = false
            pauseTimeRef.current = null
            isPausedRef.current = false
            startTime = 0
            removeCurrentAction(armBot.modelUuid)
        }

    }, [currentPhase, armBot, isPlaying, ikSolver])


    function createCurveBetweenTwoPoints(p1: any, p2: any) {
        const mid = new THREE.Vector3().addVectors(p1, p2).multiplyScalar(0.5);
        // mid.y += 0.5;
        const points = [p1, mid, p2];
        return new THREE.CatmullRomCurve3(points);
    }


    const HandleCallback = () => {
        if (armBot.isActive && armBot.state == "running" && currentPhase == "init-to-rest") {
            logStatus(armBot.modelUuid, "Callback triggered: rest");
            setArmBotActive(armBot.modelUuid, false)
            setArmBotState(armBot.modelUuid, "idle")
            setCurrentPhase("rest");
            setPath([])
        }
        else if (armBot.isActive && armBot.state == "running" && currentPhase == "rest-to-start") {
            logStatus(armBot.modelUuid, "Callback triggered: pick.");
            setArmBotActive(armBot.modelUuid, false)
            setArmBotState(armBot.modelUuid, "idle")
            setCurrentPhase("picking");
            setPath([])
        }
        else if (armBot.isActive && armBot.state == "running" && currentPhase == "start-to-end") {
            logStatus(armBot.modelUuid, "Callback triggered: drop.");
            setArmBotActive(armBot.modelUuid, false)
            setArmBotState(armBot.modelUuid, "idle")
            setCurrentPhase("dropping");
            setPath([])
        }
        else if (armBot.isActive && armBot.state == "running" && currentPhase == "end-to-rest") {
            logStatus(armBot.modelUuid, "Callback triggered: rest, cycle completed.");
            setArmBotActive(armBot.modelUuid, false)
            setArmBotState(armBot.modelUuid, "idle")
            setCurrentPhase("rest");
            setPath([])
            removeCurrentAction(armBot.modelUuid)
        }
    }
    const logStatus = (id: string, status: string) => {
        
        // 

    }

    return (
        <>
            <IKInstance modelUrl={armModel} setIkSolver={setIkSolver} ikSolver={ikSolver} armBot={armBot} groupRef={groupRef} />
            <RoboticArmAnimator HandleCallback={HandleCallback} restPosition={restPosition} ikSolver={ikSolver} targetBone={targetBone} armBot={armBot}
                logStatus={logStatus} path={path} currentPhase={currentPhase} />
        </>
    )
}

export default RoboticArmInstance;
