<template>
  <!-- scène 3D -->
  <div ref="scene" class="scene z-10">
    <div ref="box" class="box">
      <div class="face front relative" ref="frontFace">
        <img class="cover absolute" :src="`/${compilation.id}/cover.jpg`" alt="">
      </div>
      <div class="face back" ref="backFace" />
      <div class="face right" ref="rightFace" />
      <div class="face left" ref="leftFace" />
      <div class="face top" ref="topFace">
        <img class="logo h-full p-1" src="/logo.svg" alt="">
        <img class="absolute left-0 w-16 pr-4" :src="`/${compilation.id}/title.svg`" alt="">
      </div>
      <div class="face bottom" ref="bottomFace" />
    </div>
  </div>

  <div class="devtool  absolute right-4 text-white bg-black rounded-2xl px-4 py-2">
    <button @click="poser">poser</button>
    <button @click="face">face</button>
    <button @click="dos">dos</button>
    <div>
      <label class="block">
        X: {{ angleX }}
        <input v-model.number="angleX" type="range" step="1" min="-180" max="180" @input="applyTransform">
      </label>
      <label class="block">
        Y: {{ angleY }}
        <input v-model.number="angleY" type="range" step="1" min="-180" max="180" @input="applyTransform">
      </label>
      <label class="block">
        Z: {{ angleZ }}
        <input v-model.number="angleZ" type="range" step="1" min="-180" max="180" @input="applyTransform">
      </label>
    </div>
  </div>
</template>

<script setup lang="ts">
import compilations from '~~/server/api/compilations';
import type { Compilation } from '~~/types/types';

const props = defineProps<{ compilation: Compilation }>()

// States
const position = ref('')
const angleX = ref(76)
const angleY = ref(0)
const angleZ = ref(150)

const frontFace = ref()
const backFace = ref()
const rightFace = ref()
const leftFace = ref()
const topFace = ref()
const bottomFace = ref()

function poser() {
  rotateBox(76, 0, 150)
}

function face() {
  rotateBox(-20, 20, 0)
}

function dos() {
  rotateBox(-20, 200, 0)
}

const box = ref()
const scene = ref()

/*
  ÉTATS POUR LE DRAG + INERTIE
*/
let dragging = false
let lastPointer = { x: 0, y: 0, time: 0 } // position précédente du pointeur
let velocity = { x: 0, y: 0 }              // vitesse calculée pour inertie
let raf = null                              // id du requestAnimationFrame

/*
  PARAMÈTRES DE RÉGLAGE
*/
const sensitivity = 0.3    // combien de degrés par pixel de mouvement
const friction = 0.95      // inertie : 1 = sans perte, plus bas = ralentit vite
const minVelocity = 0.02   // seuil sous lequel on arrête l’inertie
const enableInertia = true // true = inertie activée, false = rotation immédiate sans suite

/*
  Applique la transformation CSS à la box
*/
function applyTransform() {
  angleX.value = Math.round(angleX.value)
  angleY.value = Math.round(angleY.value)
  angleZ.value = Math.round(angleZ.value)

  box.value.style.transform = `rotateX(${angleX.value}deg) rotateY(${angleY.value}deg) rotateZ(${angleZ.value}deg)`
}


/*
  Fonction utilitaire : place la box directement à une rotation donnée
  (utilisée par le bouton reset ou autre logique externe)
*/
function rotateBox(x, y, z) {
  angleX.value = x
  angleY.value = y
  angleZ.value = z
  applyTransform()

  box.value.style.setProperty('transition', 'transform 800ms ease-in-out')
  setTimeout(() => {
    box.value.style.setProperty('transition', 'transform 120ms linear')
    console.log('dopne timeout')
  }, 120)

}

/*
  Boucle d’inertie après un drag
  - reprend la vitesse calculée à la release
  - diminue petit à petit avec friction
  - stoppe quand vitesse < minVelocity
*/
function tickInertia() {
  if (!enableInertia) return

  // appliquer la friction
  velocity.x *= friction
  velocity.y *= friction

  // appliquer au box
  angleX.value += velocity.y
  angleY.value += velocity.x

  // clamp angleX pour éviter de retourner la box trop loin
  angleX.value = Math.max(-80, Math.min(80, angleX.value))

  applyTransform()

  // continuer tant qu’il reste du mouvement
  if (Math.abs(velocity.x) > minVelocity || Math.abs(velocity.y) > minVelocity) {
    raf = requestAnimationFrame(tickInertia)
  } else {
    raf = null
  }
}

