<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
  name: "ModelTrain",
});
</script>

<script setup lang="ts">
import streamSaver from "streamsaver";
import { downloadFile } from "@/utils/download/index.ts";

import _ from "lodash";
import TrainForm from "@/views/modelTraining/detail/components/Form/Train.vue";
import ModuleCard from "@/views/dataManage/index/components/Card/ModuleCard.vue";
import Icon from "@/components/Module/Icon/index.vue";
import { FormInstance, Button, Space, message, Modal, Tag } from "ant-design-vue";
import { onMounted, onUnmounted, ref, unref, watch, h, nextTick, computed } from "vue";
import { useMain } from "@/views/modelTraining/detail/services/index.ts";
import { router } from "@/router/index.ts";

const { trainDetailServices } = useMain();

// 日志定时器
let logsTimeCount: NodeJS.Timeout | undefined = undefined;
let logsReader: null | ReadableStreamDefaultReader = null;

// 关闭日志定时器
const cleanLogsTimecount = () => {
  if (logsTimeCount) {
    clearInterval(logsTimeCount);
    logsTimeCount = undefined;
  }
};

// 获取日志
const startLogsTimeCount = async (taskId: string) => {
  cleanLogsTimecount();
  logsTimeCount = setInterval(async () => {
    const res = await trainDetailServices.task.api.getStatus(taskId);
    if (res?.code != 200) {
      return;
    }
    const { taskStatus } = trainDetailServices.task.state;
    const ends = ["finished", "failed", "stopped"];
    if (taskStatus.value?.status && ends.includes(taskStatus.value?.status)) {
      onLogCleanUp();
      trainDetailServices.task.api.interruptLogs();
      return;
    }
    // 获取读取情况
    // const { done, chunks } = await getLogsFromReader();
    const done = await getLogsFromReader();
    // trainDetailServices.task.state.logs.value = chunks;
    if (done) {
      onLogCleanUp();
      trainDetailServices.task.api.interruptLogs();
    }
  }, 2000);
};

// 获取日志
const getLogsFromReader = async () => {
  // let params = {
  //   done: false,
  //   chunks: JSON.parse(JSON.stringify(trainDetailServices.task.state.logs.value)),
  // };
  const decoder = new TextDecoder("utf-8");
  // if (!logsReader) return params;
  if (!logsReader) return false;
  // @ts-ignore
  const { done, value } = await logsReader?.read();
  if (!done) {
    const chunk = decoder.decode(value, { stream: false });
    const chunks = chunk.split("\n");
    // params.chunks.push(chunks);
    trainDetailServices.task.state.logs.value.push(...chunks);
  }
  return done;
  // return params;
};

// 校验任务状态
const checktaskStatus = async (taskId: string) => {
  const { taskStatus } = trainDetailServices.task.state;
  const ends = ["finished", "failed", "stopped"];
  if (taskStatus.value?.status && ends.includes(taskStatus.value?.status)) {
    let status;
    logsTimeCount = setInterval(async () => {
      status = await getLogsFromReader();
      if (status) {
        onLogCleanUp();
        trainDetailServices.task.api.interruptLogs();
      }
    }, 100);
    // // 一次性获取所有日志

    // 清除
    // onLogCleanUp();
  } else {
    // 读取日志
    startLogsTimeCount(taskId);
  }
};

// 清除日志相关的定时器与流失阅读器
const onLogCleanUp = () => {
  cleanLogsTimecount();
  onLogReadDestory();
};

// 获取日志reader
const getLogsReader = async (taskId: string) => {
  const res = await trainDetailServices.task.api.getLogs(taskId);
  if (res?.status == 200) {
    logsReader = res?.body?.getReader();
  }
};

// 销毁日志reader
const onLogReadDestory = async () => {
  if (logsReader) {
    try {
      await logsReader.cancel();
      await logsReader.releaseLock();
    } catch (error: unknown) {
      console.warn("释放锁时出错:", error);
    } finally {
      logsReader = null;
    }
  }
};

const init = async () => {
  trainDetailServices.common.api.getQuery();
  trainDetailServices.options.api.getTestDataset();
  trainDetailServices.options.api.getTrainDataset();
  trainDetailServices.options.api.getModels();
  const taskId = trainDetailServices.common.state.taskId.value;
  trainDetailServices.task.api.getExportModels(taskId);
  trainDetailServices.task.api.getTaskParams(taskId);
  await Promise.all([trainDetailServices.task.api.getStatus(taskId), getLogsReader(taskId)]);
  checktaskStatus(taskId);
};

const taskStatus = trainDetailServices.task.state.taskStatus;

const logContainer = ref();

