<template>
  <div>
    <BasicTable @register="registerTable" :rowSelection="rowSelection">
      <template #tableTitle>
        <a-button type="primary" v-auth="'xslmes:mes_xsl_raw_material_entry:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
        <a-button type="primary" v-auth="'xslmes:mes_xsl_raw_material_entry:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
        <j-upload-button type="primary" v-auth="'xslmes:mes_xsl_raw_material_entry:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
        <a-button type="primary" v-auth="'xslmes:mes_xsl_raw_material_entry:stockIn'" preIcon="ant-design:check-circle-outlined" @click="handleStockIn"> 结存入库</a-button>
        <!-- 与原材料卡片一致：字典选桥接地址 + 打印机 + 刷新 -->
        <JDictSelectTag
          v-model:value="printDotWsUrl"
          dictCode="xslmes_print_dot_ws"
          :showChooseOption="false"
          style="width: 280px; margin-left: 8px"
          placeholder="选择打印桥接"
          @change="onPrintDotWsUrlChange"
        />
        <a-button v-if="!printDotConnected" style="margin-left: 8px" @click="downloadPrintPlugin">下载打印插件</a-button>
        <a-select
          v-model:value="selectedPrinterName"
          :options="printerOptions"
          style="width: 220px; margin-left: 8px"
          allow-clear
          show-search
          option-filter-prop="label"
          :placeholder="printerSelectPlaceholder"
        />
        <a-button style="margin-left: 8px" @click="() => refreshPrinterOptions(true)">刷新打印机</a-button>
        <a-button
          type="primary"
          ghost
          v-auth="'xslmes:mes_xsl_raw_material_entry:edit'"
          :loading="printLoading"
          :disabled="selectedRowKeys.length === 0"
          @click="handlePrintSelected"
        >
          <Icon icon="ant-design:printer-outlined" />
          打印选中
        </a-button>
        <a-dropdown v-if="selectedRowKeys.length > 0">
          <template #overlay>
            <a-menu>
              <a-menu-item key="1" @click="batchHandleDelete">
                <Icon icon="ant-design:delete-outlined" />
                删除
              </a-menu-item>
            </a-menu>
          </template>
          <a-button v-auth="'xslmes:mes_xsl_raw_material_entry:deleteBatch'">批量操作
            <Icon icon="mdi:chevron-down" />
          </a-button>
        </a-dropdown>
        <super-query :config="superQueryConfig" @search="handleSuperQuery" />
      </template>
      <template #action="{ record }">
        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
      </template>
    </BasicTable>
    <MesXslRawMaterialEntryModal @register="registerModal" @success="handleSuccess" />
    <RawMaterialEntryPrintPreviewModal
      v-model:open="printPreviewOpen"
      :entry-id="printPreviewEntryId"
      :barcode="printPreviewBarcode"
    />
  </div>
</template>

