import { defineComponent, nextTick, onMounted, onUnmounted, reactive, ref, watch } from "vue";
import ABCJS, { AbcElem, AbcVisualParams, ClickListenerAnalysis, ClickListenerDrag, NoteTimingEvent, SynthObjectController } from "abcjs";
import { api_musicSheetCreationWav2mp3, api_musicSheetCreationSaveMusic, api_subjectList, api_musicSheetCreationUpdate } from "../../api";
import { NButton, NForm, NFormItem, NIcon, NModal, NProgress, NSelect, NSpace, useMessage } from "naive-ui";
import styles from "./index.module.less";
import { Close } from "@vicons/ionicons5";
import { SelectMixedOption } from "naive-ui/es/select/src/interface";
import { api_uploadFile } from "/src/utils/uploadFile";
import { bufferToWave } from "/src/helpers/parseABC";
import { decodeUrl, downloadFile } from "/src/utils";
import { renderMeasures } from "../../home/runtime";
import cleanDeep from "clean-deep";

export default defineComponent({
  name: "UploadToResources",
  props: {
    show: {
      type: Boolean,
      default: false,
    },
    item: {
      type: Object,
      default: () => ({}),
    },
  },
  emits: ["update:show", "success"],
  setup(props, { emit }) {
    const message = useMessage();
    const model = reactive({
      subjects: [] as SelectMixedOption[],
      saveLoading: false,
      saveProgress: 0,
      productOpen: false,
      productIfameSrc: "",
    });
    const froms = reactive({
      subjectId: null,
      isPublic: 0,
      mp3: "",
      musicImg: "",
      musicSvg: "",
      musicJianSvg: "",
    });
    const getSubjects = async () => {
      const { data } = await api_subjectList();
      model.subjects = data.map((item: any) => {
        return {
          label: item.name,
          value: item.id,
        };
      });
    };

    const handleProductResult = (res: MessageEvent) => {
      const data = res.data;
      if (data?.api === "webApi_renderSvg") {
        let imgs: any = [];
        try {
          imgs = JSON.parse(data.product);
        } catch (error) {
          console.log("🚀 ~ error:", error);
        }
        imgs = imgs.filter((item: any) => item.base64);
        if (imgs.length === 3) {
          handleUploadImg(imgs);
        }
        console.log("🚀 ~ 上传之前", [...imgs]);
      }
    };
    const handleUploadImg = async (imgs: any[]) => {
      if (!props.show) return;
      for (let i = 0; i < imgs.length; i++) {
        const fileName = `${Date.now()}p${i}.png`;
        const file = dataURLtoFile(imgs[i].base64, fileName);
        imgs[i].url = await api_uploadFile(file, fileName, () => {});
        model.saveProgress = (i + 1) * 20;
      }
      froms.musicImg = imgs[0]?.url || "";
      froms.musicSvg = imgs[1]?.url || "";
      froms.musicJianSvg = imgs[2]?.url || "";
      model.productOpen = false;
      imgs = [];
      if (!props.show) return;
      handleSubmit();
    };
    /** base64转file */
    const dataURLtoFile = (dataurl: string, filename: string) => {
      let arr = dataurl.split(",") || [],
        mime = arr[0].match(/:(.*?);/)?.[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new File([u8arr], filename, { type: mime });
    };
    onMounted(() => {
      getSubjects();
      window.addEventListener("message", handleProductResult);
    });
    onUnmounted(() => {
      window.removeEventListener("message", handleProductResult);
    });
    watch(
      () => props.item,
      () => {
        // console.log(props.item, model.subjects);
        const subjectId = model.subjects.length > 0 ? model.subjects[0].value : null;
        froms.subjectId = props.item.subjectId ?? subjectId;
      }
    );

    const createMusic = async () => {
      await api_musicSheetCreationSaveMusic({
        musicSheetCreationId: props.item.id,
        musicSheetName: props.item.name || "曲谱名称",
        musicSheetCategoriesId: "",
        audioType: "MP3",
        mp3Type: "MP3",
        xmlFileUrl: props.item.xml,
        musicSubject: froms.subjectId,
        showFingering: 1,
        canEvaluate: 1,
        notation: 1,
        playSpeed: props.item?.visualObj?.metaText?.tempo?.bpm || "",
        background: [
          {
            audioFileUrl: froms.mp3,
            track: "P1",
          },
        ],
        musicImg: froms.musicImg,
        musicSvg: froms.musicSvg,
        musicJianSvg: froms.musicJianSvg,
        extConfigJson: "",
      });
    };
    const wav2mp3 = async () => {
      try {
        const { data } = await api_musicSheetCreationWav2mp3(props.item.filePath);
        froms.mp3 = data;
      } catch (error) {
        message.error("wav转mp3失败");
        handleClose();
      }
    };

    const handleClose = () => {
      model.saveLoading = false;
      model.saveProgress = 0;
    };

    /** 自动生成图片 */
    const handleAutoProduct = async () => {
      model.saveProgress = 0;
      const xml = props.item.xml;
      const res = await fetch(xml);
      if (res.status > 299 || res.status < 200) {
        message.error("xml文件不存在");
        handleClose();
        return;
      }
      const origin = /(localhost|192)/.test(location.host) ? "https://test.lexiaoya.cn" : location.origin;
      model.productIfameSrc = `${origin}/instrument/#/product-img?xmlUrl=${xml}&productXmlImg=1`;
      model.productOpen = true;
      setTimeout(() => {
        model.saveProgress = 10;
      }, 800);
    };

    // 生成wav
    const productWav = async (isUrl = true) => {
      return new Promise((resolve) => {
        const subjectCode = props.item.subjectCode || "acoustic_grand_piano";
        const _instruments = ABCJS.synth.instrumentIndexToName.indexOf(subjectCode);
        const program = _instruments > -1 ? _instruments : 0;
        const midiBuffer = new ABCJS.synth.CreateSynth();
        midiBuffer
          .init({
            visualObj: props.item.visualObj,
            options: {
              program,
              soundFontUrl: "https://oss.dayaedu.com/musicSheet/",
              // soundFontUrl: "https://paulrosen.github.io/midi-js-soundfonts/FluidR3_GM/", // 默认 FluidR3_GM
              // soundFontUrl: "https://paulrosen.github.io/midi-js-soundfonts/MusyngKite/", // Musyng Kite
            },
          })
          .then(() => {
            midiBuffer.prime().then(async () => {
              if (isUrl) {
                downloadFile(midiBuffer.download(), (props.item.name || "曲谱") + ".wav");
              } else {
                const blob = bufferToWave((midiBuffer as any).getAudioBuffer());
                const fileName = +new Date() + Math.ceil(Math.random() * 1000);
                const wavurl = await api_uploadFile(blob, fileName + ".wav");
                resolve(wavurl);
              }
            });
          });
      });
    };

    const fromRef = ref();
    const handleUpload = () => {
      fromRef.value.validate(async (err: any) => {
        if (err) {
          return;
        }
        if (!props.item.xml) {
          message.error("没有生成xml文件");
          handleClose();
          return;
        }

        // if (!props.item.filePath) {
        //   message.error("没有生成wav文件");
        //   handleClose();
        //   return;
        // }
        model.saveLoading = true;
        handleAutoProduct();
      });
    };
    const handleSubmit = async () => {
      // 判断是否有wav文件，如果没有则生成保存
      // if (!props.item.filePath) {
      const url = await productWav(false);
      props.item.filePath = url;
      // }

      await api_musicSheetCreationUpdate({
        id: props.item.id,
        subjectId: froms.subjectId,
        // filePath: props.item.filePath,
      });

      await wav2mp3();
      model.saveProgress = 70;
      if (!props.show) return;
      await createMusic();
      model.saveProgress = 100;
      emit("success");
      if (!props.show) return;
      message.success("上传成功");
      setTimeout(() => {
        model.saveLoading = false;
        emit("update:show", false);
      }, 300);
    };
    return () => (
      <>
        <NModal
          autoFocus={false}
          show={props.show}
          unstableShowMask={false}
          maskClosable={false}
          onUpdate:show={(val) => {
            model.productOpen = false;
            emit("update:show", val);
          }}
        >
          <div class={styles.setbox}>
            <div class={styles.head}>
              <div>上传到我的资源</div>
              <NButton
                class={styles.close}
                quaternary
                circle
                size="small"
                onClick={() => {
                  model.productOpen = false;
                  emit("update:show", false);
                }}
              >
                <NIcon component={Close} size={18} />
              </NButton>
            </div>
            <NForm ref={fromRef} model={froms} class={styles.form} labelPlacement="left" showRequireMark={false}>
              <NFormItem
                label="可用声部"
                path="subjectId"
                rule={{
                  required: true,
                  type: "number",
                  message: "请选择素材可用乐器",
                  trigger: "change",
                }}
              >
                <NSelect to="body" disabled={model.saveLoading} placeholder="请选择素材可用乐器" options={model.subjects} v-model:value={froms.subjectId}></NSelect>
              </NFormItem>
              {/* <NFormItem label="是否公开">
								<NSpace class={styles.checkbox} wrapItem={false}>
									<NButton
										secondary
										bordered={false}
										type={froms.isPublic === 1 ? "primary" : "default"}
										onClick={() => (froms.isPublic = 1)}
									>
										公开
									</NButton>
									<NButton
										secondary
										bordered={false}
										type={froms.isPublic === 0 ? "primary" : "default"}
										onClick={() => (froms.isPublic = 0)}
									>
										不公开
									</NButton>
								</NSpace>
							</NFormItem> */}
              <NFormItem label="上传进度" style={{ display: model.saveLoading ? "" : "none" }}>
                <div style={{ display: "flex", width: "100%", height: "46px", alignItems: "center" }}>
                  <NProgress percentage={model.saveProgress} />
                </div>
              </NFormItem>
            </NForm>
            <div class={styles.btns}>
              <NButton
                onClick={() => {
                  model.productOpen = false;
                  handleClose();
                  emit("update:show", false);
                }}
              >
                取消
              </NButton>
              <NButton type="primary" loading={model.saveLoading} onClick={() => handleUpload()}>
                确定
              </NButton>
            </div>
          </div>
        </NModal>
        {model.productOpen && <iframe class={styles.productIframe} src={model.productIfameSrc}></iframe>}
      </>
    );
  },
});
