<template>
  <div class="platine" :class="{ 'loading': isLoadingTrack, 'mounted': isMounted, 'playing': isPlaying }" ref="platine">
    <div v-if="true" class="debug">
      <button @click="Reverse">
        <b v-if="isReversed">reversed</b>
        <b v-else>normal</b>
      </button>
      <button @click="Rewind">
        rewind
      </button>
      <!-- <div>{{ progressPercentage }}</div> -->
      <div>{{ currentSpeed }}</div>
    </div>
    <div class="disc" ref="discRef" id="disc">
      <div class="bobine" :style="{
        height: progressPercentage + '%',
        width: progressPercentage + '%'
      }"></div>
      <button class="power-button" @click="Power" @touchstart="Power" :disabled="isLoadingTrack">
        <img class="macaron" src="/favicon.svg">
        <div class="spinner" v-if="isLoadingTrack" />
      </button>
      <div class="turn-point" v-if="!isLoadingTrack">
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import type { Card } from '~~/types/types'
import { ref, onMounted, onUnmounted, watch, computed, nextTick } from 'vue'
import Disc from '~/utils/platine/disc'
import Sampler from '~/utils/platine/sampler'

const props = defineProps<{ card?: Card, autoplay?: boolean }>()
const autoplay = props.autoplay ?? false

// State
const isLoadingTrack = ref(false)
const isFirstPlay = ref(true)
const progressPercentage = ref(0)
const currentTurns = ref(0)
const totalTurns = ref(0)// Refs pour les instances

// Refs pour les instances
const disc = ref<Disc | null>(null)
const sampler = ref<Sampler | null>(null)
const discRef = ref<HTMLElement>()
const platine = ref<HTMLElement>()
const isMounted = ref(false)

const isPlaying = computed(() => Math.abs(Math.round(sampler.value?.currentSpeed || 0)) !== 0)
const isReversed = computed(() => disc.value?.isReversed || false)
const currentSpeed = computed(() => sampler.value?.currentSpeed || 0)

// Actions
const initPlatine = (element: HTMLElement) => {
  // console.log('[INIT] Platine')
  discRef.value = element
  disc.value = new Disc(element)
  sampler.value = new Sampler()

  // Configurer les callbacks du disque
  if (disc.value) {
    disc.value.callbacks.onStop = () => {
      // console.log('[DISC] On Stop')
      sampler.value?.pause()
    }

    disc.value.callbacks.onDragStart = () => {
      // Activer le son à chaque fois qu'on glisse, pas seulement au premier play
      if (sampler.value && disc.value) {
        // On joue toujours le son quand on glisse, même après une pause
        sampler.value.play(disc.value.secondsPlayed || 0)
      }
    }

    disc.value.callbacks.onLoop = ({ playbackSpeed, isReversed, secondsPlayed }) => {
      // Ne mettre à jour que si nécessaire et s'assurer que la position est valide
      if (Math.abs((sampler.value?.currentSpeed || 0) - playbackSpeed) > 0.01) {
        const safeSecondsPlayed = Math.max(0, secondsPlayed)
        sampler.value?.updateSpeed(playbackSpeed, isReversed, safeSecondsPlayed)
      }
      updateTurns()
    }
  }
}

const updateTurns = () => {
  if (!disc.value) return

  const newTurns = disc.value.secondsPlayed * 0.75
  const newTotalTurns = (disc.value as any)._duration * 0.75

  // Calcul du pourcentage de progression pour l'affichage visuel (17% à 100%)
  const minPercentage = 17
  const maxPercentage = 100
  const progressRatio = disc.value.secondsPlayed / (disc.value as any)._duration
  const newProgressPercentage = minPercentage + (progressRatio * (maxPercentage - minPercentage))

  // Ne mettre à jour que si les valeurs ont changé de manière significative
  if (
    Math.abs(currentTurns.value - newTurns) > 0.01 ||
    Math.abs(totalTurns.value - newTotalTurns) > 0.01 ||
    Math.abs(progressPercentage.value - newProgressPercentage) > 0.1
  ) {
    currentTurns.value = newTurns
    totalTurns.value = newTotalTurns
    progressPercentage.value = newProgressPercentage
  }
}

