import { Environment, OrbitControls } from '@react-three/drei'
import React, { useEffect, useRef, useState } from 'react'
import { useFrame, useThree } from '@react-three/fiber'
import * as THREE from "three"
import { Space } from './Space'
import useStore from '@/lib/store'
import gsap from 'gsap'
import { Bloom, EffectComposer } from '@react-three/postprocessing'
import Chunks from './Chunk'

export default function MyScene() {

  const {camera, scene} = useThree()
  const focus = useStore((s)=>s.focus)
  const [raycaster] = useState(new THREE.Raycaster());
  const [pointer] = useState(new THREE.Vector2())

  useEffect(()=>{
    camera.position.set(0, 50, 200)
    const handleMouseMove = (event: MouseEvent) => {
      pointer.x = ( event.clientX / window.innerWidth ) * 2 - 1;
      pointer.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
    };
    
    const handleMouseClick = (event: MouseEvent) => {
      const px = ( event.clientX / window.innerWidth ) * 2 - 1;
      const py = - ( event.clientY / window.innerHeight ) * 2 + 1;
      raycaster.setFromCamera(new THREE.Vector2(px, py), camera);
      const network = scene.getObjectByName('network')
      if(network){
        const intersects = raycaster.intersectObjects(network.children);
        if(intersects.length>0 && intersects[ 0 ].object.type === "Mesh"){
          const data = intersects[0].object.userData
          data && useStore.setState({choose:data})
        }
      }
    };
    // Add the event listener to the window object
    window.addEventListener("mousemove", handleMouseMove);
    window.addEventListener("click", handleMouseClick);
    // Cleanup event listener on component unmount
    return () => {
      window.removeEventListener("mousemove", handleMouseMove);
      window.removeEventListener("click", handleMouseMove);
    };    
  },[])

  useFrame(({clock})=>{    
    if(controlsRef.current){
      const target = controlsRef.current.target as THREE.Vector3;
      const element = scene.getObjectByName('space')
      element && element.position.set(target.x, target.y, target.z)
      if(Number(target.x.toFixed(0)) !== focus.x || Number(target.y.toFixed(0)) !== focus.y || Number(target.z.toFixed(0)) !== focus.z){
        useStore.setState({focus:new THREE.Vector3(Number(target.x.toFixed(0)), Number(target.y.toFixed(0)), Number(target.z.toFixed(0)))})
      }
      const network = scene.getObjectByName('network')
      if(network){
        raycaster.setFromCamera( pointer, camera );
        
        const intersects = raycaster.intersectObjects( network.children );
        const wrapper = document.getElementById("canvas-wrapper");
        if ( intersects.length > 0 && intersects[ 0 ].object.type === "Mesh" && intersects[ 0 ].object.userData && wrapper) {
          wrapper.style.cursor = "pointer"
        } else {
          if(wrapper) wrapper.style.cursor = "default"
        }

        network.traverse((child:any)=>{
          const id = child.id
          const time = clock.getElapsedTime();
          if(child.type === "Line"){
            const flag = (choose && child.userData && choose?.constellation === child.userData.constellation)
            const v = flag?(Math.sin(time*2+id) * 0.25 + 0.7):(Math.sin(time * 2+id) * 0.1 + 0.1); // Range: 0 to 1
            child.material.color.setRGB(v, v, v)
          }else if(child.type === "Mesh"){
            const brightness = (choose && choose?.transaction_signature === child.name)
            ?(Math.sin(time*2+id) * 0.25 + 0.5):(Math.sin(time * 2 + id) * 0.1 - 0.1); // Range: 0 to 1          
            child.material.emissive.setScalar(brightness);
          }
        })
      }
    }
  })

  const choose = useStore((s) => s.choose)
  const controlsRef :any = useRef(null);

  useEffect(()=>{
    if(choose){
      if(controlsRef.current){
        controlsRef.current.maxDistance = 50
        let flag = false
        scene.traverse((child) => {
          if (child?.name === choose.transaction_signature) {
            const pos = new THREE.Vector3()
            child.getWorldPosition(pos)
            gsap.to(controlsRef.current?.target, {x:pos.x, y:pos.y, z:pos.z, duration:2.0, ease: "power4.out"})
            flag = true
          }
        });
        if(!flag){

        }
      }
    }else{
      controlsRef.current.maxDistance = 50
      gsap.to(controlsRef.current?.target, {x:0, y:0, z:0, duration:2.0})
    }
  },[choose])

  return (
    <React.Fragment>
      <ambientLight color={"#aaaaaa"} intensity={5}/>
      <Chunks/>
      <Environment files={['assets/textures/starry.hdr']} background blur={0.35}/>      
      <Space name='space'/>
      <OrbitControls ref={controlsRef}        
        enablePan = {true}
        panSpeed = {0.5}
        minDistance={1}
        maxDistance={300}
        autoRotate={false} autoRotateSpeed={-0.5}/>
      {/* <axesHelper args={[10]}/> */}
      <EffectComposer>
        <Bloom
          luminanceThreshold={0.05}
          luminanceSmoothing={0.2}
          intensity={5}
          radius={0.01}
        />
      </EffectComposer>
    </React.Fragment>
  )
}