<template>
   <div
      class="creation"
      :style="{
         '--heightA': state.heightA + 'px',
         '--navBarHeight': navBarHeight + 'px'
      }"
   >
      <div class="creationBg"></div>
      <van-sticky>
         <van-nav-bar
            class="nav"
            :class="{ isScreenScroll: isScreenScroll }"
            :fixed="false"
            :title="state.musicDetail.musicSheetName"
            left-arrow
            @click-left="goBack"
         />
      </van-sticky>
      <div class="singer">演奏：{{ state.musicDetail.username }}</div>
      <van-sticky :offset-top="44 + navBarHeight" :z-index="200">
         <div class="playBox" ref="playBoxDom">
            <div
               :class="[
                  'playSection',
                  plyrState.mediaTimeShow && 'mediaTimeShow',
                  isLandscapeScreen && 'isLandscapeScreen',
                  state.playType === 'Video' && 'videoType'
               ]"
               id="playMediaSection"
               @click="handlerClickPlay"
            >
               <!-- 横屏 -->
               <div v-if="isLandscapeScreen" class="backBox">
                  <img class="backImg" :src="require('./img/back.png')" @click="handlerBack" />
                  <div class="musicDetail">
                     <div class="musicSheetName">
                        <van-notice-bar :text="state.musicDetail.musicSheetName" background="none" />
                     </div>
                     <div class="username">演奏：{{ state.musicDetail.username }}</div>
                  </div>
               </div>
               <!-- audio -->
               <div class="audioBox" v-if="state.playType === 'Audio'">
                  <canvas class="audioVisualizer" id="audioVisualizer"></canvas>
                  <audio
                     crossorigin="anonymous"
                     id="audioMediaSrc"
                     :src="state.musicDetail.videoUrl"
                     controls="false"
                     preload="metadata"
                     playsinline
                     webkit-playsinline
                  />
                  <img src="./img/ty.png" class="tyBg" />
                  <div class="audioBoxBg">
                     <div :class="['audioPan', plyrState.playIngShow ? 'imgRotate' : '']">
                        <van-image class="audioImg" :src="state.musicDetail.img || require('./img/music_bg.png')" />
                     </div>
                     <i class="audioPoint"></i>
                     <i :class="['audioZhen', plyrState.playIngShow && 'active']"></i>
                  </div>
               </div>
               <!-- video -->
               <video
                  v-if="state.playType === 'Video'"
                  id="videoMediaSrc"
                  class="videoBox"
                  :src="state.musicDetail.videoUrl"
                  :data-poster="state.musicDetail.videoImg || require('./img/videoBg.png')"
                  :poster="state.musicDetail.videoImg || require('./img/videoBg.png')"
                  preload="metadata"
                  playsinline
                  webkit-playsinline
                  x5-playsinline
               />
               <!-- 工具 -->
               <div :class="['playLarge', !plyrState.mediaTimeShow && plyrState.playIngShow && 'playIngShow']"></div>
               <div class="mediaTimeCon">
                  <div class="mediaTime">
                     <div>
                        {{ getSecondRPM(plyrState.currentTime) }}
                     </div>
                     <div class="note">/</div>
                     <div class="duration">
                        {{ getSecondRPM(plyrState.duration) }}
                     </div>
                  </div>
               </div>
               <div class="landscapeScreen" @click="handlerLandscapeScreen"></div>
               <!-- 谱面 -->
               <div v-if="staffState.staffSrc" :class="['staffBoxCon', staffState.isShow && 'staffBoxShow']">
                  <div
                     class="staffBox"
                     :style="{
                        '--staffBoxHeight': staffState.height
                     }"
                  >
                     <div class="mask"></div>
                     <iframe ref="staffDom" class="staff" frameborder="0" :src="staffState.staffSrc"></iframe>
                  </div>
               </div>
            </div>
         </div>
      </van-sticky>
      <div class="musicSection">
         <div class="avatarInfoBox">
            <div class="avatar">
               <van-image class="userLogo" :src="state.musicDetail.avatar" />
               <div class="infoCon">
                  <div class="info">
                     <span class="userName">{{ state.musicDetail.username }}</span>
                     <img :src="require('./img/icon-member.png')" v-if="state.musicDetail.vipFlag" class="iconMember" />
                  </div>
                  <div class="sub">
                     {{
                        state.musicDetail.subjectName ? state.musicDetail.subjectName : ""
                     }}
                  </div>
               </div>
            </div>
            <div class="linkes">
               <img :src="require('./img/icon-zan.png')" class="iconZan" />
               <span>{{ state.musicDetail.likeNum }}</span>
            </div>
         </div>
         <textEllipsis class="textEllipsis" :text="state.musicDetail.desc || ''" />
      </div>
      <div class="likeSection">
         <div class="likeTitle">点赞记录</div>
         <van-list
            v-if="state.listState.dataShow"
            :finished="state.listState.finished"
            :finishedText="' '"
            @load="getStarList"
            :immediateCheck="false"
         >
            <van-cell
               v-for="(item, index) in state.list"
               :key="index"
               :class="['likeItem', index === state.list.length - 1 && 'likeItemLast']"
               :border="false"
            >
               <template #icon>
                  <van-image :src="item.userAvatar" class="userLogo" />
               </template>
               <template #title>
                  <div class="userInfo">
                     <p class="name">{{ item.userName || `游客${item.userId}` }}</p>
                     <p class="sub">
                        {{ item.subjectName }}
                     </p>
                  </div>
               </template>
               <template #default>
                  <div class="time">
                     {{ onDayjs(item.createTime) }}
                  </div>
               </template>
            </van-cell>
         </van-list>
         <MEmpty class="mEmpty" v-else msg="暂无内容" style="margin-bottom: 0.5rem" />
      </div>
      <div class="upward" v-show="!isScreenScroll">
         <img :src="require('./img/upward.png')" />
      </div>
      <div class="bottomSection">
         <div class="bottomShare">
            <p @click="onDownload">
               <img :src="require('./img/icon-download.png')" />
               <span>下载</span>
            </p>
            <p @click="() => (state.shareStatus = true)">
               <img :src="require('./img/icon-share.png')" />
               <span>分享</span>
            </p>
            <p @click="() => (state.deleteStatus = true)">
               <img :src="require('./img/icon-delete.png')" />
               <span>删除</span>
            </p>
         </div>
         <img
            :src="require('./img/edit.png')"
            class="btnEdit"
            @click="
               () => {
                  setStatusBarTextColor(false)
                  $router.push({ path: '/creation-edit', query: { id: this.id } })
               }
            "
         />
      </div>
      <Loading v-if="!staffState.isShow"></Loading>
      <van-popup position="bottom" v-model="state.shareStatus" style=" background: transparent ">
         <ShareModel :musicDetail="state.musicDetail" @close="state.shareStatus = false" />
      </van-popup>
      <van-popup v-model="state.deleteStatus" round class="popupContainer">
         <p class="popupTit">温馨提示</p>
         <p class="popupContent">确认删除作品吗？</p>
         <div class="popupBtnGroup">
            <van-button round @click="() => (state.deleteStatus = false)">
               取消
            </van-button>
            <van-button round type="primary" @click="onDelete">
               确认
            </van-button>
         </div>
      </van-popup>
   </div>
