import { defineComponent, Ref, ref, reactive } from 'vue'
import { Button, Slider, Popup } from 'vant'
import Speed from './speed'
import MultipleAudio, { IAudios, IMultipleAudio } from '/src/helpers/multiple-audio'
import { formatTime } from '/src/helpers/utils'
import SectionHint from '/src/helpers/section-hint'
import styles from './player.module.less'

import PlayIcon from './icons/play.svg'
import PauseIcon from './icons/pause.svg'
import ReplayIcon from './icons/replay.svg'
import SettingIcon from './icons/setting.svg'
import BackgroundIcon from './icons/background.svg'
import MusicIcon from './icons/music.svg'
import LibIcon from './icons/lib.svg'
import classNames from 'classnames'

const speedRef: Ref = ref(null)

const setStepIndex = (osmd: any, num: number) => {
  let i = 0
  osmd.cursor.reset()
  while (i < num) {
    i ++
    if (osmd.cursor.hidden !== false) {
      osmd.cursor.show()
    } else {
      // console.log(osmd)
      // osmd.cursor.iterator.moveToNextVisibleVoiceEntry(true)
      // osmd.cursor.iterator.moveToNext()
      // osmd.cursor.update()
      osmd.cursor.next()
    }
  }
}

const getIndex = (times: any[], currentTime: Number) => {
  let index = 0
  for (let i = 0; i < times.length; i++) {
    const item = times[i]
    if (currentTime >= item.time) {
      index = i
    } else {
      break
    }
  }
  return index
}

