<template>
  <div ref="threeCircleNode" class="sk-effect-ball"></div>
</template>

<script>
import { defineComponent, onMounted, ref } from 'vue'
import {
  Scene,
  PerspectiveCamera,
  WebGLRenderer,
  Group,
  AmbientLight,
  DirectionalLight,
  Mesh,
  IcosahedronGeometry,
  MeshLambertMaterial,
  SphereGeometry,
  MeshPhongMaterial,
  Float32BufferAttribute,
  PointsMaterial,
  Points, BufferGeometry, Clock,
} from 'three'

export default defineComponent({
  name: 'SkEffectBall',
  props: {
    innerColor: {
      type: String,
      default: '#0C8CFF',
    },
    outerColor: {
      type: String,
      default: '#25FFFF',
    },
    innerSize: {
      type: Number,
      default: 60,
    },
    outerSize: {
      type: Number,
      default: 65,
    },
    ambientLightColor: {
      type: String,
      default: '#4895ac',
    },
    directionalLightColor: {
      type: String,
      default: '#8da54e',
    },
    innerDetail: {
      type: Number,
      default: 20,
    },
    outDetail: {
      type: Number,
      default: 50,
    },
    pointNum: {
      type: Number,
      default: 11000,
    },
  },
  setup (props) {
    const threeCircleNode = ref(null)
    onMounted(() => {
      initCircle(threeCircleNode.value)
    })
    const initCircle = el => {
      // let controls
      const scene = new Scene()
      const camera = new PerspectiveCamera(75, el.offsetWidth / el.offsetWidth, 0.1, 1000)
      const innerColor = props.innerColor
      const outerColor = props.outerColor
      const innerSize = props.innerSize
      const outerSize = props.outerSize
      const ambientLightColor = props.ambientLightColor
      const directionalLightColor = props.directionalLightColor
      const innerDetail = props.innerDetail
      const outDetail = props.outDetail
      const pointNum = props.pointNum * 3

      const renderer = new WebGLRenderer({ antialias: true, alpha: true })
      renderer.setClearColor('#000000', 0) // background

      renderer.setSize(el.offsetWidth, el.offsetHeight)
      el.appendChild(renderer.domElement)

      // controls = new THREE.TrackballControls( camera );
      // controls.noPan = true;
      // controls.minDistance = 120;
      // controls.maxDistance = 650;

      camera.position.z = -400
      // Mesh
      const group = new Group()
      scene.add(group)

      // Lights
      const light = new AmbientLight(ambientLightColor) // soft white light
      scene.add(light)

      const directionalLight = new DirectionalLight(directionalLightColor, 1)
      directionalLight.position.set(0, 128, 128)
      scene.add(directionalLight)

      // Sphere Wireframe Inner
      const sphereWireframeInner = new Mesh(
        new IcosahedronGeometry(innerSize, innerDetail),
        new MeshLambertMaterial({
          color: innerColor,
          ambient: innerColor,
          wireframe: true,
          transparent: true,
          // alphaMap: THREE.ImageUtils.loadTexture( 'javascripts/alphamap.jpg' ),
          shininess: 0,
        }),
      )
      scene.add(sphereWireframeInner)

      // Sphere Wireframe Outer
      const sphereWireframeOuter = new Mesh(
        new IcosahedronGeometry(outerSize, outDetail),
        new MeshLambertMaterial({
          color: outerColor,
          ambient: outerColor,
          wireframe: true,
          transparent: true,
          // alphaMap: THREE.ImageUtils.loadTexture( 'javascripts/alphamap.jpg' ),
          shininess: 0,
        }),
      )
      scene.add(sphereWireframeOuter)

      // Sphere Glass Inner
      const sphereGlassInner = new Mesh(
        new SphereGeometry(innerSize, 32, 32),
        new MeshPhongMaterial({
          color: innerColor,
          ambient: innerColor,
          transparent: true,
          shininess: 25,
          // alphaMap: THREE.ImageUtils.loadTexture( 'javascripts/twirlalphamap.jpg' ),
          opacity: 0.3,
        }),
      )
      scene.add(sphereGlassInner)

      // Sphere Glass Outer
      const sphereGlassOuter = new Mesh(
        new SphereGeometry(outerSize, 32, 32),
        new MeshPhongMaterial({
          color: outerColor,
          ambient: outerColor,
          transparent: true,
          shininess: 25,
          // alphaMap: THREE.ImageUtils.loadTexture( 'javascripts/twirlalphamap.jpg' ),
          opacity: 0.3,
        }),
      )
      scene.add(sphereGlassOuter)
      function initParticles (color) {
        const p = []
        let geometry = new BufferGeometry()
        for (let i = 0; i < pointNum; i++) {
          let x = -1 + Math.random() * 2
          let y = -1 + Math.random() * 2
          let z = -1 + Math.random() * 2
          const d = 1 / Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2))
          x *= d

          p.push(x * outerSize)
        }
        geometry.setAttribute( 'position', new Float32BufferAttribute( p, 3 ) )
        const particles = new Points(geometry, new PointsMaterial({
          size: 0.1,
          color,
          // map: THREE.ImageUtils.loadTexture( 'javascripts/particletextureshaded.png' ),
          transparent: true,
        }),
        )
        return particles
      }
      // Particles Outer
      const particlesOuter = initParticles(outerColor)
      scene.add(particlesOuter)

      // Particles Inner
      const particlesInner = initParticles(innerColor)
      scene.add(particlesInner)

      // Starfield
      let position = []
      let geometry = new BufferGeometry()
      for (let i = 0; i < 5000; i++) {
        let x = Math.random() * 2000 - 1000
        let y = Math.random() * 2000 - 1000
        let z = Math.random() * 2000 - 1000
        position.push(x, y, z)
      }
      geometry.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) )
      const starField = new Points(geometry, new PointsMaterial({
        size: 2,
        color: 0xffff99,
      }),
      )
      scene.add(starField)

      camera.position.z = -110
      // camera.position.x = mouseX * 0.05;
      // camera.position.y = -mouseY * 0.05;
      // camera.lookAt(scene.position);

      const time = new Clock()

      const render = function () {
        // camera.position.x = mouseX * 0.05;
        // camera.position.y = -mouseY * 0.05;
        camera.lookAt(scene.position)

        sphereWireframeInner.rotation.x += 0.002
        sphereWireframeInner.rotation.z += 0.002

        sphereWireframeOuter.rotation.x += 0.001
        sphereWireframeOuter.rotation.z += 0.001

        sphereGlassInner.rotation.y += 0.005
        sphereGlassInner.rotation.z += 0.005

        sphereGlassOuter.rotation.y += 0.01
        sphereGlassOuter.rotation.z += 0.01

        particlesOuter.rotation.y += 0.0005
        particlesInner.rotation.y -= 0.002

        // starField.rotation.y -= 0.002

        // const innerShift = Math.abs(Math.cos(((time.getElapsedTime() + 2.5) / 20)))
        // const outerShift = Math.abs(Math.cos(((time.getElapsedTime() + 5) / 10)))

        // starField.material.color.setHSL(Math.abs(Math.cos((time.getElapsedTime() / 10))), 1, 0.5)

        // sphereWireframeOuter.material.color.setHSL(0, 1, outerShift)
        // sphereGlassOuter.material.color.setHSL(0, 1, outerShift)
        // particlesOuter.material.color.setHSL(0, 1, outerShift)

        // sphereWireframeInner.material.color.setHSL(0.08, 1, innerShift)
        // particlesInner.material.color.setHSL(0.08, 1, innerShift)
        // sphereGlassInner.material.color.setHSL(0.08, 1, innerShift)

        sphereWireframeInner.material.opacity = Math.abs(Math.cos((time.getElapsedTime() + 0.5) / 0.9) * 0.5)
        sphereWireframeOuter.material.opacity = Math.abs(Math.cos(time.getElapsedTime() / 0.9) * 0.5)

        directionalLight.position.x = Math.cos(time.getElapsedTime() / 0.5) * 128
        directionalLight.position.y = Math.cos(time.getElapsedTime() / 0.5) * 128
        directionalLight.position.z = Math.sin(time.getElapsedTime() / 0.5) * 128

        // controls.update();

        renderer.render(scene, camera)
        requestAnimationFrame(render)
      }

      render()

      // Mouse and resize events
      // document.addEventListener('mousemove', onDocumentMouseMove, false)
      window.addEventListener('resize', onWindowResize, false)

      function onWindowResize () {
        camera.aspect = el.offsetWidth / el.offsetHeight
        camera.updateProjectionMatrix()
        renderer.setSize(el.offsetWidth, el.offsetHeight)
      }

      // function onDocumentMouseMove (event) {
      //   mouseX = event.clientX - window.innerWidth / 2
      //   mouseY = event.clientY - window.innerHeight / 2
      // }
    }

    return {
      threeCircleNode,
    }
  },
})
</script>

<style>

</style>