</template>

<script>
import dayjs from "dayjs"
import { browser, getSecondRPM } from "@/common/common"
import { postMessage } from "@/helpers/native-message"
import { api_userMusicDetail, api_userMusicRemove, api_userMusicStarPage } from "./api"
import audioVisualDraw, { vaildMusicScoreUrl } from "./audioVisualDraw"
import textEllipsis from "./textEllipsis"
import Loading from "./loading"
import "plyr/dist/plyr.css"
import Plyr from "plyr"
import MEmpty from "@/components/MEmpty"
import ShareModel from "./share-model"
export default {
   name: "creation",
   data() {
      return {
         id: this.$route.query.id,
         state: {
            deleteStatus: false,
            shareStatus: false,
            playType: "", // 播放类型
            musicDetail: {},
            isClick: false,
            list: [],
            listState: {
               dataShow: true, // 判断是否有数据
               loading: false,
               finished: false
            },
            params: {
               page: 1,
               rows: 20
            },
            _plrl: null,
            heightA: 0
         },
         plyrState: {
            duration: 0,
            currentTime: 0,
            mediaTimeShow: false,
            playIngShow: true
         },
         isLandscapeScreen: false,
         isScreenScroll: false,
         navBarHeight: 0,
         staffState: {
            staffSrc: "",
            isShow: false,
            height: "initial",
            speedRate: 1,
            musicRenderType: "staff",
            partIndex: 0
         }
      }
   },
   components: {
      textEllipsis,
      MEmpty,
      Loading,
      ShareModel
   },
   methods: {
      getSecondRPM,
      onDayjs(time) {
         return dayjs(time).format("YYYY-MM-DD HH:mm")
      },
      goBack() {
         if (browser().isApp) {
            this.setStatusBarTextColor(false)
            postMessage({ api: "setBarStatus", content: { status: 1, backButtonHidden: 0 } })
            postMessage({
               api: "goBack"
            })
         } else {
            this.$router.back()
         }
      },
      // 下载
      onDownload() {
         postMessage({
            api: "saveFile",
            content: {
               url: this.state.musicDetail.videoUrl
            }
         })
      },
      // 删除作品
      async onDelete() {
         try {
            await api_userMusicRemove({ id: this.id })
            setTimeout(() => {
               this.state.deleteStatus = false
               this.$toast("删除成功")
            }, 100)
            setTimeout(() => {
               this.goBack()
            }, 1200)
         } catch {
            //
         }
      },
      async getStarList() {
         try {
            if (this.state.isClick) return
            this.state.isClick = true
            const res = await api_userMusicStarPage({
               userMusicId: this.id,
               ...this.state.params
            })
            this.state.listState.loading = false
            const result = res.data || {}
            // 处理重复请求数据
            if (this.state.list.length > 0 && result.current === 1) {
               return
            }
            this.state.list = this.state.list.concat(result.rows || [])
            this.state.listState.finished = result.current >= result.pages
            this.state.params.page = result.current + 1
            this.state.listState.dataShow = this.state.list.length > 0
            this.state.isClick = false
         } catch {
            this.state.listState.dataShow = false
            this.state.listState.finished = true
            this.state.isClick = false
         }
      },
      // 初始化 媒体播放
      initMediaPlay() {
         const { playStaff, pauseStaff, updateProgressStaff } = this.staffMoveInstance()
         const id = this.state.playType === "Audio" ? "#audioMediaSrc" : "#videoMediaSrc"
         this.state._plrl = new Plyr(id, {
            controls: ["play", "progress", "current-time", "duration"],
            fullscreen: {
               enabled: false,
               fallback: false
            }
         })
         const player = this.state._plrl
         // 创建音波数据
         if (this.state.playType === "Audio") {
            const audioDom = document.querySelector("#audioMediaSrc")
            const canvasDom = document.querySelector("#audioVisualizer")
            const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
            player.on("play", () => {
               playVisualDraw()
            })
            player.on("pause", () => {
               pauseVisualDraw()
            })
         }
         player.on("timeupdate", () => {
            this.plyrState.currentTime = player.currentTime
         })
         player.on("play", () => {
            this.plyrState.playIngShow = false
            playStaff()
         })
         player.on("pause", () => {
            this.plyrState.playIngShow = true
            pauseStaff()
         })
         player.on("ended", () => {
            if (this.plyrState.mediaTimeShow) return
            player.currentTime = 0
            if (!player.playing) {
               setTimeout(() => {
                  updateProgressStaff(player.currentTime)
               }, 100)
            }
         })
         // 处理按压事件
         const handleStart = () => {
            if (this.isLandscapeScreen.value) {
               return
            }
            this.plyrState.duration = player.duration
            this.plyrState.mediaTimeShow = true
         }
         // 处理松开事件
         const handleEnd = () => {
            this.plyrState.mediaTimeShow = false
            // 暂停的时候调用
            if (!player.playing) {
               updateProgressStaff(player.currentTime)
            }
         }
         const progressDom = document.querySelector("#playMediaSection .plyr__controls .plyr__progress__container")
         progressDom.addEventListener("mousedown", handleStart)
         progressDom.addEventListener("touchstart", handleStart)
         progressDom.addEventListener("mouseup", handleEnd)
         progressDom.addEventListener("touchend", handleEnd)
      },
      // 初始化五线谱
      initStaff() {
         const src = `${vaildMusicScoreUrl()}/gym-music-score/#/simple-detail?id=${this.state.musicDetail.musicSheetId}&musicRenderType=${
            this.staffState.musicRenderType
         }&part-index=${this.staffState.partIndex}`
         //const src = `http://192.168.3.122:3000/gym-music-score.html#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
         this.staffState.staffSrc = src
         window.addEventListener("message", event => {
            const { api, height } = event.data
            if (api === "api_musicPage") {
               this.staffState.isShow = true
               this.staffState.height = height + "px"
            }
         })
      },
      staffMoveInstance() {
         let isPause = true
         const requestAnimationFrameFun = () => {
            requestAnimationFrame(() => {
               this.$refs.staffDom?.contentWindow?.postMessage(
                  {
                     api: "api_playProgress",
                     content: {
                        currentTime: this.state._plrl.currentTime * this.staffState.speedRate
                     }
                  },
                  "*"
               )
               if (!isPause) {
                  requestAnimationFrameFun()
               }
            })
         }
         const playStaff = () => {
            // 没渲染不执行
            if (!this.staffState.isShow) return
            isPause = false
            this.$refs.staffDom?.contentWindow?.postMessage(
               {
                  api: "api_play"
               },
               "*"
            )
            requestAnimationFrameFun()
         }
         const pauseStaff = () => {
            // 没渲染不执行
            if (!this.staffState.isShow) return
            isPause = true
            this.$refs.staffDom?.contentWindow?.postMessage(
               {
                  api: "api_paused"
               },
               "*"
            )
         }
         const updateProgressStaff = currentTime => {
            // 没渲染不执行
            if (!this.staffState.isShow) return
            this.$refs.staffDom?.contentWindow?.postMessage(
               {
                  api: "api_updateProgress",
                  content: {
                     currentTime: currentTime * this.staffState.speedRate
                  }
               },
               "*"
            )
         }
         return {
            playStaff,
            pauseStaff,
            updateProgressStaff
         }
      },
      //点击改变播放状态
      handlerClickPlay(event) {
         // 原生 播放暂停按钮 点击的时候 不触发
         if (event?.target?.matches("button.plyr__control")) {
            return
         }
         if (this.state._plrl.playing) {
            this.state._plrl.pause()
         } else {
            this.state._plrl.play()
         }
      },
      handleScroll() {
         const height = window.scrollY || document.documentElement.scrollTop
         // 防止多次调用
         if (height > 0 && this.isScreenScroll === false) {
            this.isScreenScroll = true
            this.setStatusBarTextColor(false)
         }
         if (height <= 0) {
            this.isScreenScroll = false
            this.setStatusBarTextColor(true)
         }
      },
      // 设置导航栏颜色
      setStatusBarTextColor(isWhite) {
         postMessage({
            api: "setStatusBarTextColor",
            content: { statusBarTextColor: isWhite }
         })
      },
      handleVisibilitychange() {
         if (document.hidden) {
            this.state._plrl?.pause()
         }
      },
      handlerBack(event) {
         event.stopPropagation()
         this.verticalScreen()
      },
      landscapeScreen() {
         postMessage({
            api: "setRequestedOrientation",
            content: {
               orientation: 0
            }
         })
         this.isLandscapeScreen = true
      },
      verticalScreen() {
         postMessage({
            api: "setRequestedOrientation",
            content: {
               orientation: 1
            }
         })
         this.isLandscapeScreen = false
      },
      handlerLandscapeScreen(event) {
         event.stopPropagation()
         if (!this.isLandscapeScreen) {
            this.landscapeScreen()
         }
      }
   },
   mounted() {
      this.state.heightA = this.$refs.playBoxDom.offsetHeight
      document.addEventListener("scroll", this.handleScroll)
      document.addEventListener("visibilitychange", this.handleVisibilitychange)
   },
   destroyed() {
      this.state._plrl?.destroy()
      document.removeEventListener("scroll", this.handleScroll)
      document.removeEventListener("visibilitychange", this.handleVisibilitychange)
   },
   async created() {
      this.setStatusBarTextColor(true)
      postMessage({ api: "setBarStatus", content: { status: 0, backButtonHidden: 1 } })
      postMessage({ api: "getNavHeight" }, res => {
         const { content } = res
         const dpi = content.dpi || 2
         if (content.navHeight) {
            const navHeight = content.navHeight / dpi
            this.navBarHeight = navHeight
         }
      })
      /* 初始化请求 */
      try {
         const res = await api_userMusicDetail(this.id)
         this.state.musicDetail = res.data || {}
         try {
            const jsonConfig = JSON.parse(res.data.jsonConfig)
            jsonConfig.speedRate && (this.staffState.speedRate = jsonConfig.speedRate)
            jsonConfig.musicRenderType && (this.staffState.musicRenderType = jsonConfig.musicRenderType)
            jsonConfig.partIndex && (this.staffState.partIndex = jsonConfig.partIndex)
         } catch {}
         // 五线谱
         this.initStaff()
         this.getStarList()
         // 判断是视频还是音频
         if (res.data.videoUrl.lastIndexOf("mp4") !== -1) {
            this.state.playType = "Video"
         } else {
            this.state.playType = "Audio"
         }
         this.$nextTick(() => {
            this.initMediaPlay()
         })
      } catch (e) {
         this.staffState.isShow = true
         if (e.code === 999) {
            this.$dialog
               .alert({
                  message: e.msg,
                  theme: "round-button",
                  confirmButtonColor: "#2DC7AA"
               })
               .then(() => {
                  this.goBack()
               })
         }
      }
   }
}
</script>

<style lang="less" scoped>
@import url("./index.less");
</style>
