<script>
import BaseTable from "../../components/BaseTable.vue";
const { remote, ipcRenderer } = require("electron");
const { getDTFSetting, setDTFSetting } = require("@/server/utils/store");
const { Menu } = remote;
const path = require("path");
const { pathMap } = require("@/config/index.js");
import DTFhead from "./components/head.vue";
import debounce from "lodash/debounce";

import {
  submitDownload,
  getDownloadStatus,
  onDownloadStatusChange,
  submitTypesettingDownload,
  getTypesettingDownloadStatus,
  onTypesettingStatusChange
} from "@/utils/download-api";
import { startLoading, endLoading } from "@/utils/axios";

export default {
  name: "design-dtf",
  components: { BaseTable, DTFhead },
  props: {
    user: {
      default: () => ({
        avatar: "",
        factory: {}
      }),
      type: Object
    },
    factoryType: { type: String, default: "CN" }
  },
  data() {
    return {
      dialogVisible: false,
      selectionList: [],
      searchForm: {},
      radio: "",
      templateBatchArrangeNum: "",
      templateId: "",
      isDownloading: false,
      TypeDownloading: false,
      dtfSetting: getDTFSetting(),
      removeStatusListener: null,
      composingTasks: [],
      composingPollTimer: null,

      pageInfo: {
        currentPage: 1,
        pageSize: 50,
        total: 2
      },
      tableList: [],
      tableConfig: [
        {
          prop: "batchArrangeNum",
          label: "批次号",
          width: 140,
          slotName: "batchArrangeNum"
        },
        {
          prop: "operationNum",
          label: "操作单数量",
          width: 100
        },
        {
          prop: "materialNum",
          label: "素材数量",
          width: 100
        },
        {
          prop: "craftType",
          label: "工艺类型",
          width: 100
        },
        {
          prop: "standardDesignImage",
          label: "规范素材",
          width: 100,
          render(row) {
            return row.standardDesignImage == 0
              ? "否"
              : row.standardDesignImage == 1
              ? "是"
              : "混合";
          }
        },
        {
          label: "创建时间",
          prop: "createTime"
        },
        {
          label: "排版状态",
          width: 140,
          prop: "layoutStatus",
          slotName: "layoutStatus"
        },
        {
          prop: "failReason",
          label: "失败原因",
          width: 300,
          slotName: "failReason"
        },
        {
          label: "排版参数",
          prop: "composingParam",
          width: 300
        },
        {
          label: "操作",
          width: 260,
          slotName: "operation",
          prop: "operation"
        }
      ],
      layoutStatus: {
        1: { label: "待排版", type: "warning" },
        2: { label: "排版中", type: "info" },
        3: { label: "排版成功", type: "success" },
        4: { label: "排版失败", type: "danger" },
        5: { label: "部分成功", type: "success" }
      }
    };
  },
  computed: {},
  async mounted() {
    const savedPage = Number(this.$route.query.page);
    if (savedPage > 0) {
      this.pageInfo.currentPage = savedPage;
    }
    this.loadLocalConfig();
    this.fetchBatchList();
    this.removeStatusListener = onDownloadStatusChange(status => {
      this.handleDownloadStatus("material", status);
    });
    this.removeListener = onTypesettingStatusChange(status => {
      this.handleDownloadStatus("typesetting", status);
    });
    // 初始化同步状态
    await this.syncStatus();
  },
  beforeDestroy() {
    if (this.removeStatusListener) this.removeStatusListener();
    if (this.removeListener) this.removeListener();
    this.stopComposingPoll();
    this.composingTasks.forEach(t => clearTimeout(t.dismissTimer));
    this.downloadFile.cancel?.();
  },
  methods: {
    async loadLocalConfig() {
      try {
        if (!getDTFSetting().downloadDir) {
          ipcRenderer.send("get-install-path");
          ipcRenderer.once("get-install-path-res", (_, defaultPath) => {
            setDTFSetting({ downloadDir: defaultPath });
          });
        }
      } catch (error) {
        console.log(error);
      }
    },

    //定时任务
    async fetchBatchList(value) {
      try {
        let params = {
          currentPage: this.pageInfo.currentPage,
          pageSize: this.pageInfo.pageSize
        };

        if (value) {
          params = { ...params, ...value };
        }

        const res = await this.$api.post(pathMap["productionSoftware"], params);

        if (res.code === 200) {
          this.tableList = res.data.records || [];

          this.pageInfo.total = res.data.total;
        }
      } catch (err) {
        console.error("批次列表拉取失败", err);
      }
    },

    handleSelect(rows) {
      console.log("选中行", rows);
      this.selectionList = rows;
    },
    handleSizeChange(size) {
      this.pageInfo.pageSize = size;
      this.pageInfo.currentPage = 1;
      this.fetchBatchList(this.searchForm);
    },
    handleCurrentChange(page) {
      this.pageInfo.currentPage = page;
      this.fetchBatchList(this.searchForm);
    },

    //右键选择器
    openMenu(e) {
      e.preventDefault();
      const template = [
        {
          label: "全部选择",
          click: () => {
            this.$refs.tableRefs?.toggleAllSelection(true);
          }
        },
        {
          label: "取消选择",
          click: () => this.$refs.tableRefs?.toggleAllSelection(false)
        }
      ];
      const menu = Menu.buildFromTemplate(template);
      menu.popup({ x: e.clientX, y: e.clientY });
    },

    //查看排版文件
    async goFliePage(value, type) {
      console.log(value);

      let { data } = await this.$api.post("/createBatchFolder", {
        basePath: this.dtfSetting.downloadDir,
        downloadDir: value.batchArrangeNum,
        isArray: false
      });
      if (!data) {
        return this.$message.error("下载文件目录未配置或者目录错误");
      }
      if (type == "check") {
        ipcRenderer.send("open-folder-only", data);
      }
    },

    //打开手动排版弹窗
    changeTypesetting(value) {
      if (this.TypeDownloading) {
        this.$message.warning("其他排版下载中，请等待完成后再操作");
        return;
      }
      if (![2].includes(value.layoutStatus)) {
        this.dialogVisible = true;
        this.radio = "";
        this.templateBatchArrangeNum = value.batchArrangeNum;
        this.templateId = value.id;
      }
    },

    //提交手动排版
    async submit() {
      if (!this.radio) {
        return this.$message.error("请选择排版宽度");
      }
      if (this.dtfSetting.widthStrategy == 3 && this.radio == 60) {
        try {
          await this.$confirm(
            "由于排版设置中选择“按更大规格排版”仅适用于40+2，选60时，默认超60的规格不排版",
            "提示",
            { confirmButtonText: "确定", type: "warning" }
          );
        } catch {
          return;
        }
      }

      const taskId = this.templateBatchArrangeNum;
      const templateId = this.templateId;

      startLoading();
      try {
        await this.$api.post(
          pathMap["psReComposingDesignImages"],
          {
            batchArrangeNum: this.templateBatchArrangeNum,
            templateWidth: this.radio
          },
          { skipLoading: true }
        );
      } catch (error) {
        console.warn("排版请求超时:", error.message);
      }
      endLoading();
      this.dialogVisible = false;

      const task = {
        id: taskId,
        batchArrangeNum: taskId,
        templateId: templateId,
        step: "composing",
        progress: "排版处理中，等待完成后自动下载...",
        dismissTimer: null
      };
      this.composingTasks = this.composingTasks.filter(t => t.id !== taskId);
      this.composingTasks.push(task);

      this.ensureComposingPoll();
      this.fetchBatchList(this.searchForm);
    },

    async fetchBatchByNo(batchArrangeNum) {
      try {
        const res = await this.$api.post(
          pathMap["productionSoftware"],
          { currentPage: 1, pageSize: 1, batchArrangeNumber: batchArrangeNum },
          { skipLoading: true }
        );
        const list = res.code === 200 ? res.data.records || [] : [];
        return list[0] || null;
      } catch {
        return null;
      }
    },

    checkTaskStatus(task, batch) {
      if (batch && [3, 5].includes(batch.layoutStatus)) {
        task.step = "downloading";
        task.progress = "排版完成，正在下载素材...";
        this.doComposingDownload(task.id);
      } else if (batch && batch.layoutStatus === 4) {
        task.step = "error";
        task.progress = "排版失败：" + (batch?.failReason || "未知原因");
      } else {
        task.progress = "排版处理中，等待完成后自动下载...";
        this.ensureComposingPoll();
      }
    },

    getTask(taskId) {
      return this.composingTasks.find(t => t.id === taskId);
    },

    setTaskDone(taskId, progress) {
      const task = this.getTask(taskId);
      if (!task) return;
      task.step = "done";
      task.progress = progress;
      task.dismissTimer = setTimeout(() => this.removeTask(taskId), 5000);
    },

    removeTask(taskId) {
      const task = this.getTask(taskId);
      if (task) clearTimeout(task.dismissTimer);
      this.composingTasks = this.composingTasks.filter(t => t.id !== taskId);
      if (!this.composingTasks.some(t => t.step === "composing")) {
        this.stopComposingPoll();
      }
    },

    ensureComposingPoll() {
      if (this.composingPollTimer) return;
      this.composingPollTimer = setInterval(
        () => this.pollComposingStatus(),
        15000
      );
    },

    stopComposingPoll() {
      if (this.composingPollTimer) {
        clearInterval(this.composingPollTimer);
        this.composingPollTimer = null;
      }
    },

    async pollComposingStatus() {
      const polling = this.composingTasks.filter(t => t.step === "composing");
      if (polling.length === 0) {
        this.stopComposingPoll();
        return;
      }
      try {
        for (const task of polling) {
          const batch = await this.fetchBatchByNo(task.batchArrangeNum);
          this.checkTaskStatus(task, batch);
        }
        if (!this.composingTasks.some(t => t.step === "composing")) {
          this.stopComposingPoll();
        }
      } catch (err) {
        console.error("轮询排版状态失败", err);
      }
    },

    async doComposingDownload(taskId) {
      const task = this.getTask(taskId);
      if (!task) return;
      try {
        this.TypeDownloading = true;
        const { data } = await this.$api.post(
          pathMap["podOrderBatchDownload"],
          { id: task.templateId },
          { skipLoading: true }
        );
        await submitTypesettingDownload({
          urlStr: data.data.spUrl,
          targetPath: path.join(
            getDTFSetting().downloadDir,
            `批次号：${task.batchArrangeNum}`,
            "手动排版素材"
          ),
          batchArrangeNum: task.batchArrangeNum
        });
        task.progress = "素材下载中...";
      } catch (error) {
        console.error(error);
        this.TypeDownloading = false;
        if (task) {
          task.step = "error";
          task.progress = "下载失败：" + (error.message || "未知错误");
        }
      }
    },

    //跳转批次详情页
    toDetail(value) {
      this.$router.push({
        name: "dtf-batch-detail",
        params: {
          ...value
        },
        query: { fromPage: this.pageInfo.currentPage }
      });
    },
    downloadFile: debounce(
      function(value) {
        this._downloadFile(value);
      },
      300,
      {
        leading: true,
        trailing: false
      }
    ),
    //下载批次原素材
    async _downloadFile(value) {
      if (this.isDownloading) {
        this.$message.warning("正在下载中，请等待完成后再操作");
        return;
      }
      try {
        this.isDownloading = true;

        const { data } = await this.$api.post(pathMap["listMaterialsByBatch"], {
          batchArrangeNum: value
        });
        const newUrls = data.map(item => ({
          url: item.fileUrl,
          fileName: item.fileName
        }));

        if (newUrls.length === 0) {
          this.$message.warning("该批次暂无素材可下载");
          this.isDownloading = false;
          return;
        }

        const res = await submitDownload({
          urls: newUrls,
          targetPath: path.join(
            this.dtfSetting.downloadDir,
            `批次号：${value}`,
            "原素材"
          ),
          batchArrangeNum: value
        });
        if (res.code !== 200) {
          this.isDownloading = false;
          this.$message.error(res.msg);
        }
      } catch (error) {
        console.error("下载提交失败", error);
        this.$message.error("下载提交失败，请重试");
        // 仅提交失败时释放锁
        this.isDownloading = false;
      }
    },
    /**
     * 状态变更回调
     */
    handleDownloadStatus(type, status) {
      const statusKey =
        type === "material" ? "isDownloading" : "TypeDownloading";
      this[statusKey] = status.isRunning;

      if (!status.isRunning && status.result) {
        const { success, failed } = status.result;
        const { currentBatchNo } = status;

        const task =
          type === "typesetting" &&
          this.composingTasks.find(t => t.batchArrangeNum === currentBatchNo);

        if (task) {
          const msg = failed.length
            ? `下载完成：成功 ${success.length} 个，失败 ${failed.length} 个`
            : `下载完成：成功 ${success.length} 个文件`;
          this.setTaskDone(task.id, msg);
          this.fetchBatchList(this.searchForm);
          return;
        }

        this.$message.success(
          `批次号：${currentBatchNo}，下载完成：成功 ${success.length} 个，失败 ${failed.length} 个`
        );
        if (failed.length > 0) {
          console.warn("下载失败明细：", failed);
        }
      }
    },

    stepActive(task) {
      if (task.step === "composing") return 0;
      if (task.step === "downloading") return 1;
      if (task.step === "done") return 3;
      return task.progress.includes("排版") ? 0 : 1;
    },
    stepStatus(task) {
      if (task.step === "error") return "error";
      if (task.step === "done") return "success";
      return "process";
    },

    /**
     * 同步当前状态
     */
    async syncStatus() {
      try {
        const res = await getDownloadStatus();
        const resTypesetting = await getTypesettingDownloadStatus();
        this.isDownloading = res.data.isRunning;
        this.TypeDownloading = resTypesetting.data.isRunning;
      } catch (err) {
        console.error("同步下载状态失败", err);
      }
    },
    searchFn(value) {
      this.searchForm = value;
      this.pageInfo.currentPage = 1;
      if (value.timeRange?.length) {
        this.searchForm.startTime = value.timeRange[0];
        this.searchForm.endTime = value.timeRange[1];
      } else {
        this.searchForm.startTime = "";
        this.searchForm.endTime = "";
      }
      this.fetchBatchList(this.searchForm);
    }
  }
};
</script>