/*
  Mise en place des listeners une fois le composant monté
*/
onMounted(() => {
  // setup CSS vars pour la scène
  updateCssVar('--height', '200px', scene.value)
  updateCssVar('--width', '300px', scene.value)
  updateCssVar('--depth', '60px', scene.value)

  frontFace.value.style.setProperty('background', `${props.compilation.colorTo}`)
  backFace.value.style.setProperty('background', `linear-gradient(to top, ${props.compilation.colorFrom}, ${props.compilation.colorTo})`)
  rightFace.value.style.setProperty('background', `linear-gradient(to top, ${props.compilation.colorFrom}, ${props.compilation.colorTo})`)
  leftFace.value.style.setProperty('background', `linear-gradient(to top, ${props.compilation.colorFrom}, ${props.compilation.colorTo})`)
  topFace.value.style.setProperty('background', `linear-gradient(to top, ${props.compilation.colorTo}, ${props.compilation.colorTo})`)
  bottomFace.value.style.setProperty('background', `${props.compilation.colorFrom}`)


  applyTransform()

  // pointerdown = début du drag
  const down = (ev) => {
    ev.preventDefault()
    dragging = true
    scene.value.setPointerCapture(ev.pointerId)
    lastPointer = { x: ev.clientX, y: ev.clientY, time: performance.now() }
    velocity = { x: 0, y: 0 }
    if (raf) { cancelAnimationFrame(raf); raf = null }
  }

  // pointermove = on bouge la souris ou le doigt
  const move = (ev) => {
    if (!dragging) return
    ev.preventDefault()
    const now = performance.now()
    const dx = ev.clientX - lastPointer.x
    const dy = ev.clientY - lastPointer.y

    // mise à jour des angles
    angleY.value += dx * sensitivity
    angleX.value -= dy * sensitivity
    angleX.value = Math.max(-80, Math.min(80, angleX.value))

    // calcul vitesse pour inertie
    const dt = Math.max(1, now - lastPointer.time)
    velocity.x = (dx / dt) * 16 * sensitivity
    velocity.y = (-dy / dt) * 16 * sensitivity

    lastPointer = { x: ev.clientX, y: ev.clientY, time: now }

    applyTransform()
  }

  // pointerup = fin du drag
  const end = (ev) => {
    if (!dragging) return
    dragging = false
    try { scene.value.releasePointerCapture(ev.pointerId) } catch { }
    if (enableInertia && (Math.abs(velocity.x) > minVelocity || Math.abs(velocity.y) > minVelocity)) {
      if (!raf) raf = requestAnimationFrame(tickInertia)
    }
  }

  // attach des events
  scene.value.addEventListener('pointerdown', down)
  scene.value.addEventListener('pointermove', move)
  scene.value.addEventListener('pointerup', end)
  scene.value.addEventListener('pointercancel', end)
  scene.value.addEventListener('pointerleave', end)

  // cleanup au démontage
  onBeforeUnmount(() => {
    cancelAnimationFrame(raf)
  })
})
</script>


<style>
html,
body {
  height: 100%;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: system-ui, Segoe UI, Roboto, Helvetica, Arial;
  -webkit-font-smoothing: antialiased;
}

/* scène avec perspective */
.scene {
  height: var(--height);
  width: var(--width);
  perspective: 1000px;
  touch-action: none;
  /* essentiel pour empêcher le scroll pendant le drag */
  /* height: 20px; */
  transition: all .5s;
}

/* l'objet 3D (box simple) */
.box {
  width: var(--width);
  height: var(--height);
  position: relative;
  transform-style: preserve-3d;
  transition: transform 120ms linear;
  /* légère smoothing quand on lâche */
  margin: auto;
  user-select: none;
  cursor: grab;
}

.box:active {
  cursor: grabbing;
}

/* faces du box */
.face {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  color: white;
  font-weight: 600;
  backface-visibility: hidden;
  /* border: 2px solid rgba(255, 255, 255, 0.06); */
  box-sizing: border-box;
  transform-origin: top right;
}

.front,
.back {
  width: 100%;
  height: 100%;
}

.face.top,
.face.bottom {
  width: var(--width);
  height: var(--depth);
}

.face.left,
.face.right {
  width: var(--depth);
  height: var(--height);
}

.face.front {
  transform: translateX(0px) translateY(0px) translateZ(0px);
}

.face.back {
  transform: rotateY(180deg) translateX(var(--width)) translateY(0px) translateZ(var(--depth));
}

.face.right {
  transform: rotateY(90deg) translateX(0px) translateY(0px) translateZ(var(--width));
  transform-origin: top left;
}

.face.left {
  transform: rotateY(-90deg) translateX(0) translateY(0px) translateZ(var(--depth));
}

.face.top {
  transform: rotateX(90deg) translateX(0px) translateY(calc(var(--depth) * -1)) translateZ(0px);
}

.face.top>* {
  @apply rotate-180;
}

.face.bottom {
  transform: rotateX(-90deg) translateX(0) translateY(0px) translateZ(calc(var(--height)));
}

.cover {
  height: 100%;
  width: 100%;
  object-fit: cover;
}

.logo {
  filter: drop-shadow(2px 2px 0 rgb(0 0 0 / 0.8));
}
</style>