import * as THREE from "../node_modules/three/build/three.module.js"
import { VRButton } from "../node_modules/three/examples/jsm/webxr/VRButton.js";
import { XRControllerModelFactory } from "../node_modules/three/examples/jsm/webxr/XRControllerModelFactory.js";
import { XRHandModelFactory } from "../node_modules/three/examples/jsm/webxr/XRHandModelFactory.js";
import { OrbitControls } from "../node_modules/three/examples/jsm/controls/OrbitControls.js";

import { OculusHandModel } from "../node_modules/three/examples/jsm/webxr/OculusHandModel.js";
import { OculusHandPointerModel } from "../node_modules/three/examples/jsm/webxr/OculusHandPointerModel.js";
import { STLLoader } from "../node_modules/three/examples/jsm/loaders/STLLoader.js";




const scene = new THREE.Scene();
const zHinten = -1.0;
const yOben = 0.0;

function main() {

  const renderer = new THREE.WebGLRenderer({canvas: document.querySelector('#c')});
  const handModelFactory = new XRHandModelFactory();
  const fov = 45;
  const aspect = window.innerWidth/window.innerHeight;  // the canvas default
  const near = 0.1;
  const far = 150;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.set(-0.5, 1.0, 1.0);
  
  


  renderer.setSize( window.innerWidth, window.innerHeight );
  renderer.setClearColor( 0xffffff );
  document.body.appendChild(renderer.domElement );

  renderer.xr.enabled = true;
  document.body.appendChild(VRButton.createButton(renderer));

  var controls = new OrbitControls(camera, renderer.domElement);
  
  const color = 0xFFFFFF;
  const intensity = 1.1;
  const light = new THREE.DirectionalLight(color, intensity);
  light.position.set(-1, 2, 4);
  scene.add(light);

    
  const ambient = new THREE.AmbientLight(0xffffff, 0.5);
  scene.add(ambient);

  const hemi = new THREE.HemisphereLight(0xfffffb, 0x444444, 0.18);
  hemi.position.set(0, 10, 0);
  scene.add(hemi);

  const geometry = new THREE.BoxGeometry(0.05, 0.05, 0.05);
  const material = new THREE.MeshPhongMaterial({color:0x44aa88});
  const cube = new THREE.Mesh(geometry, material);
  scene.add(cube);
  cube.position.set(-0.5,0,zHinten);

  const axesHelper = new THREE.AxesHelper(2);
  axesHelper.position.set(0,0,zHinten);
  scene.add( axesHelper );
  

  // Hands
  if(typeof renderer !== "undefined"){

      const controllerModelFactory = new XRControllerModelFactory();

      
      // Hand 0 = Links
      const controllerGripL = renderer.xr.getControllerGrip( 0 );
      controllerGripL.add( controllerModelFactory.createControllerModel( controllerGripL ) );
      scene.add( controllerGripL );
      const handL = renderer.xr.getHand( 0 );
      handL.addEventListener( 'pinchend', () => {
        //scaling.active = false;
        
        var p = handR.joints[ 'thumb-tip' ].position;
        //socket.send("Info: L x="+p.x+" y="+(p.y-yOben)+" z="+p.z);
      } );
      handL.add( handModelFactory.createHandModel( handL ) );
      scene.add( handL );

      // Hand 1 = Rechts
      const controllerGripR = renderer.xr.getControllerGrip( 1 );
      controllerGripR.add( controllerModelFactory.createControllerModel( controllerGripR ) );
      scene.add( controllerGripR );
      const handR = renderer.xr.getHand( 1 );
      handR.addEventListener( 'pinchend', () => {
        //scaling.active = false;
        var p = handR.joints[ 'thumb-tip' ].position;
        //socket.send("Info: R x="+p.x+" y="+(p.y-yOben)+" z="+p.z); 
        socket.send("Info: Raum x="+(p.x*1000)+" y="+(-1.0*p.z*1000)+" z="+((p.y-yOben)*1000));
        robot.x = -(p.x*1000);
        robot.y = (1.0*(p.z-zHinten)*1000);
        robot.z = ((p.y-yOben)*1000);
        robot.processAndShow();

      } );
      handR.add( handModelFactory.createHandModel( handR ) );
      scene.add( handR );
    }

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  
  
  function render(time) {
    time *= 0.001;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }

    const speed = 1 + .1;
    const rot = time * speed;
    cube.rotation.x = rot;
    cube.rotation.y = rot;
    
    renderer.render(scene, camera);
  }

  renderer.setAnimationLoop(render);
  
}