<template>
  <div class="page" @contextmenu.prevent="openMenu">
    <DTFhead
      :user="user"
      :factoryType="factoryType"
      @search="searchFn"
    ></DTFhead>
    <BaseTable
      v-if="tableList.length"
      ref="tableRefs"
      :table-data="tableList"
      :table-config="tableConfig"
      :has-selection="true"
      :has-index="true"
      :page-info="pageInfo"
      @page-size-change="handleSizeChange"
      @page-current-change="handleCurrentChange"
      @selection="handleSelect"
      border
      stripe
      height="100%"
      size="mini"
    >
      <!-- 自定义插槽示例 -->
      <template #batchArrangeNum="scope">
        <a href="javascript:;" @click="toDetail(scope.row)">{{
          scope.row.batchArrangeNum
        }}</a>
      </template>
      <template #layoutStatus="scope">
        <el-tag :type="layoutStatus[scope.row?.layoutStatus].type">{{
          layoutStatus[scope.row?.layoutStatus].label
        }}</el-tag>
      </template>
      <template #failReason="scope">
        <div style="white-space: pre-line">
          <span v-html="scope.row?.failReason"></span>
        </div>
      </template>

      <template #operation="scope">
        <div class="flex" style="justify-content: space-between;">
          <el-button
            type="text"
            class="btn flex btnBox"
            @click="downloadFile(scope.row.batchArrangeNum)"
          >
            <img src="../../assets/download.png" width="30" height="30" />
            <div>下载素材</div></el-button
          >
          <el-button
            type="text"
            :disabled="scope.row.layoutStatus == 2"
            class="btn flex btnBox"
            @click="changeTypesetting(scope.row)"
            ><img
              src="../../assets/typesetting.png"
              width="30"
              height="30"
              :class="{ disabled: scope.row.layoutStatus == 2 }"
            />
            <div>排版</div>
          </el-button>
          <el-button
            type="text"
            class="btn flex btnBox"
            @click="goFliePage(scope.row, 'check')"
          >
            <img src="../../assets/file.png" width="30" height="30" />
            <div>查看排版文件</div>
          </el-button>
        </div>
      </template>
    </BaseTable>
    <el-empty
      style="height: 100%; "
      v-else
      :image-size="500"
      :image="require('@/assets/JOMALL.png')"
      description="好像什么都没有"
    ></el-empty>
    <el-dialog title="排版宽度" :visible.sync="dialogVisible" width="25%">
      <el-radio-group v-model="radio">
        <el-radio :label="40">40+2cm</el-radio>
        <el-radio :label="60">60cm</el-radio>
      </el-radio-group>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="submit">确 定</el-button>
      </span>
    </el-dialog>

    <!-- 排版进度浮层（多任务） -->
    <transition-group name="composing-slide" tag="div" class="composing-panels">
      <div
        v-for="task in composingTasks"
        :key="task.id"
        class="composing-progress-panel"
      >
        <div class="cp-header">
          <span class="cp-batch">批次号：{{ task.batchArrangeNum }}</span>
          <i class="el-icon-close cp-close" @click="removeTask(task.id)"></i>
        </div>
        <el-steps
          :active="stepActive(task)"
          :process-status="stepStatus(task)"
          finish-status="success"
          size="mini"
          class="cp-steps"
        >
          <el-step title="排版"></el-step>
          <el-step title="下载"></el-step>
          <el-step title="完成"></el-step>
        </el-steps>
        <div v-if="task.progress" class="cp-msg">{{ task.progress }}</div>
      </div>
    </transition-group>
  </div>
