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 audioBga1 from "../images/leftCloud.json";
import audioBga2 from "../images/rightCloud.json";
import videobg from "../images/videobg.png";
import backImg from "../images/back.png";
import {
  postMessage
} from '@/helpers/native-message';
import { usePageVisibility } from '@vant/use';
import playProgressData from "./playProgress"
import Loading from '../loading';
import { NoticeBar } from "vant"
import { generateMixedData } from "../audioVisualDraw"

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 videoBgUrl = decodeURIComponent(route.query.videoBgUrl as string || '');
    const playType = resourceUrl.lastIndexOf('mp4') !== -1 ? 'Video' : 'Audio'
    const landscapeScreen = ref(false)
    let _plrl:any
    const playIngShow = ref(true)
    const loaded = ref(false)
    let isInitAudioVisualDraw = false
    const { registerDrag, unRegisterDrag } = landscapeScreenDrag()
    const creationHeight = ref(0)
    watch(landscapeScreen, ()=>{
      if(landscapeScreen.value){
        registerDrag()
      }else{
        unRegisterDrag()
      }
    })
    // 谱面
    const staffState = reactive({
      staffSrc: "",
      isShow: false,
      height:"initial",
      speedRate:Number(decodeURIComponent(route.query.speedRate as string || "1")),
      musicRenderType:decodeURIComponent(route.query.musicRenderType as string || "staff"),
      partIndex:Number(decodeURIComponent(route.query.partIndex as string || "0"))
    })
    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"],
        fullscreen: {
          enabled: false,
          fallback: false
        }
      });
      // 在微信中运行的时候，微信没有开放自动加载资源的权限，所以要等播放之后才显示播放控制器
      _plrl.on('loadedmetadata', () => {
        loaded.value = true
        _plrl.currentTime = playProgressData.playProgress
      });
      _plrl.on('play', () => {
        playIngShow.value = false
        playStaff()
      });
      _plrl.on('pause', () => {
        playIngShow.value = true
        pauseStaff()
      });
      _plrl.on('ended', () => {
        _plrl.currentTime = 0
        if(!_plrl.playing){
          setTimeout(() => {
            updateProgressStaff(_plrl.currentTime)
          }, 100);
        }
      });
      _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")!
      let { width, height } = canvasDom.getBoundingClientRect()
      // 这里横屏的时候需要旋转，所以宽高变化一下
      if(landscapeScreen.value){
        const _width = width
        width = height
        height = _width
      }
      canvasDom.width = width
      canvasDom.height = height
      // audio
      // const audioCtx = new AudioContext()
      // const source = audioCtx.createMediaElementSource(audioDom)
      // const analyser = audioCtx.createAnalyser()
      // analyser.fftSize = fftSize
      // source?.connect(analyser)
      // analyser.connect(audioCtx.destination)
      // 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(generateMixedData(48), canvasCtx, {
        //     lineGap: 2,
        //     canvWidth: width,
        //     canvHeight: height,
        //     canvFillColor: "transparent",
        //     lineColor: "rgba(255, 255, 255, 0.7)"
        //   })
        //   if (!isPause) {
        //     requestAnimationFrameFun()
        //   }
        // })
        const _time = setInterval(() => {
          if (isPause) {
            clearInterval(_time)
            return
          }
          //analyser?.getByteFrequencyData(dataArray)
          draw(generateMixedData(38), canvasCtx, {
            lineGap: 3,
            canvWidth: width,
            canvHeight: height,
            canvFillColor: "transparent",
            lineColor: "rgba(255, 255, 255, 0.7)"
          })
        }, 300);
      }
      let isPause = true
      const playVisualDraw = () => {
        //audioCtx.resume()  // 重新更新状态   加了暂停和恢复音频音质发生了变化  所以这里取消了
        isPause = false
        requestAnimationFrameFun()
      }
      const pauseVisualDraw = () => {
        isPause = true
        requestAnimationFrame(()=>{
          canvasCtx.clearRect(0, 0, width, height);
        })
        //audioCtx?.suspend()  // 暂停   加了暂停和恢复音频音质发生了变化  所以这里取消了
        // source?.disconnect()
        // analyser?.disconnect()
      }
      return {
        playVisualDraw,
        pauseVisualDraw
      }
    }
    function handlerBack(event:MouseEvent){
      event.stopPropagation()
      playProgressData.playState = !!_plrl?.playing
      playProgressData.playProgress = _plrl?.currentTime || 0
      router.back()
    }
    //点击改变播放状态
    function handlerClickPlay(event?:MouseEvent){
      //由于ios低版本必须在用户操作之后才能初始化 createMediaElementSource 所以必须在用户操作之后初始化
      if(!isInitAudioVisualDraw && playType === "Audio"){
        isInitAudioVisualDraw = true
        // 创建音波数据
        const audioDom = document.querySelector("#audioMediaSrc") as HTMLAudioElement
        const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
        const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
        _plrl.on('play', () => {
          playVisualDraw()
        });
        _plrl.on('pause', () => {
          pauseVisualDraw()
        });
      }
      // 原生 播放暂停按钮 点击的时候 不触发
      // @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()
        setFullHeight()
        window.addEventListener('resize', updateLandscapeScreenState)
        window.addEventListener('resize', setFullHeight)
      }
    }
    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=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
      //const src = `http://192.168.3.122:3000/instrument.html#/simple-detail?id=${musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
      staffState.staffSrc = src
      window.addEventListener('message', (event) => {
        const { api, height } = event.data;
        if (api === 'api_musicPage') {
          staffState.isShow = true
          staffState.height = height + "px"
          // 如果是播放中自动开始播放  不是播放 自动跳转到当前位置
          if(playProgressData.playState){
            handlerClickPlay()
          }else{
            updateProgressStaff(_plrl.currentTime)
          }
        }
      });
    }
    function staffMoveInstance(){
      let isPause = true
      const requestAnimationFrameFun = () => {
        requestAnimationFrame(() => {
          staffDom.value?.contentWindow?.postMessage(
            {
              api: 'api_playProgress',
              content: {
                currentTime: _plrl.currentTime * staffState.speedRate
              }
            },
            "*"
          )
          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: number) => {
        // 没渲染不执行
        if(!staffState.isShow) return
        staffDom.value?.contentWindow?.postMessage(
          {
            api: 'api_updateProgress',
            content: {
              currentTime: currentTime * staffState.speedRate
            }
          },
          "*"
        )
      }
      return {
        playStaff,
        pauseStaff,
        updateProgressStaff
      }
    }
    function setFullHeight(){
      // ios 浏览器100vh 不等于可视区
      requestAnimationFrame(()=>{
        creationHeight.value = window.innerHeight
      })
    }
    onMounted(()=>{
      // 五线谱
      initStaff()
      initPlay()
      handlerLandscapeScreen()
    })
    onUnmounted(()=>{
      if(isApp){
        postMessage({
          api: "setRequestedOrientation",
          content: {
            orientation: 1,
          },
        });
      }else{
        window.removeEventListener('resize', updateLandscapeScreenState)
        window.removeEventListener('resize', setFullHeight)
      }
      _plrl?.destroy()
    })
    return () =>
    <div id="landscapeScreenPlay"
      class={[styles.playCreation,landscapeScreen.value && styles.landscapeScreen,!loaded.value && styles.notLoaded, browser().isTablet && styles.ipadPlayCreation]}
      style={
        {
          "--creationHeight":creationHeight.value ? creationHeight.value+"px" : "100vh"
        }
      }
      onClick={
        (event)=>{
          staffState.isShow && handlerClickPlay(event)
        }
      }
    >
      <div class={styles.backBox}>
        <img class={styles.backImg} src={backImg} onClick={handlerBack} />
        <div class={styles.musicDetail}>
          <div class={styles.musicSheetName}>
              <NoticeBar
                  text={musicSheetName}
                  background="none"
              />
          </div>
          <div class={styles.username}>演奏：{username}</div>
        </div>
      </div>
      {
          playType === 'Audio' ?
          <div class={styles.audioBox}>
            <canvas class={styles.audioVisualizer} id="audioVisualizer"></canvas>
            <Vue3Lottie class={styles.audioBga} animationData={audioBga} autoPlay={true} loop={true}></Vue3Lottie>
            <Vue3Lottie class={styles.audioBga1} animationData={audioBga1} autoPlay={true} loop={true}></Vue3Lottie>
            <Vue3Lottie class={styles.audioBga2} animationData={audioBga2} autoPlay={true} 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={ videoBgUrl || videobg}
            preload="metadata"
            playsinline
            webkit-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>
      }
      {
        !staffState.isShow && <Loading></Loading>
      }
    </div>;
  }
});
