import { defineComponent, onMounted, PropType, ref, Ref, toRefs, onUpdated, onUnmounted, watch } from 'vue'
import { EngravingRules, IMusicScore, OpenSheetMusicDisplay, OSMDOptions } from '/osmd-extended/src'
import { useEngravingRules, useOsmd, useOsmdLoader } from './uses'
import SettingState from '/src/pages/detail/setting-state'
import detailState from '/src/pages/detail/state'
import event from '/src/components/music-score/event'
import styles from '/src/components/music-score/index.module.less'
import SectionWrap from '../pages/detail/section-box'
import runtime, * as RuntimeUtils from '/src/pages/detail/runtime'
import { Toast } from 'vant'
import axios from 'umi-request'
import { Cursor } from '../helpers/cursor'
import { formatZoom } from '../helpers/utils'
import { musicInfo } from '../subpages/colexiu/state'
import { getAllNodes } from '../pages/detail/helpers'

export type onRerenderType = (osmd?: OpenSheetMusicDisplay | null) => void

export type SetRenderOptions = {
  score?: string
}

const rendered = ref(false)

export default defineComponent({
  name: 'music-score',
  props: {
    isSoundEffect: {
      type: Boolean,
      default: false,
    },
    score: {
      type: String,
      default: '',
    },
    showPartNames: {
      type: Boolean,
      default: false,
    },
    opotions: {
      type: Object as PropType<OSMDOptions>,
      default: () => {},
    },
    EngravingRules: {
      type: Object as PropType<{ [P in keyof EngravingRules]?: EngravingRules[P] | undefined }>,
      default: () => {},
    },
    showSection: {
      type: Boolean,
      default: true,
    },
  },
  emits: ['rerender', 'startRender', 'renderError', 'loaddingEnd'],
  setup(props, { emit, expose }) {
    // 获取svg文件
    const getSvgXml = async (url: string) => {
      event.off('section-click', RuntimeUtils.noteClick)
      emit('startRender')
      const svg = await axios.get(url)
      if (container.value) {
        let svgDiv = document.createElement('div')
        svgDiv.innerHTML = svg
        container.value?.appendChild(svgDiv.firstElementChild!) //innerHTML =  svg
        let svgEL = document.querySelector('#osmdSvgPage1')
        const svgContainer = document.getElementById('svgContainer')
        let width: any = svgEL?.getAttribute('width')
        let height: any = svgEL?.getAttribute('height')
        width = isNaN(Number(width)) ? 0 : Number(width)
        height = isNaN(Number(height)) ? 0 : Number(height)
        if (width && height) {
          let ratio = height / width
          let _w: any = svgContainer?.offsetWidth || document.body.clientWidth
          detailState.zoom = _w / width
          svgEL?.setAttribute('width', _w)
          svgEL?.setAttribute('height', _w * ratio + '')
        }
      }
    }
    const getNotePosition = (times: any[]) => {
      for (let i = 0; i < times.length; i++) {
        const item = times[i]

        if (item?.svgElelent?.bbox) {
          item.svgElelent.bbox.x *= detailState.zoom
          item.svgElelent.bbox.y *= detailState.zoom
          item.svgElelent.bbox.w *= detailState.zoom
          item.svgElelent.bbox.h *= detailState.zoom
        }
        if (item.noteElement?.sourceMeasure?.verticalMeasureList?.[0]?.boundingBox) {
          item.noteElement.sourceMeasure.verticalMeasureList[0].boundingBox.absolutePosition.x *= detailState.zoom
          item.noteElement.sourceMeasure.verticalMeasureList[0].boundingBox.absolutePosition.y *= detailState.zoom
          item.noteElement.sourceMeasure.verticalMeasureList[0].boundingBox.size.width *= detailState.zoom
          item.noteElement.sourceMeasure.verticalMeasureList[0].boundingBox.size.height *= detailState.zoom
        }
        if (item.noteElement?.sourceMeasure?.verticalMeasureList?.[0]?.stave) {
          item.noteElement.sourceMeasure.verticalMeasureList[0].stave.x *= detailState.zoom
          item.noteElement.sourceMeasure.verticalMeasureList[0].stave.y *= detailState.zoom
          item.noteElement.sourceMeasure.verticalMeasureList[0].stave.width *= detailState.zoom
          item.noteElement.sourceMeasure.verticalMeasureList[0].stave.height *= detailState.zoom
          item.noteElement.sourceMeasure.verticalMeasureList[0].stave.start_x *= detailState.zoom
          item.noteElement.sourceMeasure.verticalMeasureList[0].stave.end_x *= detailState.zoom
        }
        if (item?.cursorBox?.move) {
          // console.log("🚀 ~ item.cursorBox.x", item.cursorBox.x * detailState.zoom, item?.svgElelent?.bbox?.x)
          // item.cursorBox.x = item?.svgElelent?.bbox?.x ? formatZoom(item.svgElelent.bbox.x) : item.cursorBox.x * detailState.zoom
          item.cursorBox.x *= detailState.zoom
          item.cursorBox.y = item.cursorBox.y * detailState.zoom + 10
          item.cursorBox.w *= detailState.zoom
          item.cursorBox.h *= detailState.zoom
        }
      }
      return times
    }
    // 获取json数据
    const getMusicJson = async (url: string) => {
      const res = await axios.get(url)
      SettingState.sett.scoreSize = res?.osmd?.scoreSize || 'middle'
      if (res && Array.isArray(res.times)) {
        detailState.times = getNotePosition(res.times) // res.times
        if (detailState.times?.[0]?.cursorBox?.move) {
          // 初始化cursor
          res.osmd.cursor = new Cursor({ ...detailState.times?.[0]?.cursorBox })
          // console.log("🚀 ~ res.osmd.cursor", res.osmd.cursor)
          res.osmd.cursor.img.id = 'cursorImg-0'
          container.value?.appendChild(res.osmd.cursor.img)
        }
        detailState.renderType = 'cache'
        emit('rerender', res.osmd)
        runtime.isFirstPlay = false
        event.on('section-click', RuntimeUtils.noteClick)
      }
    }
    const { EngravingRules, opotions, showPartNames, score } = toRefs(props)
    const container: Ref<HTMLDivElement | undefined> = ref()
    let osmd: Ref<OpenSheetMusicDisplay | undefined> = ref()

    const setOsdm = () => {
      event.off('section-click', RuntimeUtils.noteClick)
      emit('startRender')
      osmd.value = useOsmd(
        container,
        { ...opotions.value, drawPartNames: showPartNames.value },
        EngravingRules.value
      ).value
      if (osmd.value) {
        useEngravingRules(osmd.value, EngravingRules.value)
        runtime.isFirstPlay = false
        event.on('section-click', RuntimeUtils.noteClick)
      }
    }
    const renderData = ref()
    // 直接读取渲染数据
    const productJsonAndSvg = async (renderData: any) => {
      await getSvgXml(renderData.svg)
      getMusicJson(renderData.json)
    }

    onMounted(async () => {
      if (rendered.value) return
      setOsdm()
      // 暂时不使用缓存
      // if (!musicInfo.musicSvg || props.isSoundEffect) {
      //   return
      // }
      // if (SettingState.sett.type === 'staff') {
      //   renderData.value = musicInfo.musicSvg?.staff
      // } else {
      //   //是否固定调
      //   renderData.value = SettingState.sett.keySignature ? musicInfo.musicSvg?.fixedTone : musicInfo.musicSvg?.firstTone
      // }
      // // console.log("🚀 ~ renderData:", renderData)
      // if (renderData.value && renderData.value.json) {
      //   productJsonAndSvg(renderData.value)
      // } else {
      //   setOsdm()
      // }
    })

    onUnmounted(() => {
      event.off('section-click', RuntimeUtils.noteClick)
    })

    watch(
      [score, osmd],
      async () => {
        if (osmd && osmd.value && score.value) {
          try {
            emit('startRender')
            await useOsmdLoader(osmd.value, score.value)
            emit('rerender', osmd.value)
            event.emit('loaded')
            resetFormate()
          } catch (error) {
            console.error(error)
            emit('renderError')
          }
        }
      },
      { immediate: true }
    )

    const resetFormate = () => {
      // const svg = container.value?.querySelector("svg");
			// if (!svg) return;
			// console.log("🚀 ~ svg:", svg)
			// const svgBBox = svg.getBBox();
      // if (svgBBox.y < 0) {
      //   svg.setAttribute('height', Number(svg.getAttribute('height')) - svgBBox.y + '')
      // }
      const stafflines: SVGAElement[] = Array.from((container.value as HTMLElement).querySelectorAll(".staffline"));
      const musicalDistance = 28; // 音阶与第一条线谱的间距，默认设置为28
			for (let i = 0, len = stafflines.length; i < len; i++) {
				const staffline = stafflines[i];
				const stafflineBox = staffline.getBBox();
				const stafflineCenter = stafflineBox.y + stafflineBox.height / 2;
				const paths: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure > .vf-stave path"));
				// 获取第一个线谱的y轴坐标
				const firstLinePathY = paths[0]?.getBBox().y || 0

        let vftexts = Array.from(staffline.querySelectorAll(".vf-text > text")).filter((n: any) => n.getBBox().y < stafflineCenter);
				// 修改音阶和线谱的间距
				const clefList = ['C', 'G', 'D', 'A', 'E', 'B', 'F#', 'C#', 'G#', 'F', 'Bb', 'Eb', 'Ab', 'Db', 'Gb', 'Cb', 'Fb', 'D#', 'A#', 'E#']
				const btransList = ['Bb', 'Eb', 'Ab', 'Db', 'Gb', 'Cb', 'Fb']
				const jtrsnsList = ['F#', 'C#', 'G#', 'D#', 'A#', 'E#', 'B#']
				vftexts.forEach((label: any) => {
					const labelText = label.textContent as string
					if (clefList.includes(labelText)){
						const _y = Number(label.getAttribute("y"))
						const endY = firstLinePathY ? firstLinePathY - musicalDistance : _y
						label.setAttribute("y", endY)
					}
					if (btransList.includes(labelText)) {
						label.textContent = labelText.replace('b','♭')
					}
					if (jtrsnsList.includes(labelText)) {
						label.textContent = labelText.replace('#','♯')
					}
				});

			}

      setTimeout(() => resetGlobalText())

    }
    const resetGlobalText = () => {
      if (!container.value) return
      // 速度dom
      const vfstavetempo: SVGAElement[] = Array.from(container.value.querySelectorAll('.vf-stavetempo'))
      if (detailState.isDaYaCategory) {
        vfstavetempo.forEach((child: SVGAElement, i: number) => {
          child.style.display = 'none'
        })
      }
    }
    /**
     * 重新渲染曲谱方法
     * @param {SetRenderOptions} options
     */
    const setRender = async ({ score: s }: SetRenderOptions = {}) => {
      const renderScore = s || score.value
      // console.log(renderScore)
      // Toast('加载中，请稍后...')
      setTimeout(async () => {
        if (osmd && osmd.value && renderScore) {
          await osmd.value.clear()
          setOsdm()
          try {
            detailState.section = []
            detailState.sectionStatus = false
            await useOsmdLoader(osmd.value, renderScore)
            emit('rerender', osmd.value)
            event.emit('loaded')
            resetFormate()
          } catch (error) {
            console.error(error)
            emit('renderError')
          }
        }
      }, 100)
    }

    const reRender = async () => {
      if (detailState.renderType == 'native') {
        osmd.value?.render()
        detailState.times = getAllNodes(osmd.value)
      } else {
        if (container.value) {
          container.value.innerHTML = ''
        }
        productJsonAndSvg(renderData.value)
      }
    }

    expose({
      setRender,
      reRender,
    })

    return () => {
      return (
        <div id="svgContainer" class={styles.container} style={{ position: 'relative' }}>
          <div ref={container}></div>
          {/* 小节覆盖层 */}
          {props.showSection && (
            <SectionWrap
              style={{
                position: 'absolute',
                width: '100%',
                height: '100%',
                zIndex: 1,
                top: 0,
                left: 0,
              }}
            />
          )}
        </div>
      )
    }
  },
})
