<!--
  -   This file is a part of the SteamWar software.
  -
  -   Copyright (C) 2024 SteamWar.de-Serverteam
  -
  -   This program is free software: you can redistribute it and/or modify
  -   it under the terms of the GNU Affero General Public License as published by
  -   the Free Software Foundation, either version 3 of the License, or
  -   (at your option) any later version.
  -
  -   This program is distributed in the hope that it will be useful,
  -   but WITHOUT ANY WARRANTY; without even the implied warranty of
  -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  -   GNU Affero General Public License for more details.
  -
  -   You should have received a copy of the GNU Affero General Public License
  -   along with this program.  If not, see <https://www.gnu.org/licenses/>.
  -->

<script lang="ts">
    import * as THREE from "three";
    import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
    import { OrbitControls } from "three/addons/controls/OrbitControls.js";
    import {onDestroy, onMount} from "svelte";
    import type { CollectionEntry } from "astro:content";

  interface Props {
    pub: CollectionEntry<"publics">;
    fov?: number;
    near?: number;
    far?: number;
    distance?: number;
    children?: import('svelte').Snippet;
  }

  let {
    pub,
    fov = 60,
    near = 1,
    far = 1000,
    distance = 100,
    children
  }: Props = $props();

    let loaded = $state(false);

    let div: HTMLDivElement = $state();
    let scene: THREE.Scene;
    let camera: THREE.PerspectiveCamera;
    let renderer: THREE.WebGLRenderer;
    let controls: OrbitControls;
    let light: THREE.AmbientLight;
    let observer: ResizeObserver;

    onMount(() => {
        if (!pub.data["3d"]) {
            return;
        }

        scene = new THREE.Scene();
        scene.background = new THREE.Color(0x171717);
        camera = new THREE.PerspectiveCamera(fov, 1, near, far);

        renderer = new THREE.WebGLRenderer();
        renderer.setSize(500, 500);
        controls = new OrbitControls(camera, renderer.domElement);
        controls.autoRotate = true;
        controls.autoRotateSpeed = 1;

        const loader = new GLTFLoader();

        loader.load(`/3d/${pub.id}.glb`, (gltf) => {
            scene.add(gltf.scene);

            let cube_bbox = new THREE.Box3();
            cube_bbox.setFromObject(gltf.scene);
            let center = new THREE.Vector3();
            cube_bbox.getCenter(center);

            controls.target = center;
            camera.position.set(0, center.y, distance);

            controls.update();
        }, undefined, (e) => {
            console.error(e);
        });

        div.append(renderer.domElement);

        light = new THREE.AmbientLight(0xffffff, 1);
        scene.add(light);

        observer = new ResizeObserver(handleResize);
        observer.observe(div);


        loaded = true;

        function animate() {
            if (loaded) {
                requestAnimationFrame(animate);
            }

            renderer.render( scene, camera );
            controls.update();
        }

        animate();
    });

    onDestroy(() => {
        if (loaded) {
            loaded = false;

            observer.unobserve(div);
            observer.disconnect();

            renderer.dispose();
            scene.clear();
            light.dispose();
        }
    })

    function handleResize() {
        let width = div.clientWidth;
        let height = div.clientHeight;

        camera.aspect = width / height;
        camera.updateProjectionMatrix();

        renderer.setSize(width, height, true);
    }
</script>

<div style="height: 500px" class="w-full relative">
    <div bind:this={div} class="w-full h-full">

    </div>

    <div class="w-full h-full flex justify-center absolute top-0 left-0 right-0 bottom-0" class:hidden={loaded}>
        {@render children?.()}
    </div>
</div>
