import "./index.less"
import state from "/src/state"
import { getAudioCurrentTime } from "/src/view/audio-list"

type rectNotesPosType = { x: number; y: number; width: number; MeasureNumberXML: number; frequency: number; noteId: number }[]
type intonationLineType = {
   canvasDom: null | HTMLCanvasElement
   canvasCtx: null | undefined | CanvasRenderingContext2D
   canvasDomWith: number
   canvasDomHeight: number
   intonationLineBoxDom: null | HTMLElement
   osmdCanvasPageDom: null | HTMLElement
   intonationLineBotDom: null | HTMLElement
   musicLineDom: null | HTMLCanvasElement
   rectNotesPos: rectNotesPosType
   frequencyAv: number
}

export const intonationLineState = {
   canvasDom: null,
   canvasCtx: null,
   canvasDomWith: 0,
   canvasDomHeight: 80,
   intonationLineBoxDom: null,
   osmdCanvasPageDom: null,
   intonationLineBotDom: null,
   musicLineDom: null,
   rectNotesPos: [], // 音符 音准线
   frequencyAv: -1
} as intonationLineType

const progressMusicData = {
   frequency: -1,
   progressMusic: []
} as {
   frequency: number
   progressMusic: { noteId: number; x: number; y: number; width: number; status: "start" | "ing" | "end" }[]
}

/**
 * 初始化 音准器
 */
export function initIntonationLine() {
   // 创建dom
   createIntonationLine()
   // 根据音符获取坐标
   intonationLineState.rectNotesPos = getRectNotesPosByBatePos()
   console.log("rectNotesPos:", intonationLineState.rectNotesPos)
   const { musicLineDom } = drawMusicLine()
   intonationLineState.musicLineDom = musicLineDom
   // 画初始进度
   drawProgressectMusic()
   // 鸟的初始位置
   intonationLineState.intonationLineBotDom && (intonationLineState.intonationLineBotDom.style.left = `${intonationLineState.rectNotesPos[0].x}px`)
   console.log(intonationLineState, "评测小鸟数据")
}

//  模拟修改值
setInterval(() => {
   progressMusicData.frequency = getRandomNumberBetween(600, 800)
}, 10)
function getRandomNumberBetween(min: number, max: number) {
   return Math.floor(Math.random() * (max - min + 1)) + min
}

/**
 * 根据播放时间进度移动处理
 */
export function moveInitIntonationLineByPlayTime() {
   const currentTime = getAudioCurrentTime()
   if (currentTime <= state.fixtime) return
   if (currentTime > state.times.last()?.endtime) return
   // 当休止小节，可能当前音符在谱面上没有实际的音符（没有bbox），所以往后找谱面上有的音符
   let nextIndex = state.activeNoteIndex + 1
   let nextBBox = state.times[nextIndex]?.bbox
   while (!nextBBox && nextIndex < state.times.length) {
      nextIndex += 1
      nextBBox = state.times[nextIndex]?.bbox
   }
   // 当前的音符和下一个音符之间的时值 (当是最后一个音符的时候，下一个音符的时间取当前音符的endtime)
   const noteDuration =
      (nextIndex > state.times.length - 1 ? state.times[state.activeNoteIndex]?.endtime : state.times[nextIndex].time) -
      state.times[state.activeNoteIndex]?.time
   // 当前时值在该区间的占比
   const playProgress = (currentTime - state.times[state.activeNoteIndex]?.time) / noteDuration
   // 当前的进度的位置信息
   const noteDistance =
      nextIndex > state.times.length - 1
         ? intonationLineState.rectNotesPos[intonationLineState.rectNotesPos.length - 1].width
         : state.times[nextIndex].bbox.x - state.times[state.activeNoteIndex].bbox.x
   const affectDistance = noteDistance * playProgress
   const translateXNum = affectDistance + state.times[state.activeNoteIndex].bbox.x - state.times[0].bbox.x
   intonationLineState.osmdCanvasPageDom && (intonationLineState.osmdCanvasPageDom.style.transform = `translateX(-${translateXNum}px)`)
   // 更新音准器小鸟的位置信息
   updateBotByFrequency()
   // 更新音准器数据
   updateProgressMusicData(affectDistance)
}
/**
 * 根据频率更新小鸟的位置信息
 */