const onScrollBottom = () => {
  const dom = logContainer.value;
  if (dom) {
    nextTick(() => {
      dom.scrollTop = dom.scrollHeight;
    });
  }
};

watch(
  () => trainDetailServices.task.state.logs,
  () => {
    onScrollBottom();
  },
  { deep: true },
);

const statusMap: Record<string, any> = {
  running: "训练中",
  finished: "训练完成",
  failed: "训练失败",
  stopped: "训练中止",
};

const statusColorMap: Record<string, any> = {
  running: "blue",
  finished: "green",
  failed: "red",
  stopped: "orange",
};

// 导出格式化
const showExportResultList = computed(() => {
  const options = trainDetailServices.task.state.validExportModels.value;
  const validOptions = options
    .filter((item: Record<string, any>) => {
      return item.completed;
    })
    .map((item: Record<string, any>) => {
      return {
        label: item.type.toUpperCase(),
        value: item.type,
        color: item.completed ? "green" : "red",
      };
    });
  return validOptions;
  // const options = trainDetailServices.options.state.exportOptions;
  // const exportList = trainDetailServices.task.state.taskParams.value?.export_formats || [];
  // const status = taskStatus?.value.status;
  // const useOptions = options
  //   .filter((item) => {
  //     return exportList.includes(item.value);
  //   })
  //   .map((item) => {
  //     return {
  //       label: `${item.label}`,
  //       value: item.value,
  //       color: status == "finished" ? "green" : "red",
  //     };
  //   });
  // return useOptions;
});

const onDownload = (info: Record<string, any>) => {
  console.log("onDownload", info);
};

// 操作区点击
const onMenuSelect = (item: Record<string, any>) => {
  console.log("item", item);
  const eventMap: Record<string, (...args: any[]) => any> = {
    // export: exportData,
    // train: onTrain,
  };
  if (eventMap[item.key]) {
    eventMap[item.key]();
  }
};

const createInterruptProps = (taskId: string) => {
  return {
    centered: true,
    title: h("div", { style: "font-size: 16px" }, "停止任务"),
    icon: h("span"),
    content: h("div", { style: "font-size: 16px; margin-bottom: 20px" }, "确定要停止当前任务吗？"),
    okText: "确定",
    cancelText: "取消",
    onOk: async () => {
      const res = await trainDetailServices.task.api.onInterrupt(taskId);
      if (res?.code == 200) {
        await trainDetailServices.task.api.getStatus(taskId);
      }
      return res;
      // return res;
    },
    onCancel() {},
  };
};

// 中断
const onInterrupt = () => {
  const taskId = trainDetailServices.common.state.taskId.value;
  const modalProps = createInterruptProps(taskId);
  Modal.confirm(modalProps);
};

const exportLoading = ref(false);

const onExportV2 = async (type: string) => {
  const taskId = trainDetailServices.common.state.taskId.value;
  const url = `/api/train/${taskId}/export/${type}`;
  // 创建a标签
  const modelId = trainDetailServices.task.state.taskParams.value.model_id;
  const targetModel = trainDetailServices.options.state.models.value.find(
    (item: Record<string, any>) => {
      return item.id === modelId;
    },
  );
  const modelName = (targetModel && targetModel?.name) || modelId;
  const fileName = `${modelName}.${type.toLowerCase()}`;
  console.log("fileName", fileName);
  const a = document.createElement("a");
  a.href = url;
  a.download = fileName;
  a.click();
  a.remove();
};

const onExport = async (type: string) => {
  const url = "";
  exportLoading.value = true;

  const modelId = trainDetailServices.task.state.taskParams.value.model_id;
  const targetModel = trainDetailServices.options.state.models.value.find(
    (item: Record<string, any>) => {
      return item.id === modelId;
    },
  );
  const modelName = (targetModel && targetModel?.name) || modelId;
  const fileName = `${modelName}.${type.toLowerCase()}`;
  console.log("fileName", fileName);
  const taskId = trainDetailServices.common.state.taskId.value;

  const fileStream = streamSaver.createWriteStream(fileName);

  await trainDetailServices.task.api.onModelExport(taskId, type).then((res) => {
    exportLoading.value = false;
    const readableStream = res.body;
    if (window.WritableStream && readableStream.pipeTo) {
      return readableStream.pipeTo(fileStream).then(() => console.log("完成写入"));
    }

    // 【步骤3】监听文件内容是否读取完整，读取完就执行“保存并关闭文件”的操作。
    window.writer = fileStream.getWriter();
    const reader = res.body.getReader();
    const pump = () =>
      reader.read().then((res) => (res.done ? writer.close() : writer.write(res.value).then(pump)));
    pump();
  });

  // const readableStream = res.body
  // if (window.WritableStream && readableStream.pipeTo) {
  //   await readableStream.pipeTo(fileSteam)
  //     // .then(() => console.log('完成写入'))
  // }

  // console.log("res", res);
  // const blob = await res.blob();
  // console.log("res", res, blob);
  // const hrefUrl = window.URL.createObjectURL(blob);

  // downloadFile(hrefUrl, `${modelName}.${type}`);
  // exportLoading.value = false;
  // return res;
};