</template>

<style scoped lang="less">
.page {
  height: "100%";
}
.flex {
  display: flex;
}
.btnBox {
  flex-direction: column;
  align-items: center;
}
.btn {
  padding: 0;
}
::v-deep .el-empty__image img {
  filter: grayscale(100%);
  opacity: 0.3;
}
::v-deep.el-empty__description p {
  font-size: 50px;
}
.el-button {
  div {
    margin-top: 5px;
    font-size: 12px;
  }
}
::v-deep.disabled {
  filter: grayscale(100%);
  opacity: 0.3;
}

.composing-panels {
  position: fixed;
  bottom: 20px;
  right: 20px;
  z-index: 2001;
  display: flex;
  flex-direction: column-reverse;
  gap: 10px;
}
.composing-progress-panel {
  width: 360px;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
  padding: 14px 16px 10px;
}
.cp-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}
.cp-batch {
  font-size: 13px;
  font-weight: 600;
  color: #303133;
}
.cp-close {
  cursor: pointer;
  color: #909399;
  font-size: 14px;
  &:hover {
    color: #606266;
  }
}
.cp-steps {
  margin-bottom: 6px;
}
::v-deep .cp-steps {
  .el-step__title {
    font-size: 12px;
    line-height: 20px;
  }
  .el-step__icon {
    width: 18px;
    height: 18px;
  }
  .el-step__icon-inner {
    font-size: 10px;
  }
}
.cp-msg {
  font-size: 12px;
  color: #909399;
  padding-left: 2px;
}
.composing-slide-enter-active,
.composing-slide-leave-active {
  transition: all 0.3s ease;
}
.composing-slide-enter,
.composing-slide-leave-to {
  opacity: 0;
  transform: translateY(20px);
}
</style>
