<template>
  <div class="import-wizard-container">
    <!-- 文件上传区域 -->
    <div class="file-upload-area" :class="{ disabled: importStatus === ImportStatus.PROCESSING }">
      <el-upload 
        ref="upload" 
        class="upload-excel" 
        action="" 
        :auto-upload="false" 
        :show-file-list="false"
        :on-change="handleFileChange" 
        accept=".xlsx,.xls" 
        :disabled="importStatus === ImportStatus.PROCESSING || validateLoading || importLoading"
      >
        <el-button type="primary" icon="el-icon-upload2">选择Excel文件</el-button>
      </el-upload>

      <!-- 操作按钮：新增loading和防呆 -->
      <el-button 
        type="success" 
        icon="el-icon-check" 
        @click="handleValidate"
        v-if="file && importStatus === ImportStatus.IDLE" 
        :disabled="!file || validateLoading"
        :loading="validateLoading"
      >
        校验数据
      </el-button>
      <el-button 
        type="warning" 
        icon="el-icon-circle-check" 
        @click="startImport"
        v-if="file && importStatus === ImportStatus.IDLE"
        :disabled="!file || !isValidated || errorList.length > 0 || importLoading"
        :loading="importLoading"
      >
        开始导入
      </el-button>
      <el-button 
        type="default" 
        icon="el-icon-refresh" 
        @click="reset" 
        :disabled="importStatus === ImportStatus.PROCESSING || validateLoading || importLoading"
      >
        重置
      </el-button>
    </div>

    <!-- 校验错误提示 -->
    <div v-if="errorList.length > 0" class="error-list">
      <el-alert title="数据校验失败" type="error" description="以下行数据不符合格式要求，请修正后重新导入：" show-icon />
      <el-table :data="errorList" border size="small" max-height="200">
        <el-table-column prop="rowNum" label="行号" width="80" />
        <el-table-column prop="errorMsg" label="错误信息" />
      </el-table>
    </div>

    <!-- 数据预览 -->
    <div v-if="tableData.length > 0 && importStatus === ImportStatus.IDLE" class="data-preview">
      <el-alert 
        title="数据预览" 
        type="info" 
        :description="`共解析出 ${tableData.length} 条有效数据`" 
        show-icon 
        :closable="false" 
      />
      <el-table :data="tableData" border size="small" max-height="300" stripe>
        <el-table-column 
          v-for="column in TableColumnEnum" 
          :key="column.prop"
          :prop="column.prop" 
          :label="column.label" 
          :width="column.width"
          :min-width="column.minWidth"
        />
      </el-table>
    </div>

    <!-- 导入进度展示 -->
    <div v-if="importStatus === ImportStatus.PROCESSING" class="import-progress">
      <el-alert 
        title="正在导入数据" 
        type="warning" 
        :description="`当前进度：${progress}%`" 
        show-icon 
        :closable="false" 
      />
      <el-progress :percentage="progress" status="success" />
      <p class="progress-tip">已导入 {{ importedCount }} / {{ totalCount }} 条数据</p>
    </div>

    <!-- 导入完成提示 -->
    <div v-if="importStatus === ImportStatus.FINISHED" class="import-finished">
      <el-alert 
        title="导入完成" 
        type="success" 
        :description="`共成功导入 ${importedCount} 条数据，总计 ${totalCount} 条`" 
        show-icon 
      />
    </div>

    <!-- 导入失败提示 -->
    <div v-if="importStatus === ImportStatus.ERROR" class="import-error">
      <el-alert title="导入失败" type="error" :description="importErrorMsg" show-icon />
    </div>
  </div>
</template>

<script>
import * as XLSX from 'xlsx';
import { addMaterialCoil } from '@/api/wms/coil';
import { addPendingAction } from '@/api/wms/pendingAction';
import { listRawMaterial } from '@/api/wms/rawMaterial';
import { listProduct } from '@/api/wms/product';
import { listWarehouse } from '@/api/wms/warehouse';

// ===================== 枚举定义 =====================
/**
 * 导入状态枚举
 */
