import type { InjectionKey, ShallowRef } from "vue";
import { getPatientAll } from "@/api/inpatient/patient";
import * as archiveApi from "@/api/archive/archive-api";
import {
  getPatientArchives,
  PatientArchive,
  submitTask,
} from "@/api/archive/archive-api";
import XEUtils from "xe-utils";
import { useWebSocket } from "@vueuse/core";
import { useUserStore } from "@/pinia/user-store";
import { useDialog } from "@/components/cy/CyDialog/index";
import ArchiveUpload from "./ArchiveUpload.vue";
import ArchiveAllLog from "@/views/archive/ArchiveAllLog.vue";
import { ElButton, ElNotification } from "element-plus";

type PatInfo = {
  inpatientNo: string;
  admissTimes: number;
  admissDate: string;
  disDate: string;
};

type Socket = {
  [key: string]: (value: any) => void;
};

const useSocket = (cb: Socket) => {
  const socketUrl = ref();

  const { data, open } = useWebSocket(socketUrl, {
    immediate: false,
  });

  watch(
    () => data.value,
    () => {
      try {
        const json = JSON.parse(data.value);
        cb[json.code]?.(json.data);
      } catch (e) {
        console.error(e);
      }
    },
    { immediate: false, deep: true }
  );

  return {
    setUrl(url: string) {
      socketUrl.value = url;
      open();
    },
  };
};

export const useArchive = () => {
  const store = reactive({
    patNo: "",
    times: 0,
    patInfo: {} as PatInfo,
    treeList: [] as PatientArchive[],
    pdfUrl: "",
    asideValue: "archive",
    footerValue: "footer",
    footerVisible: true,
    logMessage: [],
    footerRef: null as ShallowRef<{ scroll: (val: boolean) => void }>,
    mainIframe: null as HTMLIFrameElement,
    mainTabsValue: "pdf",
  });

  function notification(message) {
    const MessageNode = (
      <div>
        <div>{message}</div>
        <div>
          <ElButton
            text
            type="danger"
            onClick={() => ElNotification.closeAll()}
          >
            取消
          </ElButton>
          <ElButton
            text
            type="primary"
            onClick={() => {
              ElNotification.closeAll();
              mutation.getData();
            }}
          >
            更新目录
          </ElButton>
        </div>
      </div>
    );

    ElNotification.success({
      title: "文件有变化",
      position: "bottom-right",
      duration: 0,
      message: MessageNode,
    });
  }

  const socket = useSocket({
    log: data => {
      store.logMessage.push(JSON.parse(data));
      store.footerVisible = true;
      mutation.logScroll(false);
    },
    change: data => {
      if (useUserStore().userInfo.code !== data.code) {
        notification(data.message);
      }
    },
    taskComplete: () => {
      mutation.getData();
    },
  });

  const mutation = {
    async getData() {
      store.treeList = await getPatientArchives(store.patNo, store.times);
    },
    async setPatInfo(patInfo: string) {
      const split = patInfo.split("_");
      store.patNo = split[0];
      store.times = XEUtils.toNumber(split[1]);
      socket.setUrl(
        `${import.meta.env.VITE_SOCKET_URL}archive-${store.patNo}-${store.times}-${useUserStore().userInfo.code}`
      );
      const res = await getPatientAll(store.patNo, store.times);
      store.patInfo = res as any;
      this.getData();
    },
    setPdfUrl(url: string) {
      store.mainIframe?.contentWindow?.scrollTo(0, 0);
      store.pdfUrl = "/thyyemrpdfserver" + url;
    },
    async sort() {
      function forEach(
        data: PatientArchive[],
        fatherLevel: PatientArchive | null = null
      ) {
        data.forEach((item, index) => {
          if (fatherLevel) {
            item.parentId = fatherLevel.id;
          } else {
            item.parentId = null;
          }

          item.sort = index;
          if (item.children !== null && item.children.length > 0) {
            forEach(item.children, item);
          }
        });
      }

      forEach(store.treeList);

      const tmp = {
        patNo: store.patInfo.inpatientNo,
        times: store.patInfo.admissTimes,
        archives: mutation.toTreeArray(),
      };
      await archiveApi.sort(tmp);
    },
    toTreeArray(): PatientArchive[] {
      return XEUtils.toTreeArray(XEUtils.cloneDeep(store.treeList), {
        clear: true,
      });
    },
    archiveTask() {
      submitTask([{ patNo: store.patNo, times: store.times }]);
    },
    clearLog() {
      store.logMessage = [];
    },
    async logScroll(top = false) {
      await nextTick();
      store.footerRef?.scroll?.(top);
    },
    async uploadFiles(parent: string) {
      await useDialog(ArchiveUpload, {
        dialogProps: {
          title: "上传文件",
          closeOnClickModal: false,
          showClose: false,
          closeOnPressEscape: false,
        },
        showCancel: false,
        params: {
          patNo: store.patInfo.inpatientNo,
          times: store.patInfo.admissTimes,
          parent,
        },
      });

      await mutation.getData();
    },
    getPatNoAndTimes() {
      return {
        patNo: store.patInfo.inpatientNo,
        times: store.patInfo.admissTimes,
      };
    },
    getAllLog() {
      useDialog(ArchiveAllLog, {
        dialogProps: { title: "全部日志", fullscreen: true },
        showCancel: false,
        params: {
          ...mutation.getPatNoAndTimes(),
        },
      }).catch(XEUtils.noop);
    },
  };

  return { store, mutation };
};

type UseArchive = ReturnType<typeof useArchive>;

export const useArchiveKey: InjectionKey<UseArchive> = Symbol("useArchiveKey");