<script lang="ts" name="xslmes-mesXslRawMaterialEntry" setup>
  import { onMounted, ref, reactive, watch, h } from 'vue';
  import { Icon } from '/@/components/Icon';
  import { BasicTable, TableAction } from '/@/components/Table';
  import { useModal } from '/@/components/Modal';
  import { useListPage } from '/@/hooks/system/useListPage';
  import { initDictOptions } from '/@/utils/dict';
  import { JDictSelectTag } from '/@/components/Form';
  import MesXslRawMaterialEntryModal from './components/MesXslRawMaterialEntryModal.vue';
  import RawMaterialEntryPrintPreviewModal from './components/RawMaterialEntryPrintPreviewModal.vue';
  import { columns, searchFormSchema, superQuerySchema } from './MesXslRawMaterialEntry.data';
  import {
    list,
    deleteOne,
    batchDelete,
    batchStockIn,
    getImportUrl,
    getExportUrl,
    getLinkedRawMaterialCards,
    prepareNativePrint,
    type MesXslRawMaterialCardBrief,
  } from './MesXslRawMaterialEntry.api';
  import { useMessage } from '/@/hooks/web/useMessage';
  import {
    PRINT_TEMPLATE_SELECTED_PRINTER_KEY,
    printNativeSchemaViaPrintDot,
  } from '/@/views/print/template/utils/printNativeViaPrintDot';
  import { normalizeImportedNativeSchema } from '/@/views/print/template/native/core/nativeSchemaNormalize';
  import {
    fetchPrintDotPrinters,
    getPrintDotBridgeConfig,
    setPrintDotBridgeConfig,
  } from '/@/views/print/template/utils/printDotBridge';

  const { createConfirm, createMessage } = useMessage();
  /** 与 Flyway 中 sys_dict.dict_code 一致（与原材料卡片列表相同） */
  const PRINT_DOT_WS_DICT = 'xslmes_print_dot_ws';
  const printDotWsUrl = ref('');
  /** 是否已成功连接桥并拿到响应（用于显示「下载打印插件」） */
  const printDotConnected = ref(false);

  function persistPrintDotConfig() {
    // 与原材料卡片一致：桥接密钥固定为空，由本地 PrintDot 与字典地址对接
    setPrintDotBridgeConfig(String(printDotWsUrl.value || '').trim(), '');
    void refreshPrinterOptions(false);
  }

  function onPrintDotWsUrlChange() {
    printDotConnected.value = false;
    persistPrintDotConfig();
  }

  function downloadPrintPlugin() {
    const base = import.meta.env.BASE_URL || '/';
    const normalizedBase = base.endsWith('/') ? base : `${base}/`;
    const url = `${normalizedBase}print-plugin/XSL-PrintDot.exe`;
    const link = document.createElement('a');
    link.href = url;
    link.setAttribute('download', 'XSL-PrintDot.exe');
    link.rel = 'noopener';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  }

  const queryParam = reactive<any>({});
  const [registerModal, { openModal }] = useModal();

  const { tableContext, onExportXls, onImportXls } = useListPage({
    tableProps: {
      title: '原料入场记录',
      api: list,
      columns,
      canResize: true,
      formConfig: {
        schemas: searchFormSchema,
        autoSubmitOnEnter: true,
        showAdvancedButton: true,
        fieldMapToTime: [
          ['entryTime', ['entryTime_begin', 'entryTime_end'], 'YYYY-MM-DD HH:mm:ss'],
        ],
      },
      actionColumn: {
        width: 320,
        fixed: 'right',
        title: '操作',
        dataIndex: 'action',
        slots: { customRender: 'action' },
      },
      beforeFetch: (params) => {
        return Object.assign(params, queryParam);
      },
    },
    exportConfig: {
      name: '原料入场记录',
      url: getExportUrl,
      params: queryParam,
    },
    importConfig: {
      url: getImportUrl,
      success: handleSuccess,
    },
  });

  const [registerTable, { reload }, { rowSelection, selectedRowKeys, selectedRows }] = tableContext;
  const superQueryConfig = reactive(superQuerySchema);

  /** 打印预览弹窗 */
  const printPreviewOpen = ref(false);
  const printPreviewEntryId = ref<string | null>(null);
  const printPreviewBarcode = ref<string | undefined>(undefined);

  function handlePrintPreview(record: Recordable) {
    printPreviewEntryId.value = record.id as string;
    printPreviewBarcode.value = record.barcode as string | undefined;
    printPreviewOpen.value = true;
  }

  const printerOptions = ref<Array<{ label: string; value: string }>>([]);
  const selectedPrinterName = ref<string>('__system_default__');
  const printLoading = ref(false);
  const printerSelectPlaceholder = '选择打印机（PrintDot 桥接）';

  watch(selectedPrinterName, (v) => {
    if (v) {
      localStorage.setItem(PRINT_TEMPLATE_SELECTED_PRINTER_KEY, v);
    }
  });

  async function refreshPrinterOptions(showMessage = true) {
    const optionMap = new Map<string, { label: string; value: string }>();
    optionMap.set('__system_default__', { label: '系统默认打印机', value: '__system_default__' });
    try {
      const dotList = await fetchPrintDotPrinters();
      printDotConnected.value = true;
      dotList.forEach((p) => {
        const name = String(p.name || '').trim();
        if (!name) return;
        const defMark = p.isDefault ? '（默认）' : '';
        optionMap.set(name, { label: `${name}${defMark}`, value: name });
      });
      if (selectedPrinterName.value && !optionMap.has(selectedPrinterName.value)) {
        optionMap.set(selectedPrinterName.value, {
          label: `${selectedPrinterName.value}（手动）`,
          value: selectedPrinterName.value,
        });
      }
      printerOptions.value = Array.from(optionMap.values());
      if (showMessage) {
        if (dotList.length) {
          createMessage.success(`已从 PrintDot 桥接识别 ${dotList.length} 台打印机`);
        } else {
          createMessage.warning('PrintDot 已连接但未返回打印机列表');
        }
      }
    } catch (e: unknown) {
      printDotConnected.value = false;
      if (selectedPrinterName.value && !optionMap.has(selectedPrinterName.value)) {
        optionMap.set(selectedPrinterName.value, {
          label: `${selectedPrinterName.value}（手动）`,
          value: selectedPrinterName.value,
        });
      }
      printerOptions.value = Array.from(optionMap.values());
      if (showMessage) {
        createMessage.warning(`PrintDot：${e instanceof Error ? e.message : String(e)}`);
      }
    }
  }

  async function executePrint(record: Recordable, options?: { silentSuccess?: boolean }) {
    try {
      const prep = (await prepareNativePrint(record.id as string)) as Record<string, unknown>;
      const templateJsonRaw = prep.templateJson as string;
      const printData = prep.printData as Record<string, unknown>;
      const paperWidthMm = Number((prep as any).paperWidthMm ?? 0);
      const paperHeightMm = Number((prep as any).paperHeightMm ?? 0);
      const paperOrientation = String((prep as any).paperOrientation || '').toLowerCase();
      if (!templateJsonRaw) {
        throw new Error('模板 JSON 为空');
      }
      let raw: unknown;
      try {
        raw = typeof templateJsonRaw === 'string' ? JSON.parse(templateJsonRaw) : templateJsonRaw;
      } catch {
        throw new Error('模板 JSON 格式错误');
      }
      const schema = normalizeImportedNativeSchema(raw);
      if (paperWidthMm > 0 && paperHeightMm > 0) {
        const orient = paperOrientation === 'landscape' ? 'landscape' : paperOrientation === 'portrait' ? 'portrait' : '';
        const normalized =
          orient === 'landscape'
            ? {
                width: Math.max(paperWidthMm, paperHeightMm),
                height: Math.min(paperWidthMm, paperHeightMm),
              }
            : orient === 'portrait'
              ? {
                  width: Math.min(paperWidthMm, paperHeightMm),
                  height: Math.max(paperWidthMm, paperHeightMm),
                }
              : {
                  width: paperWidthMm,
                  height: paperHeightMm,
                };
        schema.page.width = normalized.width;
        schema.page.height = normalized.height;
      }
      await printNativeSchemaViaPrintDot({
        schema,
        data: printData as Record<string, unknown>,
        jobName: `原料入场记录-${(record.barcode as string) || record.id}.pdf`,
        printerSelection:
          selectedPrinterName.value ||
          localStorage.getItem(PRINT_TEMPLATE_SELECTED_PRINTER_KEY) ||
          '__system_default__',
      });
      if (!options?.silentSuccess) {
        createMessage.success('已通过 PrintDot 提交打印');
      }
    } catch (e: unknown) {
      throw new Error(e instanceof Error ? e.message : String(e));
    }
  }

  function handlePrintSelected() {
    if (!String(printDotWsUrl.value || '').trim()) {
      createMessage.warning('请先选择打印桥接（PrintDot 地址）');
      return;
    }
    const rows = selectedRows.value || [];
    if (!rows.length) {
      createMessage.warning('请至少勾选一条记录后再点击「打印选中」');
      return;
    }
    printLoading.value = true;
    const hideLoadingMsg = createMessage.loading(`正在打印 ${rows.length} 条记录，请稍候…`, 0);
    (async () => {
      let ok = 0;
      let firstError = '';
      for (const row of rows) {
        try {
          await executePrint(row, { silentSuccess: true });
          ok += 1;
        } catch (e: unknown) {
          if (!firstError) {
            firstError = e instanceof Error ? e.message : String(e);
          }
        }
      }
      if (ok === rows.length) {
        createMessage.success(`已通过 PrintDot 提交 ${ok} 条打印任务`);
      } else {
        createMessage.warning(`打印完成：成功 ${ok}，失败 ${rows.length - ok}${firstError ? `。首条错误：${firstError}` : ''}`);
      }
      hideLoadingMsg();
      printLoading.value = false;
    })();
  }

  function handlePrintRow(record: Recordable) {
    if (!String(printDotWsUrl.value || '').trim()) {
      createMessage.warning('请先选择打印桥接（PrintDot 地址）');
      return;
    }
    printLoading.value = true;
    const hideLoadingMsg = createMessage.loading('正在生成 PDF 并提交打印，版面复杂时可能需数十秒，请稍候…', 0);
    executePrint(record)
      .then(() => {
        createMessage.success('已通过 PrintDot 提交打印');
      })
      .catch((e: unknown) => {
        createMessage.error(e instanceof Error ? e.message : String(e));
      })
      .finally(() => {
        hideLoadingMsg();
        printLoading.value = false;
      });
  }

  onMounted(async () => {
    const cfg = getPrintDotBridgeConfig();
    // 密钥不使用，与原材料卡片列表一致
    setPrintDotBridgeConfig(cfg.wsUrl || '', '');
    printDotWsUrl.value = cfg.wsUrl || '';

    try {
      const raw = await initDictOptions(PRINT_DOT_WS_DICT);
      const items = Array.isArray(raw) ? raw : [];
      const values = items
        .map((it: Recordable) => String(it.value ?? it.itemValue ?? '').trim())
        .filter(Boolean);
      const valueSet = new Set(values);
      if (valueSet.size && printDotWsUrl.value && !valueSet.has(String(printDotWsUrl.value).trim())) {
        printDotWsUrl.value = values[0];
        setPrintDotBridgeConfig(printDotWsUrl.value, '');
      } else if (valueSet.size && !String(printDotWsUrl.value || '').trim()) {
        printDotWsUrl.value = values[0];
        setPrintDotBridgeConfig(printDotWsUrl.value, '');
      }
    } catch {
      /* 字典未配置时沿用 localStorage */
    }

    const saved = localStorage.getItem(PRINT_TEMPLATE_SELECTED_PRINTER_KEY);
    if (saved) {
      selectedPrinterName.value = saved;
    }
    await refreshPrinterOptions(false);
  });

  function handleSuperQuery(params) {
    Object.keys(params).map((k) => {
      queryParam[k] = params[k];
    });
    reload();
  }

  function handleAdd() {
    openModal(true, { isUpdate: false, showFooter: true });
  }

  function handleEdit(record: Recordable) {
    openModal(true, { record, isUpdate: true, showFooter: true });
  }

  function handleDetail(record: Recordable) {
    openModal(true, { record, isUpdate: true, showFooter: false });
  }

  /** 删除确认框：关联卡片以列表形式展示 */
  function renderLinkedCardsConfirmContent(linked: MesXslRawMaterialCardBrief[], summaryText: string) {
    const labelStyle = { color: 'rgba(0,0,0,0.45)', display: 'inline-block', minWidth: '40px' as const };
    return h('div', { class: 'linked-raw-material-cards-confirm' }, [
      h('p', { style: { margin: '0 0 12px', color: 'rgba(0,0,0,0.88)' } }, summaryText),
      h(
        'ul',
        {
          style: {
            listStyle: 'none',
            padding: 0,
            margin: 0,
            maxHeight: '360px',
            overflowY: 'auto' as const,
            border: '1px solid #f0f0f0',
            borderRadius: '6px',
            background: '#fafafa',
          },
        },
        linked.map((c, idx) =>
          h(
            'li',
            {
              key: c.id ?? `${c.barcode ?? ''}-${c.batchNo ?? ''}-${idx}`,
              style: {
                padding: '10px 12px',
                borderBottom: idx < linked.length - 1 ? '1px solid #f0f0f0' : 'none',
                background: '#fff',
              },
            },
            [
              h('div', { style: { fontSize: '13px', lineHeight: '22px', color: 'rgba(0,0,0,0.88)', wordBreak: 'break-all' as const } }, [
                h('div', null, [h('span', { style: labelStyle }, '条码'), '：', c.barcode || '-']),
                h('div', null, [h('span', { style: labelStyle }, '批次'), '：', c.batchNo || '-']),
                h('div', null, [h('span', { style: labelStyle }, '物料'), '：', c.materialName || '-']),
              ]),
            ],
          ),
        ),
      ),
    ]);
  }

  async function handleDelete(record: Recordable) {
    try {
      const linked = await getLinkedRawMaterialCards(record.id as string);
      if (linked && linked.length > 0) {
        createConfirm({
          iconType: 'warning',
          title: '已生成原材料卡片',
          width: 600,
          content: renderLinkedCardsConfirmContent(linked, `以下 ${linked.length} 张卡片将随入场记录一并删除：`),
          okText: '仍要删除',
          cancelText: '取消',
          onOk: async () => {
            await deleteOne({ id: record.id as string, cascadeDeleteCards: true }, handleSuccess);
          },
        });
      } else {
        createConfirm({
          iconType: 'warning',
          title: '确认删除',
          content: '是否确认删除该条原料入场记录？',
          okText: '确认',
          cancelText: '取消',
          onOk: async () => {
            await deleteOne({ id: record.id as string, cascadeDeleteCards: false }, handleSuccess);
          },
        });
      }
    } catch (e: unknown) {
      createMessage.error(e instanceof Error ? e.message : String(e));
    }
  }

  async function batchHandleDelete() {
    const ids = (selectedRowKeys.value || []).join(',');
    if (!ids) {
      createMessage.warning('请先勾选要删除的记录');
      return;
    }
    try {
      const linked = await getLinkedRawMaterialCards(ids);
      const cardList: MesXslRawMaterialCardBrief[] = linked && linked.length > 0 ? linked : [];
      const hasCards = cardList.length > 0;
      createConfirm({
        iconType: 'warning',
        title: hasCards ? '已生成原材料卡片' : '确认删除',
        width: hasCards ? 600 : 416,
        content: hasCards
          ? renderLinkedCardsConfirmContent(cardList, `以下 ${cardList.length} 张卡片将随选中入场记录一并删除：`)
          : `是否删除选中的 ${selectedRowKeys.value.length} 条数据？`,
        okText: '确认删除',
        cancelText: '取消',
        onOk: async () => {
          await batchDelete({ ids, cascadeDeleteCards: !!hasCards }, handleSuccess);
        },
      });
    } catch (e: unknown) {
      createMessage.error(e instanceof Error ? e.message : String(e));
    }
  }

  function handleStockIn() {
    if (!selectedRowKeys.value.length) {
      createMessage.warning('请先勾选要结存入库的记录');
      return;
    }
    createConfirm({
      iconType: 'warning',
      title: '结存入库',
      content: `是否将选中的 ${selectedRowKeys.value.length} 条记录结存入库`,
      okText: '确认',
      cancelText: '取消',
      onOk: async () => {
        await batchStockIn(selectedRowKeys.value.join(','));
        createMessage.success('结存入库成功！');
        handleSuccess();
      },
    });
  }

  function handleSuccess() {
    (selectedRowKeys.value = []) && reload();
  }

  function getTableAction(record) {
    return [
      {
        label: '编辑',
        onClick: handleEdit.bind(null, record),
        auth: 'xslmes:mes_xsl_raw_material_entry:edit',
      },
      {
        label: '打印预览',
        onClick: handlePrintPreview.bind(null, record),
        auth: 'xslmes:mes_xsl_raw_material_entry:edit',
      },
      {
        label: '打印',
        onClick: handlePrintRow.bind(null, record),
        auth: 'xslmes:mes_xsl_raw_material_entry:edit',
      },
    ];
  }

  function getDropDownAction(record) {
    return [
      {
        label: '详情',
        onClick: handleDetail.bind(null, record),
      },
      {
        label: '删除',
        onClick: handleDelete.bind(null, record),
        auth: 'xslmes:mes_xsl_raw_material_entry:delete',
      },
    ];
  }
</script>

<style lang="less" scoped>
  :deep(.ant-picker-range) {
    width: 100%;
  }
</style>