function updateBotByFrequency() {
   const frequency = progressMusicData.frequency
   let translateYNum = 0
   if (frequency !== -1) {
      const y =
         intonationLineState.canvasDomHeight / 2 -
         (((frequency - intonationLineState.frequencyAv) / intonationLineState.frequencyAv) * intonationLineState.canvasDomHeight) / 2
      if (y >= 0 && y <= intonationLineState.canvasDomHeight) {
         translateYNum = intonationLineState.canvasDomHeight - y
      } else if (y > intonationLineState.canvasDomHeight) {
         translateYNum = 0
      } else if (y < 0) {
         translateYNum = intonationLineState.canvasDomHeight
      }
   }
   intonationLineState.intonationLineBotDom && (intonationLineState.intonationLineBotDom.style.transform = `translateY(-${translateYNum}px)`)
}

/**
 * 根据 频率更新音准器数据
 * @affectDistance 偏移的距离
 */
const affectNum = 50
function updateProgressMusicData(affectDistance: number) {
   const { frequency, progressMusic } = progressMusicData
   const { activeNoteIndex, times } = state
   const activeNote = times[activeNoteIndex]
   // 最后
   const lastProgressmusic = progressMusic.length ? progressMusic[progressMusic.length - 1] : null
   if (frequency + affectNum > activeNote.frequency && frequency - affectNum < activeNote.frequency) {
      const y =
         intonationLineState.canvasDomHeight / 2 -
         (((activeNote.frequency - intonationLineState.frequencyAv) / intonationLineState.frequencyAv) * intonationLineState.canvasDomHeight) / 2
      if (lastProgressmusic) {
         // 有值的时候先看是不是当前小节
         if (lastProgressmusic.noteId === activeNote.noteId) {
            if (lastProgressmusic.status === "end") {
               // 当前小节 新增
               progressMusicData.progressMusic.push({
                  noteId: activeNote.noteId,
                  x: activeNote.bbox.x + affectDistance,
                  y,
                  width: 0,
                  status: "start"
               })
            } else {
               // 更新处理
               lastProgressmusic.status = "ing"
               lastProgressmusic.width = activeNote.bbox.x + affectDistance - lastProgressmusic.x
            }
         } else if (lastProgressmusic.status !== "end") {
            // 不是当前小节 并且不为end时候
            lastProgressmusic.status = "end"
            // 下一个 小节 新增
            progressMusicData.progressMusic.push({
               noteId: activeNote.noteId,
               x: activeNote.bbox.x + affectDistance,
               y,
               width: 0,
               status: "start"
            })
         }
      } else {
         // 增加新值
         progressMusicData.progressMusic.push({
            noteId: activeNote.noteId,
            x: activeNote.bbox.x + affectDistance,
            y,
            width: 0,
            status: "start"
         })
      }
   } else {
      // 没有匹配上的时候 关闭最后一个
      if (lastProgressmusic && lastProgressmusic.status !== "end") {
         lastProgressmusic.status = "end"
      }
   }
   // 更新音准器
   drawProgressectMusic()
}

/**
 * 画音准线进度
 */
function drawProgressectMusic() {
   const canvasCtx = intonationLineState.canvasCtx!
   const canvasDom = intonationLineState.canvasDom!
   canvasCtx.clearRect(0, 0, canvasDom.width, canvasDom.height)
   canvasCtx.drawImage(intonationLineState.musicLineDom!, 0, 0)
   console.log(progressMusicData.progressMusic, 888)
   // 过滤掉宽度为0的数据
   const filterProgressMusic = progressMusicData.progressMusic.filter(item => {
      return item.width !== 0
   })
   drawPathRectByArr(canvasCtx!, filterProgressMusic, "#FFC121")
}

/**
 * 画音准线
 */
function drawMusicLine() {
   const musicLineDom = document.createElement("canvas")
   musicLineDom.width = intonationLineState.canvasDomWith
   musicLineDom.height = intonationLineState.canvasDomHeight
   const musicLineCtx = musicLineDom.getContext("2d")!
   musicLineCtx.clearRect(0, 0, musicLineDom.width, musicLineDom.height)
   // 画矩形
   drawPathRectByArr(musicLineCtx, intonationLineState.rectNotesPos, "rgba(255, 255, 255, 0.3)")
   return {
      musicLineDom,
      musicLineCtx
   }
}

/**
 * 创建dom
 */
