<script setup lang="js">
import { onMounted, onUnmounted, ref } from "vue";
import * as THREE from "three";
import gsap from "gsap";
import ScrollTrigger from "gsap/ScrollTrigger";

import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

import surf_video from "/vids/Aus_dem_wasser.mp4";
import ski_video from "/vids/ski.mp4";

const canvasRef = ref(null);
let renderer, scene, camera, model, controls, gsapCtx;
let screen1, screen3, screen4;

const video_surf = document.createElement("video");
const video_ski = document.createElement("video");

video_surf.src = surf_video;
video_surf.loop = true;
video_surf.muted = true;

video_ski.src = ski_video;
video_ski.loop = true;
video_ski.muted = true;

function initThree(canvas) {
  renderer = new THREE.WebGLRenderer({
    canvas,
    antialias: true,
    alpha: true,
  });

  renderer.setPixelRatio(1); //TODO

  renderer.outputColorSpace = THREE.SRGBColorSpace;
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(45, 2, 0.1, 100);

  const light = new THREE.DirectionalLight(0xffe0b0, 0.9);
  light.position.set(-1, 4, 5);
  scene.add(light);

  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.enabled = false;

  // controls.minDistance = 5;
  // controls.maxDistance = 5;
  controls.maxPolarAngle = Math.PI / 2;
  controls.minAzimuthAngle = -Math.PI / 2;
  controls.maxAzimuthAngle = Math.PI / 2;

  scene.add(new THREE.AmbientLight(0xffffff, 0.5));

  loadModel();

  gsap.ticker.add(render);
}

function loadModel() {
  if (model) {
    scene.remove(model);
  }
  let modelUrl = "/models/room-draco.glb";
  let dracoPath = "/draco/";

  const dracoLoader = new DRACOLoader();
  dracoLoader.setDecoderPath(dracoPath);

  const loader = new GLTFLoader();
  loader.setDRACOLoader(dracoLoader);

  loader.load(
    modelUrl,
    (gltf) => {
      model = gltf.scene;

      const box = new THREE.Box3().setFromObject(model);
      const center = box.getCenter(new THREE.Vector3());
      const size = box.getSize(new THREE.Vector3());
      const texture_surf_video = new THREE.VideoTexture(video_surf);
      const texure_ski = new THREE.VideoTexture(video_ski);
      screen1 = model.getObjectByName("fernseher1Bild");
      screen4 = model.getObjectByName("fernseher4Bild");
      screen3 = model.getObjectByName("fernseher3Bild");

      texture_surf_video.flipY = false;
      texure_ski.flipY = false;
      texure_ski.offset.set(-0.3, -0.2);

      screen1.material = new THREE.MeshBasicMaterial({
        map: texture_surf_video,
      });
      screen4.material = new THREE.MeshBasicMaterial({
        map: texure_ski,
      });
      screen3.material = new THREE.MeshBasicMaterial({
        map: texure_ski,
      });
      const maxSize = Math.max(size.x, size.y, size.z);
      const distance = maxSize * 2;

      camera.position.set(center.x, center.y, center.z + distance);
      controls.target.copy(center);
      controls.update();

      console.log(scene);
      model.position.set(0, 0, 0);
      scene.add(model);
      gsapCtx = scrollCamreaGsap(center);

      document.title = "Model geladen";
    },
    (progress) => {
      const percent = ((progress.loaded / progress.total) * 100).toFixed(1);
      console.log(`Loading: ${percent}%`);
      document.title = `${percent}%`;
    },
    (error) => {
      console.error("Fehler beim Laden des Modells:", error);
      document.title = "Fehler beim Laden!";
    },
  );
}

function render() {
  if (!renderer) return;

  controls.update();

  renderer.render(scene, camera);
}
function onResize() {
  if (!renderer || !canvasRef.value) return;
  const r = canvasRef.value.getBoundingClientRect();
  const dpr = Math.min(window.devicePixelRatio || 1, 2);

  const width = canvasRef.value.clientWidth;
  const height = canvasRef.value.clientHeight;

  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
  renderer.setSize(width, height, false);

  camera.aspect = (r.width || 1) / (r.height || 1);
  camera.updateProjectionMatrix();
}

function scrollCamreaGsap(center) {
  gsap.registerPlugin(ScrollTrigger);

  const ctx = gsap.context(() => {
    gsap.to(camera.position, {
      z: center.z + 5,
      ease: "none",
      scrollTrigger: {
        trigger: canvasRef.value,
        start: "top top",
        end: "+=2000",
        scrub: 1,
        pin: true,
        anticipatePin: 1,
        onUpdate: (self) => {
          if (self.progress >= 0.8) {
            controls.enabled = true;

            controls.enableRotate = true;
            controls.enableZoom = false;
            controls.enablePan = false;

            screen1.visible = true;
            screen3.visible = true;
            screen4.visible = true;
            setVideoActive(true);
          } else {
            controls.enabled = false;
            screen1.visible = false;
            screen3.visible = false;
            screen4.visible = false;
            setVideoActive(false);
          }
        },
      },
    });
  }, canvasRef.value);

  return ctx;
}

function setVideoActive(active) {
  if (active) {
    video_surf.play();
    video_ski.play();
  } else {
    video_surf.pause();
    video_ski.pause();
  }
}

const resizeObserver = new ResizeObserver(onResize);

onMounted(() => {
  initThree(canvasRef.value);
  onResize();

  resizeObserver.observe(canvasRef.value);
  window.addEventListener("resize", onResize);
});

onUnmounted(() => {
  gsap.ticker.remove(render);
  window.removeEventListener("resize", onResize);
  resizeObserver.disconnect();
  renderer?.dispose();
  gsapCtx?.revert();
  ScrollTrigger.getAll().forEach((t) => t.kill());
});
</script>
<template>
  <div class="wrapper">
    <!-- <div class="spacer"></div> -->

    <canvas class="canvas" ref="canvasRef"></canvas>
  </div>
  <div class="scroll-buffer"></div>
  <div class="spacer"></div>
</template>

<style>
.spacer {
  width: 100%;
  height: 200vh;
  display: grid;
  place-items: center;
  font-weight: 600;
}

.wrapper {
  width: 100%;
  height: 100vh;
}

.canvas {
  width: 100%;
  height: 100%;
}
.scroll-buffer {
  height: 100vh;
}
</style>