const ImportStatus = Object.freeze({
  IDLE: 'idle',         // 闲置
  PROCESSING: 'processing', // 处理中
  FINISHED: 'finished', // 完成
  ERROR: 'error'        // 失败
});

/**
 * 错误类型枚举（含校验逻辑）
 */
const ErrorType = Object.freeze({
  // 表头错误
  HEADER_COUNT_ERROR: {
    message: (required, actual) => `表头数量不匹配，要求${required}列，实际${actual}列`
  },
  HEADER_NAME_ERROR: {
    message: (index, required, actual) => `第${index + 1}列表头错误，要求："${required}"，实际："${actual}"`
  },
  // 字段校验错误
  FIELD_REQUIRED: {
    message: (label) => `${label}不能为空`,
    validator: (rowObj, rowNum, errorList) => {
      const requiredFields = [
        { key: 'type', label: '类型' },
        { key: 'logicWarehouse', label: '逻辑库区' },
        { key: 'inboundCoilNo', label: '入场卷号' },
        { key: 'name', label: '名称' },
        { key: 'specification', label: '规格' },
        { key: 'weight', label: '重量（吨）' }
      ];

      requiredFields.forEach(field => {
        const value = rowObj[field.key];
        if (!value || (typeof value === 'string' && value.trim() === '')) {
          errorList.push({
            rowNum,
            errorMsg: ErrorType.FIELD_REQUIRED.message(field.label)
          });
        }
      });
    }
  },
  // 类型错误
  TYPE_ERROR: {
    message: '类型只能是"原料"或"成品"',
    validator: (rowObj, rowNum, errorList) => {
      if (rowObj.type && !['原料', '成品'].includes(rowObj.type.trim())) {
        errorList.push({
          rowNum,
          errorMsg: ErrorType.TYPE_ERROR.message
        });
      }
    }
  },
  // 重量错误
  WEIGHT_ERROR: {
    message: '重量必须是大于0的数字',
    validator: (rowObj, rowNum, errorList) => {
      if (rowObj.weight) {
        const weight = Number(rowObj.weight);
        if (isNaN(weight) || weight <= 0) {
          errorList.push({
            rowNum,
            errorMsg: ErrorType.WEIGHT_ERROR.message
          });
        }
      }
    }
  },
  // 仓库名不规范或不存在
  WAREHOUSE_ERROR: {
    message: (warehouseName) => `仓库名"${warehouseName}"不规范或不存在`,
    validator: (rowObj, rowNum, errorList, warehouseMap) => {
      const warehouseId = warehouseMap[rowObj.logicWarehouse];
      if (!warehouseId) {
        errorList.push({
          rowNum,
          errorMsg: ErrorType.WAREHOUSE_ERROR.message(rowObj.logicWarehouse)
        });
      }
    }
  },
  // 物料ID不存在
  ITEM_ID_NOT_FOUND: {
    message: (type, name, spec, material, surfaceTreatmentDesc, manufacturer, zincLayer) => `未找到唯一匹配的${type}类型（名称：${name}，规格：${spec}，材质：${material || '无'}，表面处理：${surfaceTreatmentDesc || '无'}，厂家：${manufacturer || '无'}，锌层：${zincLayer || '无'}）`
  }
});

/**
 * 表格列配置枚举
 */
const TableColumnEnum = Object.freeze([
  { prop: 'type', label: '类型', width: 80 },
  { prop: 'logicWarehouse', label: '逻辑库区', width: 120 },
  { prop: 'inboundCoilNo', label: '入场卷号', width: 150 },
  { prop: 'factoryCoilNo', label: '厂家卷号', width: 150 },
  { prop: 'weight', label: '重量（吨）', width: 120 },
  { prop: 'remark', label: '备注', minWidth: 100 },
  { prop: 'name', label: '名称', minWidth: 100 },
  { prop: 'specification', label: '规格', minWidth: 100 },
  { prop: 'material', label: '材质', width: 100 },
  { prop: 'manufacturer', label: '厂家', minWidth: 100 },
  { prop: 'surfaceTreatmentDesc', label: '表面处理', width: 120 },
  { prop: 'zincLayer', label: '锌层', width: 100 }
]);

