<template>
  <h1>AUDiO Tag mit dem volume: {{ safeVolume }}</h1>
  <p>audioStatus {{ audioStatus }}</p>
  <button @click="muteAudio">muteAudio</button>
  <audio
    v-if="src"
    ref="audioElement"
    :src="src"
    loop="true"
    :volume="safeVolume"
    mediagroup="noiseGroup"
    sinkId=""
    @canplay="()=> $emit('canplay')"
  />
</template>
<script lang="ts">
import type { Logger } from 'pino'
import { defineComponent, ref, watch, computed } from 'vue'
import { ensureAudio, useAudioStore } from '~/stores/audio'
import { useUserStore } from '~/stores/user'
export default defineComponent({
  name: 'AudioTag',
  props: {
    src: {
      type: String,
      required: true
    },
    volume: {
      type: [Number, String],
      default: 0.23,
      validator: (value:any) => {
        const num = parseFloat(value)
        return num >= -3.4 && num <= 3.4
      }
    },
    play: {
      type: Boolean,
      default: false
    }
  },
  emits: ['canplay'],
  setup (props, { emit: $emit }) {
    const logger = useNuxtApp().$logger as Logger
    const audioElement = ref<HTMLAudioElement | null>(null)
    const audioStatus = ref<'stopped' | 'playing' | 'paused'>('stopped')

    const safeVolume = computed(() => {
      const vol = parseFloat(props.volume.toString())
      return Math.max(0, Math.min(1, isNaN(vol) ? 1 : vol))
    })

    const muteAudio = () => {
      if (audioElement.value) {
        audioElement.value.muted = !audioElement.value.muted
      }
    }

    // kleine Hilfsfunktion für Volume-Fading
    const fadeVolume = (audio: HTMLAudioElement, from: number, to: number, duration: number) => {
      const steps = 20
      const stepTime = duration / steps
      let currentStep = 0

      const fadeInterval = setInterval(() => {
        currentStep++
        const progress = currentStep / steps
        const newVolume = from + (to - from) * progress
        audio.volume = Math.max(0, Math.min(1, newVolume))

        if (currentStep >= steps) {
          clearInterval(fadeInterval)
          audio.volume = to
        }
      }, stepTime)
    }

    const startPlaying = async () => {
      const audioStore = useAudioStore()
      await ensureAudio()
      const sink = useUserStore().audioOutputDevice as MediaDeviceInfo
      audioElement.value?.setSinkId(sink.deviceId)
      if (audioElement.value && audioStore.isPlaying()) {
        try {
          const audio = audioElement.value
          audio.currentTime = 0
          audio.volume = 0
          audio.muted = false

          await audio.play().catch((error) => {
            logger.warn('Error playing audio:', error)
          })

          fadeVolume(audio, 0, 0.3, 8000) // weiches Fade-In
          audioStatus.value = 'playing'
        } catch (error) {
          logger.warn('Error starting audio:', error)
        }
      } else {
        logger.info('Audio Playback has not started, audioStore is not playing')
      }
    }

    const pausePlaying = () => {
      if (audioElement.value && audioStatus.value === 'playing') {
        try {
          const audio = audioElement.value
          const initialVolume = audio.volume

          fadeVolume(audio, initialVolume, 0, 300)

          setTimeout(() => {
            audio.pause()
            audioStatus.value = 'paused'
          }, 350) // minimal länger als Fade
        } catch (error) {
          logger.warn('Error pausing audio:', error)
        }
      }
    }

    const stopAndResetPlaying = () => {
      if (audioElement.value) {
        try {
          const audio = audioElement.value
          const sink = useUserStore().audioOutputDevice as MediaDeviceInfo
          audio.setSinkId(sink.deviceId)
          audio.pause()
          audio.currentTime = 0
          audio.volume = safeVolume.value
          audio.muted = true
          audioStatus.value = 'stopped'
        } catch (error) {
          logger.warn('Error stopping audio:', error)
        }
      }
    }

    const resumePlaying = async () => {
      const audioStore = useAudioStore()
      await ensureAudio()

      if (audioElement.value && audioStore.isPlaying() && audioStatus.value === 'paused') {
        try {
          const audio = audioElement.value
          audio.muted = false
          audio.volume = 0

          await audio.play().catch((error) => {
            logger.warn('Error resuming audio:', error)
          })

          fadeVolume(audio, 0, safeVolume.value, 500) // kürzeres Fade-In
          audioStatus.value = 'playing'
        } catch (error) {
          logger.warn('Error resuming audio:', error)
        }
      } else {
        logger.info('Audio Resume not possible: wrong audio state')
      }
    }

    const stopPlaying = () => {
      if (audioElement.value) {
        try {
          const audio = audioElement.value
          const initialVolume = audio.volume

          fadeVolume(audio, initialVolume, 0, 500)

          setTimeout(() => {
            audio.pause()
            audio.currentTime = 0
            audio.volume = safeVolume.value
            audio.muted = true
            audioStatus.value = 'stopped'
          }, 550)
        } catch (error) {
          logger.warn('Error stopping and fading audio:', error)
        }
      }
    }

    watch(() => props.src, () => {
      stopAndResetPlaying()
      if (audioElement.value) {
        audioElement.value.load()
      }
    })

    watch(() => props.play, (newPlay) => {
      setTimeout(() => {
        if (newPlay === false) {
          pausePlaying()
        } else if (audioStatus.value === 'paused') {
          resumePlaying()
        } else {
          startPlaying()
        }
      }, 500)
    })

    watch(() => safeVolume.value, (newVolume) => {
      if (audioElement.value && audioStatus.value === 'playing') {
        try {
          audioElement.value.volume = newVolume
        } catch (error) {
          logger.warn('Error updating audio volume:', error)
        }
      }
    })

    return {
      audioElement,
      startPlaying,
      pausePlaying,
      stopPlaying,
      resumePlaying,
      safeVolume,
      muteAudio,
      audioStatus
    }
  }
})
</script>
