import { defineComponent, onMounted, reactive, ref, onUnmounted, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { browser, vaildMusicScoreUrl } from "@/helpers/utils"
import styles from './index.module.less';
import "plyr/dist/plyr.css";
import Plyr from "plyr";
import { Vue3Lottie } from "vue3-lottie";
import audioBga from "../images/audioBga.json";
import videobg from "../images/videobg.png";
import backImg from "../images/back.png";
import {
  postMessage
} from '@/helpers/native-message';
import { usePageVisibility } from '@vant/use';

export default defineComponent({
  name: 'playCreation',
  setup() {
    const {isApp} = browser()
    const route = useRoute();
    const router = useRouter();
    const resourceUrl = decodeURIComponent(route.query.resourceUrl as string || '');
    const musicSheetName = decodeURIComponent(route.query.musicSheetName as string || '');
    const username = decodeURIComponent(route.query.username as string || '');
    const musicSheetId = decodeURIComponent(route.query.musicSheetId as string || '');
    const playType = resourceUrl.lastIndexOf('mp4') !== -1 ? 'Video' : 'Audio'
    const lottieDom = ref()
    const landscapeScreen = ref(false)
    let _plrl:any
    const playIngShow = ref(true)
    const loaded = ref(false)
    const { registerDrag, unRegisterDrag } = landscapeScreenDrag()
    watch(landscapeScreen, ()=>{
      if(landscapeScreen.value){
        registerDrag()
      }else{
        unRegisterDrag()
      }
    })
    // 谱面
    const staffState = reactive({
      staffSrc: "",
      isShow: false,
      height:"initial"
    })
    const staffDom= ref<HTMLIFrameElement>()
    const {playStaff, pauseStaff, updateProgressStaff} = staffMoveInstance()
    function initPlay(){
      const id = playType === "Audio" ? "#audioMediaSrc" : "#videoMediaSrc";
      _plrl = new Plyr(id, {
        controls: ["play", "progress", "current-time", "duration"]
      });
      // 在微信中运行的时候，微信没有开放自动加载资源的权限，所以要等播放之后才显示播放控制器
      _plrl.on('loadedmetadata', () => {
        loaded.value = true
      });
      // 创建音波数据
      if(playType === "Audio"){
        const audioDom = document.querySelector("#audioMediaSrc") as HTMLAudioElement
        const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
        const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
        _plrl.on('play', () => {
          lottieDom.value.play()
          playVisualDraw()
        });
        _plrl.on('pause', () => {
          lottieDom.value.pause()
          pauseVisualDraw()
        });
      }
      _plrl.on('play', () => {
        playIngShow.value = false
        playStaff()
      });
      _plrl.on('pause', () => {
        playIngShow.value = true
        pauseStaff()
      });
      _plrl.on('seeked', () => {
        // 暂停的时候调用
        if(!_plrl.playing){
          updateProgressStaff(_plrl.currentTime)
        }
      });
    }
    // 注册 横屏时候的自定义拖动事件 解决旋转时候拖动进度条坐标的问题
    function landscapeScreenDrag() {
      let progressBar: HTMLElement
      function onDown(e: MouseEvent | TouchEvent) {
        e.preventDefault();
        e.stopPropagation();
        // 记录拖动之前的状态
        const playing = _plrl.playing
        _plrl.pause()
        const isTouchEv = isTouchEvent(e);
        const event = isTouchEv ? e.touches[0] : e;
        setProgress(event)
        function onUp() {
          document.removeEventListener(
            isTouchEv ? 'touchmove' : 'mousemove',
            onMove
          );
          document.removeEventListener(isTouchEv ? 'touchend' : 'mouseup', onUp);
          playing && _plrl.play()  // 之前是播放状态  就播放
        }
        function onMove(e: MouseEvent | TouchEvent){
          e.preventDefault();
          e.stopPropagation();
          const event = isTouchEvent(e) ? e.touches[0] : e;
          setProgress(event)
        }
        function setProgress(event: MouseEvent | Touch) {
          const {top, height} = progressBar.getBoundingClientRect();
          const progress = (event.clientY - top) / height;
          const progressNum = Math.min(Math.max(progress, 0), 1);
          _plrl.currentTime = progressNum * _plrl.duration
        }
        document.addEventListener(isTouchEv ? 'touchmove' : 'mousemove', onMove);
        document.addEventListener(isTouchEv ? 'touchend' : 'mouseup', onUp);
      }
      function registerDrag() {
        if(!progressBar){
          progressBar = document.querySelector('#landscapeScreenPlay .plyr__progress__container') as HTMLElement;
        }
        progressBar.addEventListener('mousedown', onDown);
        progressBar.addEventListener('touchstart', onDown);
      }
      function unRegisterDrag() {
        progressBar.removeEventListener('mousedown', onDown);
        progressBar.removeEventListener('touchstart', onDown);
      }
      return {
        registerDrag,
        unRegisterDrag
      }
    }
    function isTouchEvent(e: MouseEvent | TouchEvent): e is TouchEvent {
      return window.TouchEvent && e instanceof window.TouchEvent;
    }
    /**
     * 音频可视化
     * @param audioDom
     * @param canvasDom
     * @param fftSize  2的幂数，最小为32
     */
    function audioVisualDraw(audioDom: HTMLAudioElement, canvasDom: HTMLCanvasElement, fftSize = 128) {
      type propsType = { canvWidth: number; canvHeight: number; canvFillColor: string; lineColor: string; lineGap: number }
      // canvas
      const canvasCtx = canvasDom.getContext("2d")!
      const { width, height } = canvasDom.getBoundingClientRect()
      canvasDom.width = width
      canvasDom.height = height
      // audio
      let audioCtx : AudioContext | null = null
      let analyser : AnalyserNode | null = null
      let source : MediaElementAudioSourceNode | null = null
      const dataArray = new Uint8Array(fftSize / 2)
      const draw = (data: Uint8Array, ctx: CanvasRenderingContext2D, { lineGap, canvWidth, canvHeight, canvFillColor, lineColor }: propsType) => {
        if (!ctx) return
        const w = canvWidth
        const h = canvHeight
        fillCanvasBackground(ctx, w, h, canvFillColor)
          // 可视化
        const dataLen = data.length
        let step = (w / 2 - lineGap * dataLen) / dataLen
        step < 1 && (step = 1)
        const midX = w / 2
        const midY = h / 2
        let xLeft = midX
        for (let i = 0; i < dataLen; i++) {
          const value = data[i]
          const percent = value / 255 // 最大值为255
          const barHeight = percent * midY
          canvasCtx.fillStyle = lineColor
          // 中间加间隙
          if (i === 0) {
            xLeft -= lineGap / 2
          }
          canvasCtx.fillRect(xLeft - step, midY - barHeight, step, barHeight)
          canvasCtx.fillRect(xLeft - step, midY, step, barHeight)
          xLeft -= step + lineGap
        }
        let xRight = midX
        for (let i = 0; i < dataLen; i++) {
          const value = data[i]
          const percent = value / 255 // 最大值为255
          const barHeight = percent * midY
          canvasCtx.fillStyle = lineColor
          if (i === 0) {
            xRight += lineGap / 2
          }
          canvasCtx.fillRect(xRight, midY - barHeight, step, barHeight)
          canvasCtx.fillRect(xRight, midY, step, barHeight)
          xRight += step + lineGap
        }
      }
      const fillCanvasBackground = (ctx: CanvasRenderingContext2D, w: number, h: number, colors: string) => {
        ctx.clearRect(0, 0, w, h)
        ctx.fillStyle = colors
        ctx.fillRect(0, 0, w, h)
      }
      const requestAnimationFrameFun = () => {
        requestAnimationFrame(() => {
          analyser?.getByteFrequencyData(dataArray)
          draw(dataArray, canvasCtx, {
            lineGap: 2,
            canvWidth: width,
            canvHeight: height,
            canvFillColor: "transparent",
            lineColor: "rgba(255, 255, 255, 0.7)"
          })
          if (!isPause) {
            requestAnimationFrameFun()
          }
        })
      }
      let isPause = true
      const playVisualDraw = () => {
        if (!audioCtx) {
          audioCtx = new AudioContext()
          source = audioCtx.createMediaElementSource(audioDom)
          analyser = audioCtx.createAnalyser()
          analyser.fftSize = fftSize
          source?.connect(analyser)
          analyser.connect(audioCtx.destination)
        }
        //audioCtx.resume()  // 重新更新状态   加了暂停和恢复音频音质发生了变化  所以这里取消了
        isPause = false
        requestAnimationFrameFun()
      }
      const pauseVisualDraw = () => {
        isPause = true
        //audioCtx?.suspend()  // 暂停   加了暂停和恢复音频音质发生了变化  所以这里取消了
        // source?.disconnect()
        // analyser?.disconnect()
      }
      return {
        playVisualDraw,
        pauseVisualDraw
      }
    }
    function handlerBack(event:MouseEvent){
      event.stopPropagation()
      router.back()
    }
    //点击改变播放状态
    function handlerClickPlay(event:MouseEvent){
      // 原生 播放暂停按钮 点击的时候 不触发
      // @ts-ignore
      if(event.target?.matches('button.plyr__control')){
        return
      }
      if (_plrl.playing) {
        _plrl.pause();
      } else {
        _plrl.play();
      }
    }
    function handlerLandscapeScreen(){
      // app端调用app的横屏
      if(isApp){
        postMessage({
          api: "setRequestedOrientation",
          content: {
            orientation: 0,
          },
        });
      }else{
        // web端使用旋转的方式
        updateLandscapeScreenState()
        window.addEventListener('resize', updateLandscapeScreenState)
      }
    }
    function updateLandscapeScreenState(){
      // 下一帧 计算  横竖屏切换太快  获取的宽高不准
      requestAnimationFrame(()=>{
        if(window.innerWidth > window.innerHeight){
          landscapeScreen.value = false
        }else{
          landscapeScreen.value = true
        }
      })
    }
    const pageVisibility = usePageVisibility();
    watch(pageVisibility, value => {
      if (value === 'hidden') {
        _plrl?.pause();
      }
    });
    // 初始化五线谱
    function initStaff(){
      const src = `${vaildMusicScoreUrl()}/instrument/#/simple-detail?id=${musicSheetId}&musicRenderType=staff`;
      //const src = `http://192.168.3.68:3000/instrument.html#/simple-detail?id=${musicSheetId}&musicRenderType=staff`;
      staffState.staffSrc = src
      window.addEventListener('message', (event) => {
        const { api, height } = event.data;
        if (api === 'api_musicPage') {
          staffState.isShow = true
          staffState.height = height + "px"
          // 如果是播放中自动开始 播放
          if(_plrl.playing){
            playStaff()
          }
        }
      });
    }
    function staffMoveInstance(){
      let isPause = true
      const requestAnimationFrameFun = () => {
        requestAnimationFrame(() => {
          staffDom.value?.contentWindow?.postMessage(
            {
              api: 'api_playProgress',
              content: {
                currentTime: _plrl.currentTime
              }
            },
            "*"
          )
          if (!isPause) {
            requestAnimationFrameFun()
          }
        })
      }
      const playStaff = () => {
        // 没渲染不执行
        if(!staffState.isShow) return
        isPause = false
        staffDom.value?.contentWindow?.postMessage(
          {
            api: 'api_play'
          },
          "*"
        )
        requestAnimationFrameFun()
      }
      const pauseStaff = () => {
        // 没渲染不执行
        if(!staffState.isShow) return
        isPause = true
        staffDom.value?.contentWindow?.postMessage(
          {
            api: 'api_paused'
          },
          "*"
        )
      }
      const updateProgressStaff = (currentTime: string) => {
        // 没渲染不执行
        if(!staffState.isShow) return
        staffDom.value?.contentWindow?.postMessage(
          {
            api: 'api_updateProgress',
            content: {
              currentTime
            }
          },
          "*"
        )
      }
      return {
        playStaff,
        pauseStaff,
        updateProgressStaff
      }
    }
    onMounted(()=>{
      // 五线谱
      initStaff()
      initPlay()
      handlerLandscapeScreen()
    })
    onUnmounted(()=>{
      if(isApp){
        postMessage({
          api: "setRequestedOrientation",
          content: {
            orientation: 1,
          },
        });
      }else{
        window.removeEventListener('resize', updateLandscapeScreenState)
      }
    })
    return () =>
    <div id="landscapeScreenPlay" class={[styles.playCreation,landscapeScreen.value && styles.landscapeScreen,!loaded.value && styles.notLoaded]} onClick={handlerClickPlay}>
      <div class={styles.backBox}>
        <img class={styles.backImg} src={backImg} onClick={handlerBack} />
        <div class={styles.musicDetail}>
          <div class={styles.musicSheetName}>{musicSheetName}</div>
          <div class={styles.username}>{username}</div>
        </div>
      </div>
      {
          playType === 'Audio' ?
          <div class={styles.audioBox}>
            <canvas class={styles.audioVisualizer} id="audioVisualizer"></canvas>
            <Vue3Lottie ref={lottieDom} class={styles.audioBga} animationData={audioBga} autoPlay={false} loop={true}></Vue3Lottie>
            <audio
              crossorigin="anonymous"
              id="audioMediaSrc"
              src={resourceUrl}
              controls="false"
              preload="metadata"
              playsinline
            />
          </div>
          :
          <video
            id="videoMediaSrc"
            class={styles.videoBox}
            src={resourceUrl}
            data-poster={videobg}
            preload="metadata"
            playsinline
          />
      }
      <div class={[styles.playLarge, playIngShow.value && styles.playIngShow]}></div>
      {/* 谱面 */}
      {
        staffState.staffSrc &&
        <div
          class={[styles.staffBox, staffState.isShow && styles.staffBoxShow]}
          style={
            {
              '--staffBoxHeight':staffState.height
            }
          }
        >
          <div class={styles.mask}></div>
          <iframe
            ref={staffDom}
            class={styles.staff}
            frameborder="0"
            src={staffState.staffSrc}>
          </iframe>
        </div>
      }
    </div>;
  }
});
