"use client";

import { useEffect, useRef } from "react";
import * as THREE from "three";
import { GLTFLoader } from "three-stdlib";
import { OrbitControls } from "three-stdlib";
import { toast, Toaster } from "sonner";

export default function GLTFViewer() {
    const mountRef = useRef<HTMLDivElement>(null);

    useEffect(() => {
        if (!mountRef.current) return;

        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x0b0b0b);

        const camera = new THREE.PerspectiveCamera(
            75,
            mountRef.current.clientWidth / mountRef.current.clientHeight,
            0.1,
            1000
        );

        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(mountRef.current.clientWidth, mountRef.current.clientHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
        mountRef.current.appendChild(renderer.domElement);

        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;

        scene.add(new THREE.AmbientLight(0xffffff, 1.5));
        const dirLight = new THREE.DirectionalLight(0xffffff, 2);
        dirLight.position.set(5, 10, 5);
        scene.add(dirLight);

        const loader = new GLTFLoader();
        let mixer: THREE.AnimationMixer | null = null;
        const wireframeLines: THREE.LineSegments[] = [];

        loader.load(
            "/ring.gltf",
            (gltf) => {
                const model = gltf.scene;

                // Center and scale
                const box = new THREE.Box3().setFromObject(model);
                const size = box.getSize(new THREE.Vector3()).length();
                const center = box.getCenter(new THREE.Vector3());
                model.position.sub(center);
                model.scale.setScalar(2 / size);

                scene.add(model);

                model.traverse((child) => {
                    if ((child as THREE.Mesh).isMesh) {
                        const mesh = child as THREE.Mesh;
                        mesh.visible = false;

                        // Use WireframeGeometry (always works)
                        const edgeThreshold = 9; // degrees (try 10–40)
                        const wireGeometry = new THREE.EdgesGeometry(
                            mesh.geometry,
                            THREE.MathUtils.degToRad(edgeThreshold)
                        );

                        const wireframeLine = new THREE.LineSegments(
                            wireGeometry,
                            new THREE.LineBasicMaterial({ color: 0x00ff00 })
                        );

                        wireframeLine.position.copy(mesh.position);
                        wireframeLine.rotation.copy(mesh.rotation);
                        wireframeLine.scale.copy(mesh.scale);

                        wireframeLines.push(wireframeLine);
                        scene.add(wireframeLine);
                    }
                });

                if (gltf.animations.length > 0) {
                    mixer = new THREE.AnimationMixer(model);
                    gltf.animations.forEach((clip) => mixer!.clipAction(clip).play());
                }

                camera.position.set(size / 2, size / 4, size / 2);
                camera.lookAt(0, 0, 0);
            },
            undefined,
            (err) => console.error("GLTF LOAD ERROR", err)
        );

        // Click-to-copy only if not dragging
        const raycaster = new THREE.Raycaster();
        const mouse = new THREE.Vector2();
        const COPY_STRING = "ssh krishna@ayyalasomayajula.net";
        let mouseDownPos: { x: number; y: number } | null = null;
        const DRAG_THRESHOLD = 2;

        function onMouseDown(event: MouseEvent) {
            mouseDownPos = { x: event.clientX, y: event.clientY };
        }

        function onClick(event: MouseEvent) {
            if (!mouseDownPos) return;
            const dx = event.clientX - mouseDownPos.x;
            const dy = event.clientY - mouseDownPos.y;
            if (Math.sqrt(dx * dx + dy * dy) > DRAG_THRESHOLD) return;
            if (wireframeLines.length === 0) return;

            const rect = renderer.domElement.getBoundingClientRect();
            mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
            mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

            raycaster.setFromCamera(mouse, camera);

            for (const wf of wireframeLines) {
                const intersects = raycaster.intersectObject(wf);
                if (intersects.length > 0) {
                    navigator.clipboard.writeText(COPY_STRING).then(() => {
                        toast.success(`Copied: ${COPY_STRING}`);
                    });
                    break;
                }
            }
        }

        renderer.domElement.addEventListener("mousedown", onMouseDown);
        window.addEventListener("click", onClick);

        const clock = new THREE.Clock();
        const animate = () => {
            requestAnimationFrame(animate);
            const delta = clock.getDelta();
            if (mixer) mixer.update(delta);
            controls.update();
            renderer.render(scene, camera);
        };
        animate();

        const handleResize = () => {
            if (!mountRef.current) return;
            camera.aspect = mountRef.current.clientWidth / mountRef.current.clientHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(mountRef.current.clientWidth, mountRef.current.clientHeight);
        };
        window.addEventListener("resize", handleResize);

        return () => {
            window.removeEventListener("resize", handleResize);
            window.removeEventListener("click", onClick);
            renderer.domElement.removeEventListener("mousedown", onMouseDown);
            mountRef.current?.removeChild(renderer.domElement);
        };
    }, []);

    return (
        <div ref={mountRef} className="w-full h-full">
            <Toaster
                theme="dark"
                richColors
                toastOptions= { { style: { color: "limegreen" } } }
            />
        </div>
    );
}
