/*
This file was generated by https://github.com/pmndrs/gltfjsx and then
customized manually. It uses drei's new useAnimations hook which extracts
all actions and sets up a THREE.AnimationMixer for it so that you don't have to.
All of the assets actions, action-names and clips are available in its output.
*/

import * as THREE from 'three'
import React, { useEffect, useState } from 'react'
import { useGLTF, useTexture, useAnimations } from '@react-three/drei'
import { a, useSpring } from '@react-spring/three'
import { GLTF } from 'three-stdlib'

// ** HELPER Imports
// import { Perf } from 'r3f-perf'
// import Spinner from '#/layout/ui/spinner'
// ** HELPFUL UTIL: COLORFUL CONSOLE MESSAGES (ccm)
import ccm from '#/lib/utils/console-colors'

// ** DEBUG: this module
const debug: boolean = false
const DEBUG: boolean = false

type GLTFResult = GLTF & {
  nodes: {
    stacy: THREE.SkinnedMesh
    mixamorigHips: THREE.Bone
  }
  materials: {}
}

type ActionName =
  | 'pockets'
  | 'rope'
  | 'swingdance'
  | 'jump'
  | 'react'
  | 'shrug'
  | 'wave'
  | 'golf'
  | 'idle'
type GLTFActions = Record<ActionName, THREE.AnimationAction>

// export this type?
type CharacterModelProps = any

export default function CharacterModel(props: CharacterModelProps) {
  // Fetch model and a separate texture
  const { nodes, animations } = useGLTF('/assets/examples/stacy.glb')
  const texture = useTexture('/assets/examples/stacy.jpg')

  // Extract animation actions
  const { ref, actions, names } = useAnimations(animations)
  if (debug) 
    console.debug(`%c Stacy -- animations.actions`, ccm.darkredAlert, actions, names, ref)

  // Hover and animation-index states
  const [hovered, setHovered] = useState(false)
  const [index, setIndex] = useState(4)

  // Animate the selection halo
  const { color, scale } = useSpring({
    scale: hovered ? [1.15, 1.15, 1] : [1, 1, 1],
    color: hovered ? '#ff6d6d' : '#569AFF',
  })

  // Change cursor on hover-state
  useEffect(() => void (document.body.style.cursor = hovered ? 'pointer' : 'auto'), [hovered])

  // Change animation when the index changes
  useEffect((): any => {
    try {
      // Reset and fade in animation after an index has been changed
      if (typeof actions[names[index]] !== undefined) {
        actions[names[index]].reset().fadeIn(0.5).play()
      }

      // In the clean-up phase, fade it out
      // (page route may have changed)
      // if (typeof actions[names[index]] !== undefined) {
      //   return () => actions[names[index]].fadeOut(0.5)
      // }
    } catch (err: any) {
      console.debug('Stacy err', err)
    }
    return null
  }, [index, actions, names])

  return (
    <group 
      // @ ts-expect-error
      ref={ref} 
      {...props} 
      dispose={null}
    >
      <group 
        rotation={[Math.PI / 2, 0, 0]} 
        scale={0.01}
      >
        {/* THREE.Bone(s) */}
        <primitive object={nodes.mixamorigHips} />
        {/* model */}
        <skinnedMesh
          castShadow
          receiveShadow
          onPointerOver={() => setHovered(true)}
          onPointerOut={() => setHovered(false)}
          onClick={() => setIndex((index + 1) % names.length)}
          // @ts-expect-error
          geometry={nodes.stacy.geometry}
          // @ts-expect-error
          skeleton={nodes.stacy.skeleton}
          rotation={[-Math.PI / 2, 0, 0]}
          scale={100}
        >
          {/* texture map */}
          <meshStandardMaterial 
            map={texture} 
            map-flipY={false} 
            // @ts-expect-error
            skinning
          />
        </skinnedMesh>
      </group>
      {/* background circle
      <a.mesh receiveShadow position={[0, 1, -1]} scale={scale}>
        <circleGeometry args={[1, 64]} />
        <a.meshStandardMaterial color={color} />
      </a.mesh> */}
    </group>
  )
}

useGLTF.preload('/assets/examples/stacy.glb')