main();


var bauteile = [];


function show3D(r){

    if(bauteile.length == 0){

        // Weißes, leicht transluzentes PLA-ähnliches Material
        var matPLA = new THREE.MeshPhysicalMaterial({
          color: 0xffffff,
          metalness: 0.0,
          roughness: 0.55,
          transmission: 0.05,
          opacity: 0.98,
          transparent: true,
          clearcoat: 0.0
        });

        // Holz Anfnag 
        // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

        const holz = new THREE.ShaderMaterial({
          uniforms: {
            ringWidth:      { value: 0.006 },   // Abstand der Ringe
            seed:           { value: 42.0 },
            grainScale:     { value: 180.0 },   // Skaliert die feine Maserung
            ringJitter:     { value: 0.45 },    // wie stark die Ringpositionen variieren
            thicknessMin:   { value: 0.028 },   // minimale Ringdicke
            thicknessMax:   { value: 0.065 },   // maximale Ringdicke
            rayIntensity:   { value: 0.14 },    // Stärke der „Holzstrahlen“
            warble:         { value: 0.008 }    // Verzerrung der Ringe (welliger Effekt)
          },
          vertexShader: `
            varying vec3 vW;
            void main() {
              vec4 wp = modelMatrix * vec4(position,1.0);
              vW = wp.xyz;
              gl_Position = projectionMatrix * viewMatrix * wp;
            }
          `,
          fragmentShader: `
            varying vec3 vW;
            uniform float ringWidth;
            uniform float seed;
            uniform float grainScale;
            uniform float ringJitter;
            uniform float thicknessMin;
            uniform float thicknessMax;
            uniform float rayIntensity;
            uniform float warble;

            float hash(vec3 p) {
              return fract(sin(dot(p + seed, vec3(127.1,311.7,74.7))) * 43758.5453);
            }

            float noise(vec3 p) {
              vec3 i = floor(p);
              vec3 f = fract(p);
              f = f*f*(3.0-2.0*f);
              float a = hash(i);
              float b = hash(i+vec3(1.0,0.0,0.0));
              float c = hash(i+vec3(0.0,1.0,0.0));
              float d = hash(i+vec3(1.0,1.0,0.0));
              float e = hash(i+vec3(0.0,0.0,1.0));
              float f1 = hash(i+vec3(1.0,0.0,1.0));
              float g = hash(i+vec3(0.0,1.0,1.0));
              float h = hash(i+vec3(1.0,1.0,1.0));
              return mix(mix(mix(a,b,f.x), mix(c,d,f.x), f.y),
                        mix(mix(e,f1,f.x), mix(g,h,f.x), f.y), f.z);
            }

            float fbm(vec3 p){
              float v = 0.0;
              float amp = 0.5;
              for(int i=0;i<5;i++){
                v += amp * noise(p);
                p *= 2.0;
                amp *= 0.5;
              }
              return v;
            }

            void main() {
              vec2 center = vec2(-0.3, 0.0);
              vec2 pos = vW.xz - center;

              float r = length(pos);
              float ang = atan(pos.y, pos.x);

              float warp = fbm(vec3(vW.x*3.0, vW.y*1.0, vW.z*3.0)) * warble;
              r += warp;

              float base = r / ringWidth;
              float jitter = fbm(vec3(vW.x*1.2, vW.y*0.5, vW.z*1.2)) * ringJitter;
              float ringsVal = fract(base + jitter);

              float tNoise = fbm(vec3(vW.x*12.0, vW.y*6.0, vW.z*12.0));
              float thickness = mix(thicknessMin, thicknessMax, tNoise);

              float d = abs(ringsVal - 0.5);

              // Ringmask mit stärkerem Kontrast
              float ringMask = 1.0 - smoothstep(0.0, thickness, d);
              ringMask = pow(ringMask, 1.5);

              float grain = fbm(vec3(vW.x * (grainScale * 0.001), vW.y * 0.02, vW.z * (grainScale * 0.001)));
              grain = grain * 0.5 + 0.5;

              float raysNoise = fbm(vec3(vW.x*6.0, vW.y*3.0, vW.z*6.0));
              float rays = pow(max(0.0, cos(ang * 12.0 + raysNoise * 6.2831)), 16.0) * rayIntensity;

              // Farben: leicht mehr Kontrast
              vec3 c1 = vec3(0.85, 0.65, 0.42); // hell
              vec3 c2 = vec3(0.72, 0.50, 0.32); // mittel
              vec3 c3 = vec3(0.55, 0.38, 0.20); // dunkel

              vec3 baseColor = mix(c2, c1, (grain * 0.25 + 0.25));

              vec3 color = mix(baseColor, c3, ringMask * 0.75);
              color *= (1.0 - rays * 0.85);

              float spots = fbm(vec3(vW.x*30.0, vW.y*6.0, vW.z*30.0));
              color += (spots - 0.5) * 0.015;

              color = clamp(color, 0.0, 1.0);
              gl_FragColor = vec4(color, 1.0);
            }
          `
        });

        // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        // Holz Ende

        
        var material = new THREE.MeshStandardMaterial( { color: 0x22ee22, roughness: 0.2, metalness: 0.2} );
        
        // 00: BodenBrett, 61mm unter der Achse, 24mm vor der Achse
        var brettBox = new THREE.BoxGeometry( 0.8, 0.027, 0.078);
        var brettMesh = new THREE.Mesh( brettBox, holz );
        brettMesh.geometry.translate(0,-0.061-0.027/2,-1+0.078/2+0.024);

        scene.add( brettMesh );

        // 0: BasisBox
        var basisBox = new THREE.BoxGeometry( 0.060, 0.080, 0.080 );
        var m2 = new THREE.MeshStandardMaterial({ color: 0xadd8e6, roughness: 0.2, metalness: 0.2});
        var basisMesh = new THREE.Mesh( basisBox, material );
        basisMesh.castShadow = true;
        scene.add( basisMesh );
        var stlLoader = new STLLoader();
        stlLoader.load('/model/Robot7M/1_01_Bodenplatte.stl', function (geometry) {
          // dunkelblaue, hochglänzende Lack-/Pulverbeschichtung
          var matO = new THREE.MeshStandardMaterial({
            color: 0x0b3d91,
            metalness: 0.15,
            roughness: 0.08,
            clearcoat: 1.0,
            clearcoatRoughness: 0.02
          });
          var mesh = new THREE.Mesh( geometry, matO );
          mesh.castShadow = true;
          mesh.rotation.x = Math.PI/2;
          mesh.rotation.z = 0;
          mesh.rotation.y = 0;
          mesh.scale.set(0.001, 0.001, 0.001);
          mesh.position.x = -63/2000;
          mesh.position.y = -80/2000;;
          mesh.position.z = -80/2000;;
          
          basisMesh.add(mesh);
        });
        bauteile.push(basisMesh);

        // 1: Bizeps
        var oberarmMesh = new THREE.Object3D();
        scene.add( oberarmMesh );
        bauteile.push(oberarmMesh);

        stlLoader.load('/model/Robot7M/2_01_Holm_SeitenBlech.stl', function (geometry) {
          // dunkelblaue, hochglänzende Lack-/Pulverbeschichtung
          var matO = new THREE.MeshStandardMaterial({
            color: 0x0b3d91,
            metalness: 0.15,
            roughness: 0.08,
            clearcoat: 1.0,
            clearcoatRoughness: 0.02
          });
          var mesh = new THREE.Mesh( geometry, matO );
          mesh.castShadow = true;
          mesh.rotation.x = -Math.PI/2;
          mesh.rotation.z = -Math.PI/2;
          mesh.rotation.y = Math.PI;
          mesh.scale.set(0.001, 0.001, 0.001);
          
          oberarmMesh.add(mesh);
        });

        // Bizeps MotorHalter
        stlLoader.load('/model/Robot7M/2_02_Bizeps_Motor_Holder.stl', function (geometry) {
          
          var mesh = new THREE.Mesh( geometry, matPLA );
          mesh.castShadow = true;
          
          mesh.rotation.z = Math.PI/2;
          mesh.rotation.x = Math.PI/2;
          mesh.scale.set(0.001, 0.001, 0.001);
          mesh.geometry.translate(275,-57/2,28.5);
          oberarmMesh.add(mesh);
        });
        



        // 2: Ellebogen
        var ellebogenMesh = new THREE.Object3D();
        scene.add( ellebogenMesh );
        bauteile.push(ellebogenMesh);

        stlLoader.load('/model/Robot7M/3_01_Ellebogen_Schlank.stl', function (geometry) {
          
          var mesh = new THREE.Mesh( geometry, matPLA );
          mesh.castShadow = true;
          mesh.rotation.z = -Math.PI/2;
          mesh.rotation.x = Math.PI; // lange achse
          mesh.scale.set(0.001, 0.001, 0.001);
          // Mesh zentrieren
          mesh.geometry.translate(0,0,25);
          ellebogenMesh.add(mesh);
        
        });

        // 3: Unterarm 
        var unterarmMesh = new THREE.Object3D();
        scene.add( unterarmMesh );
        bauteile.push(unterarmMesh);

        stlLoader.load('/model/Robot7M/4_01_Unterarm_Schlank_Rund.stl', function (geometry) {
          
          var mesh = new THREE.Mesh( geometry, matPLA );
          mesh.castShadow = true;
          mesh.rotation.x = -Math.PI/2; // lange achse
          mesh.rotation.z = -Math.PI/2;
          mesh.scale.set(0.001, 0.001, 0.001);
          mesh.geometry.translate(0,0,0);
          unterarmMesh.add(mesh);
        });
        

        // 4: Handgelenk
        var handMeshR = new THREE.Object3D();
        scene.add( handMeshR );
        bauteile.push(handMeshR);  
        
        stlLoader.load('/model/Robot7M/5_01_Hand_7M_Schlank.stl', function (geometry) {
  
          var mesh = new THREE.Mesh( geometry, matPLA );
          mesh.castShadow = true;
          mesh.rotation.x = 0; // -Math.PI/2; // lange achse
          mesh.rotation.z = 0; //-Math.PI/2;
          mesh.scale.set(0.001, 0.001, 0.001);
          mesh.geometry.translate(0,0,0);
          handMeshR.add(mesh);
        });
        
        // 5: Hand
        var handMeshF = new THREE.Object3D();
        scene.add( handMeshF );
        bauteile.push(handMeshF);        
        stlLoader.load('/model/Robot7M/5_03_Hand_7M_60for50_Fingerhalter.stl', function (geometry) {
  
          var mesh = new THREE.Mesh( geometry, matPLA );
          mesh.castShadow = true;
          mesh.rotation.x = 0; 
          mesh.rotation.z = 0; 
          mesh.scale.set(0.001, 0.001, 0.001);
          mesh.geometry.translate(0,0,0);
          handMeshF.add(mesh);
        });
        
        // 6: Finger1
        var handMeshFinger = new THREE.Object3D();
        scene.add( handMeshFinger );
        bauteile.push(handMeshFinger);        
        stlLoader.load('/model/Robot7M/5_05_Finger_Monolith.stl', function (geometry) {
  
          var mesh = new THREE.Mesh( geometry, matPLA );
          mesh.castShadow = true;
          mesh.rotation.x = 0; 
          mesh.rotation.z = 0; 
          mesh.scale.set(0.001, 0.001, 0.001);
          mesh.geometry.translate(-9,-23,0);
          handMeshFinger.add(mesh);
        });        
        
        // 6: Finger2
        var handMeshFinger2 = new THREE.Object3D();
        scene.add( handMeshFinger2 );
        bauteile.push(handMeshFinger2);        
        stlLoader.load('/model/Robot7M/5_05_Finger_Monolith.stl', function (geometry) {
  
          var mesh = new THREE.Mesh( geometry, matPLA );
          mesh.castShadow = true;
          mesh.rotation.x = 0; 
          mesh.rotation.z = 0; 
          mesh.scale.set(0.001, 0.001, 0.001);
          mesh.geometry.translate(-9,-23,0);
          handMeshFinger2.add(mesh);
        });
    }

    bauteile[0].position.x = -robot.xMotor/1000;
    bauteile[0].position.y = 0;
    bauteile[0].position.z = 0;

    // Bizeps
    bauteile[1].position.y = 28.5/1000;
    bauteile[1].position.x = -robot.xMotor/1000 + 0.04;
    bauteile[1].position.z = -25/1000;;
    bauteile[1].rotation.y = 0;
    bauteile[1].rotation.x = 0;
    bauteile[1].applyMatrix4(new THREE.Matrix4().makeRotationX(-robot.alpha))
  
    // Ellebogen 
    bauteile[2].position.x = 0;
    bauteile[2].position.z = (robot.l2*0.2)/2000; 
    bauteile[2].position.y = 0;
    bauteile[2].rotation.x = 0;
    bauteile[2].rotation.y = 0;
    bauteile[2].rotation.z = 0;
    bauteile[2].applyMatrix4(new THREE.Matrix4().makeRotationX(-robot.beta))
    bauteile[2].position.z += Math.cos(robot.alpha)*robot.l1/1000;
    bauteile[2].position.y += Math.sin(robot.alpha)*robot.l1/1000;
    bauteile[2].position.x -= robot.xMotor/1000 - 0.160;
   
    // Unterarm 
    bauteile[3].position.x = 0;
    bauteile[3].position.z = robot.l2/1000;
    bauteile[3].position.y = 0;
    bauteile[3].rotation.x = 0;
    bauteile[3].rotation.y = 0;
    bauteile[3].rotation.z = 0;
    bauteile[3].applyMatrix4(new THREE.Matrix4().makeRotationZ(-robot.a + Math.PI))
    bauteile[3].applyMatrix4(new THREE.Matrix4().makeRotationX(-robot.beta))
    bauteile[3].position.z += Math.cos(robot.alpha)*robot.l1/1000;
    bauteile[3].position.y += Math.sin(robot.alpha)*robot.l1/1000;
    bauteile[3].position.x -= robot.xMotor/1000 - 0.160;

    // Handgelenk
    
    bauteile[4].position.x = 0;
    bauteile[4].position.z = 0;
    bauteile[4].position.y = 0;
    bauteile[4].rotation.x = 0;
    bauteile[4].rotation.y = 0;
    bauteile[4].rotation.z = 0;

    bauteile[4].applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI)); // unklar, ob das koorekt ist
    
    bauteile[4].applyMatrix4(new THREE.Matrix4().makeRotationX(-robot.b));
    bauteile[4].applyMatrix4(new THREE.Matrix4().makeRotationZ(-robot.a+ Math.PI));
    bauteile[4].applyMatrix4(new THREE.Matrix4().makeRotationX(-robot.beta));
    
    bauteile[4].position.z += Math.cos(robot.alpha)*robot.l1/1000;
    bauteile[4].position.y += Math.sin(robot.alpha)*robot.l1/1000;
    bauteile[4].position.z += Math.cos(robot.beta)*robot.l2/1000;
    bauteile[4].position.y += Math.sin(robot.beta)*robot.l2/1000;
    bauteile[4].position.x -= robot.xMotor/1000 - 0.160;
    

    // Finger Halter
    bauteile[5].position.x = -0.057;
    bauteile[5].position.z = -0.026;
    bauteile[5].position.y = 0;
    bauteile[5].rotation.x = 0;
    bauteile[5].rotation.y = 0;
    bauteile[5].rotation.z = 0;

    bauteile[5].applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI)); // unklar, ob das koorekt ist
    bauteile[5].applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI));
    bauteile[5].applyMatrix4(new THREE.Matrix4().makeRotationZ(robot.c));
    bauteile[5].applyMatrix4(new THREE.Matrix4().makeRotationX(-robot.b));
    bauteile[5].applyMatrix4(new THREE.Matrix4().makeRotationZ(-robot.a+ Math.PI));
    bauteile[5].applyMatrix4(new THREE.Matrix4().makeRotationX(-robot.beta));
    bauteile[5].position.z += Math.cos(robot.alpha)*robot.l1/1000;
    bauteile[5].position.y += Math.sin(robot.alpha)*robot.l1/1000;
    bauteile[5].position.z += Math.cos(robot.beta)*robot.l2/1000;
    bauteile[5].position.y += Math.sin(robot.beta)*robot.l2/1000;
    bauteile[5].position.x -= robot.xMotor/1000 - 0.160;
    
    // Finger1
    bauteile[6].position.x = 0;
    bauteile[6].position.z = 0;
    bauteile[6].position.y = 0;
    bauteile[6].rotation.x = 0;
    bauteile[6].rotation.y = 0;
    bauteile[6].rotation.z = 0;
    bauteile[6].applyMatrix4(new THREE.Matrix4().makeRotationZ(Math.PI/2));
    bauteile[6].position.z = 0.026 + 0.009;
    bauteile[6].position.x += robot.e/1000;

    bauteile[6].applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI)); // unklar, ob das koorekt ist

    bauteile[6].applyMatrix4(new THREE.Matrix4().makeRotationZ(robot.c));
    bauteile[6].applyMatrix4(new THREE.Matrix4().makeRotationX(-robot.b));
    bauteile[6].applyMatrix4(new THREE.Matrix4().makeRotationZ(-robot.a+ Math.PI));
    bauteile[6].applyMatrix4(new THREE.Matrix4().makeRotationX(-robot.beta));
    bauteile[6].position.z += Math.cos(robot.alpha)*robot.l1/1000;
    bauteile[6].position.y += Math.sin(robot.alpha)*robot.l1/1000;
    bauteile[6].position.z += Math.cos(robot.beta)*robot.l2/1000;
    bauteile[6].position.y += Math.sin(robot.beta)*robot.l2/1000;
    bauteile[6].position.x -= robot.xMotor/1000 - 0.160;

    // Finger2
    bauteile[7].position.x = 0;
    bauteile[7].position.z = 0;
    bauteile[7].position.y = 0;
    bauteile[7].rotation.x = 0;
    bauteile[7].rotation.y = 0;
    bauteile[7].rotation.z = 0;
    bauteile[7].applyMatrix4(new THREE.Matrix4().makeRotationZ(-Math.PI/2));
    bauteile[7].position.z = 0.026 + 0.009;
    bauteile[7].position.x -= robot.e/1000;

    bauteile[7].applyMatrix4(new THREE.Matrix4().makeRotationX(Math.PI)); // unklar, ob das koorekt ist

    bauteile[7].applyMatrix4(new THREE.Matrix4().makeRotationZ(robot.c));
    bauteile[7].applyMatrix4(new THREE.Matrix4().makeRotationX(-robot.b));
    bauteile[7].applyMatrix4(new THREE.Matrix4().makeRotationZ(-robot.a+ Math.PI));
    bauteile[7].applyMatrix4(new THREE.Matrix4().makeRotationX(-robot.beta));
    bauteile[7].position.z += Math.cos(robot.alpha)*robot.l1/1000;
    bauteile[7].position.y += Math.sin(robot.alpha)*robot.l1/1000;
    bauteile[7].position.z += Math.cos(robot.beta)*robot.l2/1000;
    bauteile[7].position.y += Math.sin(robot.beta)*robot.l2/1000;
    bauteile[7].position.x -= robot.xMotor/1000 - 0.160;
   
    
    for (var i = 0; i < bauteile.length; i++) {
      bauteile[i].position.z += zHinten;
      bauteile[i].position.y += yOben;
    } 
    
}


if(!robot.showFunctions.includes(show3D)){
  robot.showFunctions.push(show3D);
}


robot.showRobot();

