<script lang="ts">
	import { T } from "@threlte/core";
	import { Group } from "three";
	import { getRootLinks } from "@/components/3d/elements/robot/URDF/utils/UrdfParser";
	import UrdfLink from "@/components/3d/elements/robot/URDF/primitives/UrdfLink.svelte";
	import RobotStatusBillboard from "@/components/3d/elements/robot/status/RobotStatusBillboard.svelte";
	import type { Robot } from "$lib/elements/robot/Robot.svelte.js";
	import { createUrdfRobot } from "$lib/elements/robot/createRobot.svelte";
	import { type IntersectionEvent, useCursor } from "@threlte/extras";
	import type { RobotUrdfConfig } from "$lib/types/urdf";
	import { onMount } from "svelte";
	import type IUrdfRobot from "@/components/3d/elements/robot/URDF/interfaces/IUrdfRobot.js";
	import { ROBOT_CONFIG } from "$lib/elements/robot/config.js";

	interface Props {
		robot: Robot;
		onCameraMove: (ref: any) => void;
		onInputBoxClick: (robot: Robot) => void;
		onRobotBoxClick: (robot: Robot) => void;
		onOutputBoxClick: (robot: Robot) => void;
	}

	let ref = $state<Group | undefined>(undefined);

	let {
		robot = $bindable(),
		onCameraMove,
		onInputBoxClick,
		onRobotBoxClick,
		onOutputBoxClick
	}: Props = $props();

	let urdfRobotState = $state<IUrdfRobot | null>(null);
	let lastJointValues = $state<Record<string, number>>({});

	onMount(async () => {
		const urdfConfig: RobotUrdfConfig = {
			urdfUrl: "/robots/so-100/so_arm100.urdf"
		};

		try {
			const UrdfRobotState = await createUrdfRobot(urdfConfig);
			urdfRobotState = UrdfRobotState.urdfRobot;
		} catch (error) {
			console.error("Failed to load URDF robot:", error);
		}
	});

	// Sync joint values from Robot to URDF joints with optimized updates
	$effect(() => {
		if (!urdfRobotState) return;
		if (robot.jointArray.length === 0) return;

		// Check if this is the initial sync (no previous values recorded)
		const isInitialSync = Object.keys(lastJointValues).length === 0;

		// Check if any joint values have actually changed (using config threshold)
		const threshold = isInitialSync ? 0 : ROBOT_CONFIG.performance.uiUpdateThreshold;
		const hasSignificantChanges =
			isInitialSync ||
			robot.jointArray.some(
				(joint) => Math.abs((lastJointValues[joint.name] || 0) - joint.value) > threshold
			);
		if (!hasSignificantChanges) return;

		// Batch update all joints that have changed (or all joints on initial sync)
		let updatedCount = 0;
		robot.jointArray.forEach((joint) => {
			if (!urdfRobotState) return;
			if (isInitialSync || Math.abs((lastJointValues[joint.name] || 0) - joint.value) > threshold) {
				lastJointValues[joint.name] = joint.value;
				const urdfJoint = findUrdfJoint(urdfRobotState, joint.name);
				if (urdfJoint) {
					// Initialize rotation array if it doesn't exist
					if (!urdfJoint.rotation) {
						urdfJoint.rotation = [0, 0, 0];
					}

					// Use the Robot's conversion method for proper coordinate mapping
					const radians = robot.convertNormalizedToUrdfRadians(joint.name, joint.value);
					const axis = urdfJoint.axis_xyz || [0, 0, 1];

					// Reset rotation and apply to the appropriate axis
					urdfJoint.rotation = [0, 0, 0];
					for (let i = 0; i < 3; i++) {
						if (Math.abs(axis[i]) > 0.001) {
							urdfJoint.rotation[i] = radians * axis[i];
						}
					}
					updatedCount++;
				}
			}
		});
	});

	function findUrdfJoint(robot: IUrdfRobot, jointName: string): any {
		// Search through the robot's joints array
		if (robot.joints && Array.isArray(robot.joints)) {
			for (const joint of robot.joints) {
				if (joint.name === jointName) {
					return joint;
				}
			}
		}
		return null;
	}

	const { onPointerEnter, onPointerLeave, hovering } = useCursor();
	

	let isToggled = $state(false);

	function handleClick(event: IntersectionEvent<MouseEvent>) {
		event.stopPropagation();
		isToggled = !isToggled;
	}
</script>

<T.Group
	bind:ref
	position.x={robot.position.x}
	position.y={robot.position.y}
	position.z={robot.position.z}
	scale={[10, 10, 10]}
	rotation={[-Math.PI / 2, 0, 0]}
>
	<T.Group onpointerenter={(event) => {
		event.stopPropagation();
		onPointerEnter();
	}} onpointerleave={(event) => {
		event.stopPropagation();
		onPointerLeave();
	}} onclick={handleClick}>
		{#if urdfRobotState}
			{#each getRootLinks(urdfRobotState) as link}
				<UrdfLink
					robot={urdfRobotState}
					{link}
					textScale={0.2}
					showName={$hovering || isToggled}
					showVisual={true}
					showCollision={false}
					visualColor={robot.connectionStatus.isConnected ? "#10b981" : "#6b7280"}
					visualOpacity={$hovering || isToggled ? 0.4 : 1.0}
					collisionOpacity={1.0}
					collisionColor="#813d9c"
					jointNames={$hovering}
					joints={$hovering}
					jointColor="#62a0ea"
					jointIndicatorColor="#f66151"
					nameHeight={0.1}
					showLine={$hovering || isToggled}
					opacity={1}
				/>
			{/each}
		{:else}
			<!-- Fallback simple representation while URDF loads -->
			<T.Mesh>
				<T.BoxGeometry args={[0.1, 0.1, 0.1]} />
				<T.MeshStandardMaterial
					color={robot.connectionStatus.isConnected ? "#10b981" : "#6b7280"}
					opacity={$hovering ? 0.8 : 1.0}
					transparent
				/>
			</T.Mesh>
		{/if}
	</T.Group>

	<RobotStatusBillboard
		{robot}
		{onInputBoxClick}
		{onRobotBoxClick}
		{onOutputBoxClick}
		visible={isToggled}
	/>
</T.Group>