const loadCard = async (card: Card) => {
  // console.log('[LOAD CARD]', card)
  if (!sampler.value || !card) return

  isLoadingTrack.value = true
  // console.log(disc.value)
  try {
    await sampler.value.loadTrack(card.url_audio)
    if (disc.value) {
      // console.log('[DISC] Set Duration', sampler.value.duration)
      disc.value.setDuration(sampler.value.duration)
      updateTurns()
    }
  } finally {
    isLoadingTrack.value = false
  }
}

const play = (position = 0) => {
  isFirstPlay.value = false
  if (!disc.value || !sampler.value || !props.card) return

  sampler.value.play(position)
  disc.value.powerOn()
}

const pause = () => {
  // console.log('[PAUSE]')
  if (!disc.value || !sampler.value) return

  sampler.value.pause()
  disc.value.powerOff()
}

const togglePlay = () => {
  if (isPlaying.value) {
    pause()
  } else {
    // Reprendre la lecture à la position actuelle
    const currentPosition = disc.value?.secondsPlayed || 0
    play(currentPosition)
  }
}

// Nettoyage
const cleanup = () => {
  // console.log('[CLEANUP] Platine')
  if (disc.value) {
    disc.value.stop()
    disc.value.powerOff()
  }
  if (sampler.value) {
    sampler.value.pause()
  }
}

const Power = (e: MouseEvent) => {
  togglePlay()
}

const Reverse = () => {
  if (!disc.value || !sampler.value) return

  // Sauvegarder la position actuelle
  const currentPosition = disc.value.secondsPlayed || 0
  const wasPlaying = !disc.value.isStopped()

  // Inverser la direction du disque et du sampler
  disc.value.reverse()
  sampler.value.reverse(wasPlaying ? currentPosition : 0)
}

const Rewind = async () => {
  if (!disc.value || !sampler.value) return
  Reverse()
  play()

}

const handleKeyDown = (e: KeyboardEvent) => {
  if (e.code === 'Space' || e.key === ' ' || e.keyCode === 32) {
    e.preventDefault() // Empêcher le défilement de la page
    togglePlay()
  }
}

// Initialisation du lecteur
onMounted(async () => {
  isMounted.value = true
  if (discRef.value) {
    initPlatine(discRef.value)
    await loadCard(props.card!)
    if (autoplay) {
      await nextTick()
      play()
    }
  }

  window.addEventListener('keydown', handleKeyDown)
})

// Nettoyage de l'écouteur d'événement
onUnmounted(() => {
  window.removeEventListener('keydown', handleKeyDown)
  isMounted.value = false
  cleanup()
})

// Surveillance des changements de piste
watch(() => props.card, (newCard) => {
  // console.log('[WATCH] Card', newCard)
  if (newCard) {
    loadCard(newCard)
  }
})

</script>

<style lang="scss">
.platine {
  overflow: hidden;
  position: relative;
  width: 100%;
  height: 100%;

  .disc {
    pointer-events: auto;
    position: fixed;
    background-color: transparent;
    position: relative;
    aspect-ratio: 1;
    width: 100%;
    overflow: hidden;
    border-radius: 50%;
    cursor: grab;
    background-position: center;
    background-size: cover;
    padding: 14px;

    .loading & {
      box-shadow: none;
    }
  }

  .turn-point {
    @apply absolute top-1/2 right-8 size-1/12 rounded-full bg-esyellow;
  }

  .disc.is-scratching {
    cursor: grabbing;
  }

  .power-button {
    position: absolute;
    z-index: 100;
    cursor: pointer;
    transition: all 0.1s;
    display: flex;
    justify-content: center;
    align-items: center;
    transform-origin: center;
    width: 33%;
    height: 33%;
    border-radius: 999px;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);

    .macaron {
      position: absolute;
      filter: grayscale(1);
      transition: transform 0.1s, filter 0.8s;
      @apply size-2/3;
    }

    .spinner {
      @apply size-1/2;
    }

    &:active {
      .macaron {
        transform: scale(0.8);
      }
    }
  }

  &.playing .power-button .macaron {
    filter: grayscale(0);
  }

  .disc-middle {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 20px;
    height: 20px;
    background: rgb(26, 26, 26);
    border-radius: 50%;
  }

  .spinner {
    width: 40px;
    height: 40px;
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-top-color: #fff;
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    // @apply md:border-8;
  }

  @keyframes spin {
    to {
      transform: rotate(360deg);
    }
  }

  .bobine {
    width: 17%;
    height: 17%;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    @apply relative bg-black bg-opacity-30 backdrop-blur-sm rounded-full;
  }
}
</style>