const onBack = () => {
  router.go(-1);
};

onMounted(() => {
  init();
  onScrollBottom();
});

onUnmounted(() => {
  trainDetailServices.task.api.interruptLogs();
  onLogCleanUp();
});

const prefix = "model-train-page";
</script>

<template>
  <div :class="prefix">
    <div :class="`${prefix}-wrapper--top`">
      <Button class="custom-btn primary-text" @click="onBack">
        <template #icon>
          <Icon name="back" />
        </template>
        返回
      </Button>
    </div>
    <div :class="`${prefix}-container`">
      <div :class="`${prefix}-form`">
        <ModuleCard title="模型调优">
          <template #head-extra>
            <Space :size="20">
              <Button
                v-if="['running'].includes(taskStatus?.status)"
                type="primary"
                class="custom-btn"
                @click="onInterrupt"
                :loading="trainDetailServices.task.requestMap.interruptRequest.loading.value"
              >
                <template #icon>
                  <Icon name="interruptLine" />
                </template>
                中断任务
              </Button>
              <Tag v-else :color="statusColorMap[taskStatus?.status]">{{
                statusMap[taskStatus?.status]
              }}</Tag>
              <template v-if="['finished'].includes(taskStatus?.status)">
                <Button
                  @click="onExportV2(item.value)"
                  type="primary"
                  v-for="item in showExportResultList"
                  :loading="exportLoading"
                  >下载{{ item.label }}</Button
                >
                <!-- <Tag :color="item.color" v-for="item in showExportResultList">
                  {{ item.label }}
                </Tag> -->
              </template>
              <!--  -->
            </Space>
          </template>
          <div>
            <TrainForm
              :formData="trainDetailServices.task.state.taskParams.value"
              :serviers="trainDetailServices"
            />
            <!-- <div style="margin-top: 40px">已经导出到/home/xjhe/xjhe/code/MMRadarCode/目录下</div> -->
          </div>
        </ModuleCard>
      </div>
      <div :class="`${prefix}-log`">
        <div :class="`${prefix}-log-title`">训练日志</div>
        <div :class="`${prefix}-log-content`" ref="logContainer">
          <p
            :class="`${prefix}-log-desc`"
            v-for="item in trainDetailServices.task.state.logs.value"
          >
            {{ item }}
          </p>
        </div>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
$prefix: "model-train-page";

.#{$prefix} {
  width: 100%;
  height: 100%;
  padding: 20px 26px;
  box-sizing: border-box;
  &-wrapper {
    &--top {
      height: 32px;
      margin-bottom: 13px;
    }
  }
  &-container {
    width: 100%;
    height: calc(100% - 45px);
    background: rgba(255, 255, 255, 0.6);
    border: 1px solid rgba(231, 239, 251, 0.5);
    border-radius: 10px;
    // background-color: #fff;
    border-radius: 12px;
    padding: 24px;
    display: flex;
    align-items: start;
    justify-content: start;
    gap: 20px;
  }
  &-form {
    flex: 1;
    height: 100%;
    overflow: auto;
    :deep(.module-card) {
      padding: 0;
    }
  }
  &-log {
    flex: 1;
    display: flex;
    align-items: start;
    justify-content: start;
    flex-direction: column;
    height: 100%;
    &-title {
      width: 100%;
      margin-bottom: 14px;
    }
    &-content {
      border-radius: 12px;
      width: 100%;
      flex: 1;
      overflow: auto;
      display: flex;
      align-items: start;
      justify-content: start;
      flex-direction: column;
      padding: 20px;
      background-color: #dcdcdc;
    }
    &-desc {
      font-family:
        Source Han Sans,
        Source Han Sans;
      font-weight: 350;
      font-size: 14px;
      color: #4b5563;
      line-height: 20px;
      text-align: left;
      font-style: normal;
      text-transform: none;
    }
  }
  .custom-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    border-radius: 4px 4px 4px 4px;
    padding: 8px 16px;
  }
  .grey-btn {
    background: #aab5c4;
  }
  .primary-text {
    color: #0256ff;
  }
}
</style>