function createIntonationLine() {
   // osmdCanvasPage
   const osmdCanvasPageDom = document.querySelector("#osmdCanvasPage1") as HTMLElement
   intonationLineState.osmdCanvasPageDom = osmdCanvasPageDom
   // box
   const intonationLineBoxDom = document.createElement("div")
   intonationLineBoxDom.className = "intonationLineBox"
   intonationLineState.intonationLineBoxDom = intonationLineBoxDom
   // con
   const intonationLineConDom = document.createElement("div")
   intonationLineConDom.className = "intonationLineCon"
   //canvas
   const intonationLineCanvasDom = document.createElement("canvas")
   intonationLineCanvasDom.className = "intonationLineCanvas"
   intonationLineState.canvasDom = intonationLineCanvasDom
   intonationLineState.canvasDomWith = osmdCanvasPageDom?.offsetWidth | 0
   intonationLineCanvasDom.width = intonationLineState.canvasDomWith
   intonationLineCanvasDom.height = intonationLineState.canvasDomHeight
   intonationLineState.canvasCtx = intonationLineCanvasDom.getContext("2d")
   // bot
   const intonationLineBotDom = document.createElement("div")
   intonationLineBotDom.className = "intonationLineBot"
   intonationLineState.intonationLineBotDom = intonationLineBotDom
   document.querySelector("#musicAndSelection")?.appendChild(intonationLineBotDom)
   intonationLineConDom.appendChild(intonationLineCanvasDom)
   intonationLineBoxDom.appendChild(intonationLineConDom)
   // 添加到 osmdCanvasPage1
   osmdCanvasPageDom?.insertBefore(intonationLineBoxDom, osmdCanvasPageDom.firstChild)
}

/**
 * 根据音符获取坐标
 */
function getRectNotesPosByBatePos(): rectNotesPosType {
   let totalAvInde = 0
   // 取平均值
   const totalAv =
      state.times.reduce((total, item) => {
         if (item.frequency !== -1) {
            // -1 为休止符
            total += item.frequency
            totalAvInde++
         }
         return total
      }, 0) / totalAvInde
   intonationLineState.frequencyAv = totalAv
   const notesPos = state.times.reduce((notesArr: any[], item) => {
      // 当休止小节，可能当前音符在谱面上没有实际的音符（没有bbox），所以往后找谱面上有的音符
      if (item.bbox) {
         notesArr.push({
            noteId: item.noteId,
            frequency: item.frequency,
            MeasureNumberXML: item.MeasureNumberXML,
            x: item.bbox.x,
            // 当为休止符的时候 取最下面的位置*0.9，确保能显示完整
            y:
               intonationLineState.canvasDomHeight / 2 -
               ((((item.frequency === -1 ? 2 * totalAv * 0.1 : item.frequency) - totalAv) / totalAv) * intonationLineState.canvasDomHeight) / 2
            // cavans 高度为160 所以基准为80
         })
      }
      return notesArr
   }, [])
   // 最后一个音符延长(这里建立一个虚拟的音符延长)
   const extendPoint = {
      ...notesPos[notesPos.length - 1]
   }
   extendPoint.MeasureNumberXML++
   extendPoint.frequency = -1
   // 当总长度减30小于最后一个音符时候，取最后一个音符加15
   extendPoint.x = intonationLineState.canvasDomWith - 30 > extendPoint.x ? intonationLineState.canvasDomWith - 30 : extendPoint.x + 15
   notesPos.push(extendPoint)
   /* 计算音准线 */
   return notesPos.reduce(
      (
         arr: { MeasureNumberXML: number; frequency: number; x: number; y: number; width: number; noteId: number }[],
         { frequency, x, y, MeasureNumberXML, noteId },
         index
      ) => {
         const canvasDataLen = notesPos.length
         if (index < canvasDataLen - 1) {
            const nextCanvasObj = notesPos[index + 1]
            arr.push({
               noteId,
               MeasureNumberXML,
               frequency,
               x,
               y,
               width: nextCanvasObj.x - x
            })
         }
         return arr
      },
      []
   )
}

/**
 * 根据坐标信息 画矩形路径
 */
function drawPathRectByArr(ctx: CanvasRenderingContext2D, arr: { x: number; y: number; width: number }[], color: string) {
   arr.map(({ x, y, width }) => {
      drawRect(ctx, x, y, width * 0.92, 7, 4, color)
   })
}

/**
 * 画矩形
 */
function drawRect(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, radius: number, color: string) {
   ctx.fillStyle = color
   ctx.beginPath()
   ctx.moveTo(x + radius, y)
   ctx.lineTo(x + width - radius, y)
   ctx.arcTo(x + width, y, x + width, y + radius, radius)
   ctx.lineTo(x + width, y + height - radius)
   ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius)
   ctx.lineTo(x + radius, y + height)
   ctx.arcTo(x, y + height, x, y + height - radius, radius)
   ctx.lineTo(x, y + radius)
   ctx.arcTo(x, y, x + radius, y, radius)
   ctx.closePath()
   ctx.fill()
}