/**
 * 系统常量枚举
 */
const SystemConstant = Object.freeze({
  // Excel表头配置
  REQUIRED_HEADERS: TableColumnEnum.map(col => col.label),
  HEADER_MAP: TableColumnEnum.reduce((map, col) => {
    map[col.label] = col.prop;
    return map;
  }, {}),
  // 接口常量
  COIL_DATA_TYPE: 10,        // 钢卷数据类型
  PENDING_ACTION_STATUS: 0,  // 待处理状态
  OPERATION_TYPE_IMPORT: 'import', // 操作类型-导入
  PENDING_ACTION_TYPE_RECEIVE: 401, // 待处理类型-入库
  // 物料类型映射
  ITEM_TYPE_MAP: {
    '原料': 'raw_material',
    '成品': 'product'
  },
  // 物料ID字段映射
  ITEM_ID_FIELD: {
    'raw_material': 'rawMaterialId',
    'product': 'productId'
  }
});

export default {
  name: 'MaterialCoilImportWizard',
  props: {
    planId: {
      type: String,
      default: 0
    }
  },
  data() {
    return {
      // 枚举挂载到实例，方便模板使用
      ImportStatus,
      TableColumnEnum,
      
      // 文件对象
      file: null,
      // 解析后的原始数据
      rawData: [],
      // 格式化后用于展示/导入的数据
      tableData: [],
      // 校验错误列表（为空表示校验通过）
      errorList: [],
      // 是否点击过校验按钮（新增状态）
      isValidated: false,
      // 导入进度（0-100）
      progress: 0,
      // 已导入条数
      importedCount: 0,
      // 总数据条数
      totalCount: 0,
      // 导入状态
      importStatus: ImportStatus.IDLE,
      // 导入错误信息
      importErrorMsg: '',
      // 仓库名到仓库id的映射关系
      warehouseMap: {},
      // 防呆loading状态
      validateLoading: false, // 校验按钮loading
      importLoading: false    // 导入按钮loading
    };
  },
  methods: {
    /**
     * 处理文件选择（新增防呆：操作中禁止切换文件）
     */
    handleFileChange(file) {
      // 操作中禁止切换文件
      if (this.validateLoading || this.importLoading || this.importStatus === ImportStatus.PROCESSING) {
        this.$message.warning('当前有操作正在进行中，请完成后再选择新文件');
        return;
      }
      this.file = file.raw;
      this.isValidated = false; // 选择新文件后重置校验状态
      this.readExcel();
    },

    /**
     * 获取所有的仓库，建立仓库名到仓库id的映射关系
     */
    async getWarehouseMap() {
      try {
        const response = await listWarehouse({ pageNum: 1, pageSize: 1000 });
        const map = {};
        
        for (let item of response.data) {
          map[item.warehouseName] = item.warehouseId;
        }
        console.log(map, response);
        this.warehouseMap = map;
      } catch (error) {
        this.handleError(`获取仓库列表失败：${error.message}`);
      }
    },

    /**
     * 读取Excel文件内容
     */
    async readExcel() {
      if (!this.file) return;

      try {
        const fileReader = new FileReader();
        fileReader.readAsArrayBuffer(this.file);

        fileReader.onload = async (e) => {
          try {
            const data = new Uint8Array(e.target.result);
            const workbook = XLSX.read(data, { type: 'array' });
            const sheetName = workbook.SheetNames[0];
            const worksheet = workbook.Sheets[sheetName];
            const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });

            // 校验表头
            this.validateHeaders(jsonData[0]);
            // 解析数据行（过滤空行）
            this.rawData = jsonData.slice(1).filter(row => row.length > 0);
            // 格式化数据
            this.formatExcel();

            this.$message.success(`成功解析Excel，共读取到 ${this.rawData.length} 条数据`);
          } catch (error) {
            this.handleError(`解析Excel失败：${error.message}`);
          }
        };
      } catch (error) {
        this.handleError(`读取文件失败：${error.message}`);
      }
    },

    /**
     * 校验表头是否匹配
     */
    validateHeaders(headers) {
      this.errorList = [];
      const { REQUIRED_HEADERS } = SystemConstant;

      // 校验表头数量
      if (headers.length !== REQUIRED_HEADERS.length) {
        this.errorList.push({
          rowNum: 1,
          errorMsg: ErrorType.HEADER_COUNT_ERROR.message(REQUIRED_HEADERS.length, headers.length)
        });
      }

      // 校验表头名称
      headers.forEach((header, index) => {
        if (header !== REQUIRED_HEADERS[index]) {
          this.errorList.push({
            rowNum: 1,
            errorMsg: ErrorType.HEADER_NAME_ERROR.message(index, REQUIRED_HEADERS[index], header)
          });
        }
      });

      if (this.errorList.length > 0) {
        this.$message.error('Excel表头格式不符合要求，请检查！');
      }
    },

    /**
     * 校验Excel数据格式（唯一校验入口，添加防重复点击）
     */
    async handleValidate() {
      // 防重复点击校验
      if (this.validateLoading) {
        this.$message.warning('正在校验数据，请稍候...');
        return;
      }
      if (!this.file) {
        this.$message.warning('请先选择Excel文件');
        return;
      }

      // 标记为已点击过校验
      this.isValidated = true;

      if (this.rawData.length === 0) {
        this.$message.warning('暂无数据可校验');
        return;
      }

      this.validateLoading = true; // 开启校验loading
      this.errorList = [];

      try {
        // 逐行校验
        for (let i = 0; i < this.rawData.length; i++) {
          const row = this.rawData[i];
          const rowNum = i + 2; // 数据行从第二行开始
          const rowObj = this.formatRowData(row, rowNum);

          // 执行各类校验器
          ErrorType.FIELD_REQUIRED.validator(rowObj, rowNum, this.errorList);
          ErrorType.TYPE_ERROR.validator(rowObj, rowNum, this.errorList);
          ErrorType.WEIGHT_ERROR.validator(rowObj, rowNum, this.errorList);
          ErrorType.WAREHOUSE_ERROR.validator(rowObj, rowNum, this.errorList, this.warehouseMap);

          // 校验物料ID是否存在（仅当当前行无基础错误时）
          if (!this.errorList.some(err => err.rowNum === rowNum) && rowObj.type) {
            const itemId = await this._findItemId(rowObj);
            if (!itemId) {
              this.errorList.push({
                rowNum,
                errorMsg: ErrorType.ITEM_ID_NOT_FOUND.message(rowObj.type, rowObj.name, rowObj.specification, rowObj.material, rowObj.surfaceTreatmentDesc, rowObj.manufacturer, rowObj.zincLayer)
              });
            }
          }
        }

        if (this.errorList.length > 0) {
          this.$message.error(`数据校验失败，共发现${this.errorList.length}条错误`);
        } else {
          this.$message.success('数据校验通过，可以开始导入');
        }
      } catch (error) {
        this.handleError(`校验数据时发生错误：${error.message}`);
      } finally {
        this.validateLoading = false; // 关闭校验loading
      }
    },

    /**
     * 格式化Excel行数据
     */
    formatExcel() {
      this.tableData = [];
      if (this.rawData.length === 0) return;

      this.rawData.forEach((row, index) => {
        const rowNum = index + 2;
        const rowObj = this.formatRowData(row, rowNum);
        this.tableData.push(rowObj);
      });
    },

    /**
     * 格式化单行数据
     */
    formatRowData(row, rowNum) {
      const { HEADER_MAP, REQUIRED_HEADERS } = SystemConstant;
      const rowObj = {};

      // 映射表头和字段
      REQUIRED_HEADERS.forEach((header, index) => {
        const field = HEADER_MAP[header];
        rowObj[field] = row[index] ? row[index].toString().trim() : '';
      });

      // 重量转数字
      rowObj.weight = rowObj.weight ? Number(rowObj.weight) : 0;
      // 增加行号
      rowObj.rowNum = rowNum;

      return rowObj;
    },

    /**
     * 开始导入数据（添加防重复点击和二次确认）
     */
    async startImport() {
      // 防重复点击导入
      if (this.importLoading) {
        this.$message.warning('正在导入数据，请勿重复操作...');
        return;
      }
      if (!this.file || this.tableData.length === 0) {
        this.$message.warning('暂无数据可导入');
        return;
      }

      // 二次确认，防止误操作
      const confirm = await this.$confirm(
        '确认导入已校验通过的数据？导入过程中请勿刷新页面或关闭浏览器！', 
        '导入确认', 
        {
          confirmButtonText: '确认导入',
          cancelButtonText: '取消',
          type: 'warning',
          dangerouslyUseHTMLString: true
        }
      ).catch(() => false);

      if (!confirm) return;

      this.importLoading = true; // 开启导入loading
      // 初始化导入状态
      this.importStatus = ImportStatus.PROCESSING;
      this.progress = 0;
      this.importedCount = 0;
      this.totalCount = this.tableData.length;
      this.importErrorMsg = '';

      try {
        await this.batchImport();
        this.importStatus = ImportStatus.FINISHED;
        this.$message.success(`导入完成！共成功导入${this.importedCount}条数据`);
      } catch (error) {
        this.handleError(`导入失败：${error.message}，已导入${this.importedCount}条数据`);
      } finally {
        this.importLoading = false; // 关闭导入loading
      }
    },

    /**
     * 批量导入数据
     */
    async batchImport() {
      for (let i = 0; i < this.tableData.length; i++) {
        // 若导入已失败，终止后续操作
        if (this.importStatus === ImportStatus.ERROR) break;

        const row = this.tableData[i];
        try {
          await this.importOneRecord(row);
          this.importedCount++;
          // 更新进度（避免进度跳动过大）
          const currentProgress = Math.round(((i + 1) / this.totalCount) * 100);
          this.progress = currentProgress;
          // 给浏览器渲染时间，避免卡死
          await new Promise(resolve => setTimeout(resolve, 50));
        } catch (error) {
          throw new Error(`第${row.rowNum}行导入失败：${error.message}`);
        }
      }
    },

    /**
     * 导入单条记录
     */
    async importOneRecord(row) {
      try {
        // 1. 查找物料ID（再次校验，防止数据篡改）
        const itemId = await this._findItemId(row);
        if (!itemId) {
          throw new Error(ErrorType.ITEM_ID_NOT_FOUND.message(row.type, row.name, row.specification, row.material, row.surfaceTreatmentDesc, row.manufacturer, row.zincLayer));
        }

        const itemType = SystemConstant.ITEM_TYPE_MAP[row.type];

        // 2. 插入钢卷数据
        const coilParams = {
          itemId,
          itemType,
          materialType: row.type,
          warehouseId: this.warehouseMap[row.logicWarehouse],
          enterCoilNo: row.inboundCoilNo,
          currentCoilNo: row.inboundCoilNo,
          supplierCoilNo: row.factoryCoilNo,
          grossWeight: row.weight,
          netWeight: row.weight,
          remark: row.remark,
          dataType: SystemConstant.COIL_DATA_TYPE
        };
        const coilRes = await addMaterialCoil(coilParams);
        if (coilRes.code !== 200) {
          throw new Error(`钢卷数据插入失败：${coilRes.message || '接口返回异常'}`);
        }
        const coilId = coilRes.data?.coilId;

        // 3. 插入待处理操作
        const actionParams = {
          coilId,
          currentCoilNo: row.inboundCoilNo,
          actionStatus: SystemConstant.PENDING_ACTION_STATUS,
          itemType,
          itemId,
          actionType: SystemConstant.PENDING_ACTION_TYPE_RECEIVE,
          operationType: SystemConstant.OPERATION_TYPE_IMPORT,
          remark: `Excel导入：${row.inboundCoilNo}`,
          warehouseId: this.planId
        };
        const actionRes = await addPendingAction(actionParams);
        if (actionRes.code !== 200) {
          throw new Error(`待处理操作插入失败：${actionRes.message || '接口返回异常'}`);
        }

      } catch (error) {
        throw new Error(error.message);
      }
    },

    /**
     * 根据条件查找唯一的物料ID
     */
    async _findItemId(row) {
      const { ITEM_TYPE_MAP, ITEM_ID_FIELD } = SystemConstant;
      const itemType = ITEM_TYPE_MAP[row.type];
      if (!itemType) return null;

      try {
        // 构建查询参数
        const queryParams = {
          [row.type === '原料' ? 'rawMaterialName' : 'productName']: row.name,
          specification: row.specification,
          material: row.material,
          manufacturer: row.manufacturer,
          surfaceTreatmentDesc: row.surfaceTreatmentDesc,
          zincLayer: row.zincLayer
        };

        // 执行查询
        const res = itemType === 'raw_material' 
          ? await listRawMaterial(queryParams) 
          : await listProduct(queryParams);

        // 空值判断函数
        const isEmpty = (value) => value === null || value === undefined || value === '';

        // 筛选匹配记录
        const matchedRecords = res.rows.filter(item => {
          if (isEmpty(row.zincLayer) && !isEmpty(item.zincLayer)) return false;
          if (isEmpty(row.surfaceTreatmentDesc) && !isEmpty(item.surfaceTreatmentDesc)) return false;
          if (isEmpty(row.manufacturer) && !isEmpty(item.manufacturer)) return false;
          if (isEmpty(row.material) && !isEmpty(item.material)) return false;
          return true;
        });

        // 必须返回唯一记录
        if (matchedRecords.length !== 1) return null;

        // 返回物料ID
        return matchedRecords[0][ITEM_ID_FIELD[itemType]];
      } catch (error) {
        this.$message.error(`查询${row.type}信息失败：${error.message}`);
        return null;
      }
    },

    /**
     * 重置所有状态（添加防呆和二次确认）
     */
    async reset() {
      // 操作中禁止重置
      if (this.validateLoading || this.importLoading || this.importStatus === ImportStatus.PROCESSING) {
        this.$message.warning('当前有操作正在进行中，无法重置');
        return;
      }

      // 有数据时二次确认，防止误清空
      if (this.file || this.tableData.length > 0 || this.errorList.length > 0) {
        const confirm = await this.$confirm(
          '确认重置所有状态？已选择的文件、解析的数据和校验结果将被清空！', 
          '重置确认', 
          {
            confirmButtonText: '确认重置',
            cancelButtonText: '取消',
            type: 'info'
          }
        ).catch(() => false);

        if (!confirm) return;
      }

      // 重置所有状态
      this.file = null;
      this.rawData = [];
      this.tableData = [];
      this.errorList = [];
      this.isValidated = false;
      this.progress = 0;
      this.importedCount = 0;
      this.totalCount = 0;
      this.importStatus = ImportStatus.IDLE;
      this.importErrorMsg = '';
      this.$refs.upload?.clearFiles();
      this.$message.success('已重置所有状态');
    },

    /**
     * 统一错误处理（确保loading状态关闭）
     */
    handleError(message) {
      this.$message.error(message);
      this.importStatus = ImportStatus.ERROR;
      this.importErrorMsg = message;
      // 异常场景下强制关闭loading，避免界面卡死
      this.validateLoading = false;
      this.importLoading = false;
    }
  },
  mounted() {
    this.getWarehouseMap();
  },
};
</script>

<style scoped>
.import-wizard-container {
  padding: 20px;
  background: #fff;
  border-radius: 4px;
}

.file-upload-area {
  margin-bottom: 20px;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap; /* 适配小屏幕 */
}

.file-upload-area.disabled {
  opacity: 0.6;
  pointer-events: none;
}

.error-list {
  margin-bottom: 20px;
}

.data-preview {
  margin-bottom: 20px;
}

.import-progress {
  margin-bottom: 20px;
  padding: 10px;
  background: #f5f7fa;
  border-radius: 4px;
}

.progress-tip {
  margin: 10px 0 0 0;
  color: #666;
  font-size: 14px;
}

.import-finished,
.import-error {
  margin-bottom: 20px;
}

/* 优化按钮间距，适配小屏幕 */
@media (max-width: 768px) {
  .file-upload-area {
    flex-direction: column;
    align-items: flex-start;
  }
}
</style>