<template>
    <figure id="cubetti" ref="cubetti" />
</template>

<style lang="pcss" scoped>
@reference '../assets/css/main.css';

@media screen and (width >= theme(breakpoint.sm)) {
    #cubetti {
        position: absolute;
        width: 200px !important;
        height: 200px !important;
        top: -55px !important;
        left: 0px !important;
    }
}

#cubetti {
    position: absolute;
    width: 120px;
    height: 120px;
    overflow: visible;
    top: -24px;
    left: -22px;
}
</style>

<script lang="ts" setup>
    import {
        AmbientLight,
        DirectionalLight,
        BoxGeometry,
        Mesh,
        MeshStandardMaterial,
        PerspectiveCamera,
        Scene,
        Vector3,
        WebGLRenderer,
        MathUtils,
        LinearToneMapping,
    } from 'three';
    import { animate, stagger } from 'animejs';

    const scene = new Scene()
    const camera = new PerspectiveCamera(80, 1, 0.1, 1000)
    const renderer = new WebGLRenderer({ antialias: true, alpha: true })
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.toneMapping = LinearToneMapping
    renderer.toneMappingExposure = 2.5
    const directionalLight = new DirectionalLight(0xffffff)
    const ambientLight = new AmbientLight(0xffffff)
    const geometry = new BoxGeometry(1, 1, 1)
    const blueMaterial = new MeshStandardMaterial({ color: 'dodgerblue' })
    const greenMaterial = new MeshStandardMaterial({ color: 'greenyellow' })
    const orangeMaterial = new MeshStandardMaterial({ color: 'orange' })
    const blueCube = new Mesh(geometry, blueMaterial)
    blueCube.position.set(-1, 0, 1)
    const greenCube = new Mesh(geometry, greenMaterial)
    greenCube.position.set(1, 0, 1)
    const orangeCube = new Mesh(geometry, orangeMaterial)
    orangeCube.position.set(0, 0, -1)
    const cubeGroup = new Scene()
    cubeGroup.add(blueCube, greenCube, orangeCube)

    const cubettiAnims = [
        { // group spin
            targets: [cubeGroup.rotation],
            params: {
                keyframes: [
                    { y: 2 * Math.PI, duration: 1000 },
                ],
                easing: 'easeOutCubic',
                duration: 1000,
                onComplete: playRandomAnimation,
            }
        },
        { // floating cubes
            targets: [orangeCube.position, blueCube.position, greenCube.position],
            params: {
                keyframes: [
                    { y: -0.5, duration: 500/3 },
                    { y:  0.5, duration: 707/3 },
                    { y:  0.0, duration: 500/3 },
                ],
                easing: 'easeInOutSine',
                delay: stagger(500/3),
                onComplete: playRandomAnimation,
            }
        },
        { // rotating cubes
            targets: [orangeCube.rotation, blueCube.rotation, greenCube.rotation],
            params: {
                x: MathUtils.randInt(0, 1) * 2 * Math.PI, y: MathUtils.randInt(0, 1) * 2 * Math.PI, z: MathUtils.randInt(0, 1) * 2 * Math.PI, duration: 1000,
                easing: 'easeOutSine',
                delay: stagger(500/3),
                onComplete: playRandomAnimation
            }
        }
    ]
    
    const cubetti = ref()

    function playRandomAnimation() {
        setTimeout(() => {
            const n = MathUtils.randInt(0, cubettiAnims.length-1)
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            const a = cubettiAnims[n] as any;
            animate(a.targets, a.params)
        }, MathUtils.randInt(1000, 8000))
    }

    const runAnimation = () => {
        renderer.render(scene, camera)
        requestAnimationFrame(runAnimation)
    }

    const resizeCanvas = () => {
        if (window.innerWidth < 640) {
            renderer.setSize(120, 120);
        } else {
            renderer.setSize(200, 200);
        }
    }

    onMounted(() => {
        scene.add(camera)
        scene.add(ambientLight, directionalLight)
        scene.add(cubeGroup)
        // renderer.setSize(200, 200)
        resizeCanvas();
        camera.position.copy((new Vector3(-2, 1.5, 2)).multiplyScalar(1.2))
        camera.lookAt(0, 0, 0)
        scene.background = null
        cubetti.value.appendChild(renderer.domElement)

        window.addEventListener('resize', resizeCanvas);

        playRandomAnimation()

        runAnimation()
    })

    onUnmounted(() => {
        window.removeEventListener('resize', resizeCanvas);
    })
</script>