export default defineComponent({
  name: 'player',
  props: {
    osmd: Object,
    times: Array,
    songs: Object,
    lib: Object,
    openLib: Function,
    onActiveKeyChange: Function,
  } as {
    osmd: any
    times: any
    songs: any
    lib: any
    openLib: any
  },
  data() {
    return {
      sectionHint: new SectionHint(),
      audiosInstance: new MultipleAudio(Object.values(this.songs)),
      state: reactive({
        currentTime: formatTime(0),
        duration: formatTime(0),
        currentTimeNum: 0,
        durationNum: 0,
        playState: 'pause',
        loading: false,
        speedShow: false,
        speed: this.lib?.speed || 90,
        mode: this.songs.music ? 'music' : 'background',
        isFirstPlay: true,
      })
    } as {
      sectionHint: any,
      audiosInstance: IMultipleAudio,
      state: {
        currentTime: string,
        duration: string,
        currentTimeNum: number,
        durationNum: number,
        playState: string,
        loading: boolean,
        speedShow: boolean,
        speed: number,
        mode: 'background' | 'music',
        isFirstPlay: boolean,
      }
    }
  },
  methods: {
    changeMode (val: 'background' | 'music') {
      this.state.mode = val
      const cm = val === 'background' ? 'music' : 'background'
      this.audiosInstance.setMute(true, this.songs[cm])
      this.audiosInstance.setMute(false, this.songs[val])
    },
    setCurrentTime(time: number) {
      this.state.currentTimeNum = time
      this.state.currentTime = formatTime(time)
      this.audiosInstance.setCurrentTime(time)
      this.state.playState = this.audiosInstance.status
    },
    resetPlayStatus() {
      try {
        this.osmd.cursor.reset()
        this.osmd.cursor.hide()
        if (this.sectionHint) {
          this.sectionHint.destroy()
          // this.sectionHint = null
        } else {
          // this.sectionHint = new SectionHint()
          this.sectionHint.hide()
        }
        this.audiosInstance.pause()
        this.setCurrentTime(0)
        // if (speedRef.value) {
        //   speedRef.value.resetSpeed()
        // }
      } catch (error) {}
    },
    setPlayState() {
      this.state.isFirstPlay = false
      this.audiosInstance.togglePlay()
      this.state.playState = this.audiosInstance.status
    },
    onTimeChanged(num: number) {
      const time = Math.min(num, this.state.durationNum)
      this.setCurrentTime(time)
    },
    changeSpeed(speed: number) {
      this.state.speed = speed
      this.audiosInstance.setSpeed(speed/ 90)
    },
    setAudioInit() {
      const { state } = this
        this.audiosInstance.event.on('loadedmetadata', evt => {
        state.duration = formatTime((evt.target as HTMLAudioElement).duration)
        state.durationNum = (evt.target as HTMLAudioElement).duration
      })

      const ended = () => {
        this.resetPlayStatus()
        this.audiosInstance.pause()
        endNext()
      }

      let timer: any = null

      const refreshPlayer = () => {
        if (this.audiosInstance.audio) {
          state.currentTimeNum = (this.audiosInstance.audio as HTMLAudioElement).currentTime
          state.currentTime = formatTime((this.audiosInstance.audio as HTMLAudioElement).currentTime)
          const index = getIndex(this.times, this.audiosInstance.audio.currentTime)
          if (this.times[index] && state.currentTimeNum + 0.3 >= (this.times[index].time)) {
            this.osmd.cursor.show()
            this.sectionHint.show()
            if (this.times[index] && this.times[index].noteElement) {
              this.sectionHint.showForElement(this.times[index].noteElement)
              resetElementColor()
              this.times[index].noteElement.noteheadColor = '#14928A'
              this.times[index].noteElement.Notehead = '#14928A'
              // this.osmd.render()
            }
            setStepIndex(this.osmd, this.times[index].i)
            console.log(this.times[index].realKey)
            this.onActiveKeyChange(this.times[index].realKey)
            // console.log(state.currentTimeNum, this.times[index].time, index, this.times.length, this.times[index].noteElement)
          }
          if (prevIndex !== index) {
            // this.osmd.render()
            prevIndex = index
          }
        }
      }

      const startNext = () => {
        if (!timer) {
          timer = setInterval(() => refreshPlayer(), 100)
        }
      }

      const endNext = () => {
        clearInterval(timer)
      }

      const play = () => {
        state.playState = this.audiosInstance.status
        this.changeMode(state.mode)
        startNext()
      }

      const pause = () => {
        state.playState = this.audiosInstance.status
        endNext()
      }

      const waiting = () => {
        state.loading = true
      }

      const playing = () => {
        state.loading = false
      }

      const resetElementColor = () => {
        for (const item of this.times) {
          item.noteElement.noteheadColor = '#000000'
          item.noteElement.Notehead = '#000000'
        }
      }

      let prevIndex = 0

      this.audiosInstance.event.on('waiting', waiting)
      this.audiosInstance.event.on('playing', playing)
      this.audiosInstance.event.on('play', play, false)
      this.audiosInstance.event.on('pause', pause, false)
      this.audiosInstance.event.on('ended', ended, false)
      this.audiosInstance.event.on('timeupdate', refreshPlayer)

      window.addEventListener('resize', () => {
        const index = getIndex(this.times, state.currentTimeNum)
        setTimeout(() => {
          this.sectionHint?.showForElement(this.times[index]?.noteElement)
        }, 300)
      })

    },
  },
  mounted() {
    this.changeSpeed(this.lib?.speed)
    this.setAudioInit()
    // this.sectionHint = new SectionHint()
  },
  unmounted() {
    this.resetPlayStatus()
    this.audiosInstance.destroyed()
  },
  render() {
    const { state } = this

    return (
      <div class={styles.player}>
        <Button
          class={styles['play-state']}
          icon={state.playState === 'play' ? PauseIcon : PlayIcon}
          loading={state.loading}
          onClick={this.setPlayState}
        />
        <div class={styles.times}>
          <span>{state.currentTime}</span>
          <Slider
            disabled={state.isFirstPlay}
            min={0}
            max={state.durationNum}
            modelValue={state.currentTimeNum}
            onUpdate:modelValue={this.onTimeChanged}
            step={1}
            onChange={this.onTimeChanged}
            activeColor="#14928A"
          />
          <span>{state.duration}</span>
        </div>
        <Button
          class={styles['mode-button']}
          disabled={state.isFirstPlay || this.audiosInstance.length == 1}
          icon={state.mode === 'background' ? BackgroundIcon : MusicIcon}
          onClick={() => {
            this.changeMode(state.mode === 'background' ? 'music' : 'background')
          }}
        />
        <div class={styles.margin10}>
          <Button
            icon={ReplayIcon}
            disabled={state.isFirstPlay}
            onClick={() => this.resetPlayStatus()}
          />
        </div>
        <Button
          class={styles['play-state-inline']}
          icon={state.playState === 'play' ? PauseIcon : PlayIcon}
          loading={state.loading}
          onClick={this.setPlayState}
        />
        <div class={styles.badge} onClick={() => state.speedShow = true}>
          <Button
            icon={SettingIcon}
          />
          <span>{state.speed}</span>
        </div>
        <div class={classNames(styles.badge, styles.lib)} onClick={this.openLib}>
          <Button
            disabled={!this.lib}
            icon={LibIcon}
          />
          <span>{this.lib?.subjectName}</span>
        </div>
        <Popup
          round
          closeable
          style="height: '2rem'"
          teleport="body"
          closeOnPopstate={true}
          overlay={false}
          show={state.speedShow}
          onClickCloseIcon={() => state.speedShow = false}
        >
          <Speed
            ref={speedRef}
            close={() => state.speedShow = false}
            changed={this.changeSpeed}
            mode={state.mode}
            changeMode={this.changeMode}
            lib={this.lib}
          />
        </Popup>
      </div>
    )
  }
})
