import { useEffect, useRef } from 'react'
import { useThree, useFrame } from '@react-three/fiber'
import { ViewportGizmo } from 'three-viewport-gizmo'
import { PerspectiveCamera, WebGLRenderer, Scene } from 'three'

type Controls = {
    enabled: boolean
    setPosition: (...args: number[]) => void
    getTarget: (target: any) => void
    addEventListener: (type: string, listener: (...args: any[]) => void) => void
}

export const Gizmo = () => {
    const { camera, gl, scene, controls } = useThree<{
        camera: PerspectiveCamera
        gl: WebGLRenderer
        scene: Scene
        controls?: Controls
    }>()

    const gizmoRef = useRef<ViewportGizmo | null>(null)

    useEffect(() => {
        const gizmo = new ViewportGizmo(camera, gl, {})
        gizmoRef.current = gizmo

        const resize = () => {
            const width = window.innerWidth
            const height = window.innerHeight - 1
            camera.aspect = width / height
            camera.updateProjectionMatrix()
            gl.setSize(width, height)
            gizmo.update()
        }

        if (controls) {
            gizmo.addEventListener('start', () => { controls.enabled = false })
            gizmo.addEventListener('end', () => { controls.enabled = true })
            gizmo.addEventListener('change', () => {
                controls.setPosition(...camera.position.toArray())
            })
            controls.addEventListener('update', () => {
                controls.getTarget(gizmo.target)
                gizmo.update()
            })
        }

        window.addEventListener('resize', resize)

        return () => {
            window.removeEventListener('resize', resize)
        }
    }, [camera, gl, scene, controls])

    useFrame(() => {
        if (gizmoRef.current) {
            gl.render(scene, camera)
            gizmoRef.current.render()
        }
    })

    return null
}