import * as THREE from 'three'
import { Points, useGLTF, OrbitControls, ScrollControls, Scroll } from '@react-three/drei'
import { GLTF } from 'three-stdlib'
import { useFrame, Canvas } from '@react-three/fiber'
import { useMemo, useRef } from 'react'
import { EffectComposer, SelectiveBloom } from '@react-three/postprocessing'

type GLTFResult = GLTF & {
  nodes: {
    Object_2: THREE.Mesh
  }
  materials: {
    ['Scene_-_Root']: THREE.PointsMaterial
  }
}

export function Galaxy(props: JSX.IntrinsicElements['group']) {
  const ref = useRef<THREE.Group>(null!)
  const galaxyCenterLightRef = useRef<THREE.PointLight>(null!)
  const { nodes } = useGLTF('./models/galaxy.glb') as GLTFResult
  const [positions, colors] = useMemo(() => {
    nodes.Object_2.geometry.center()
    const positions = new Float32Array(
      nodes.Object_2.geometry.attributes.position.array.buffer
    )
    const colors = new Float32Array(positions.length)

    const getDistanceToCenter = (x: number, y: number, z: number) =>
      Math.sqrt(x * x + y * y + z * z)

    // make colors closer to 0,0,0 be more reddish and colors further away be more blueish
    const color = new THREE.Color()
    for (let i = 0; i < positions.length; i += 3) {
      const x = positions[i]
      const y = positions[i + 1]
      const z = positions[i + 2]
      const distanceToCenter = getDistanceToCenter(x, y, z)
      const normalizedDistanceToCenter = distanceToCenter / 100

      // make colors closer to 0,0,0 be more reddish and colors further away be more blueish (do not use hsl)
      color.setHSL(
        (0.15 * (0.21 + Math.cos(distanceToCenter * 0.02))) / 2,
        0.75,
        0.6
      )
      color.setRGB(
        Math.cos(normalizedDistanceToCenter),
        THREE.MathUtils.randFloat(0, 0.8),
        Math.sin(normalizedDistanceToCenter)
      )
      color.toArray(colors, i)
    }

    return [positions, colors]
  }, [nodes])


  // slowly rotate the galaxy
  useFrame(({ clock }) => {
    ref.current.rotation.z = clock.getElapsedTime() / 2
    // zoom in and out
    ref.current.scale.setScalar(Math.sin(clock.getElapsedTime() / 2) + 1.2)
  })

  //  make particles glow

  return (
    <group {...props} dispose={null} ref={ref}>
      <pointLight
        position={[0, 0, 0]}
        ref={galaxyCenterLightRef}
        intensity={0.5}
      />
      <Points scale={0.05} positions={positions} colors={colors}>
        <pointsMaterial
          //map={starTexture}
          transparent
          depthWrite={false}
          vertexColors
          opacity={0.4}
          depthTest
          size={0.01}
        />
      </Points>
      <EffectComposer autoClear={false}>
        <SelectiveBloom
          intensity={5}
          luminanceThreshold={0.01}
          luminanceSmoothing={0.225}
          lights={[galaxyCenterLightRef]}
        />
      </EffectComposer>
		    <ambientLight intensity={1} />
    </group>
  )
}

useGLTF.preload('./models/galaxy.glb')

export const ThreeFiberGalaxy = () => {
	return (
		<Canvas camera={{ position: [0, 12, 0], fov: 75 }}>
		<OrbitControls enableZoom={true} enablePan={true} enableRotate={true} zoomSpeed={2} panSpeed={2} rotateSpeed={0.5} />
		<pointLight position={[10, 10, 10]} />
		<ScrollControls pages={5}>
		<Scroll>
		<Galaxy position={[0, 9, 0]} />
		</Scroll>
		</ScrollControls>
		</Canvas>
	)
}
