<template>
  <section class="page-grid">
    <div v-if="feedbackMessage" class="feedback-banner">{{ feedbackMessage }}</div>
    <div v-if="errorMessage" class="feedback-banner error-banner">{{ errorMessage }}</div>

    <section class="panel">
      <div class="page-hero-card purchase-chain-hero purchase-order-hero">
        <div class="page-hero-copy">
          <p class="eyebrow">采购订单</p>
          <h3>采购计划与订单执行</h3>
          <p class="page-hero-subtitle">统一管理备料采购与销售订单采购，串联合同生成、锁单和到货预警。</p>
        </div>
        <div class="page-hero-actions">
          <span class="panel-tag">合同与锁单</span>
          <button
            class="purchase-contract-button"
            type="button"
            :disabled="!selectedOrderIds.length"
            title="勾选采购订单后生成基础采购合同"
            @click="generatePurchaseContract"
          >
            生成合同
          </button>
          <button
            class="purchase-contract-button"
            type="button"
            title="勾选采购订单后批量下载PDF归档"
            @click="batchDownloadPurchaseArchives"
          >
            批量下载PDF归档
          </button>
          <button class="primary-button" type="button" @click="openCreateDrawer">新增采购订单</button>
        </div>
      </div>

      <TableControls
        v-model:search="orderControls.search.value"
        v-model:sort-key="orderControls.sortKey.value"
        v-model:sort-direction="orderControls.sortDirection.value"
        :sort-options="orderControls.sortOptions"
        placeholder="搜索采购单号、采购仓库、来源销售订单、供应商、状态"
      />

      <div class="table-wrap">
        <table class="data-table">
          <thead>
            <tr>
              <th class="select-col">
                <input
                  type="checkbox"
                  :checked="allVisibleOrdersSelected"
                  :indeterminate="someVisibleOrdersSelected && !allVisibleOrdersSelected"
                  title="选择当前页采购订单"
                  @change="toggleVisibleOrders"
                />
              </th>
              <th>采购单号</th>
              <th>采购仓库</th>
              <th>采购来源</th>
              <th>供应商</th>
              <th>物料项</th>
              <th>预计到货</th>
              <th>总金额</th>
              <th>订单量</th>
              <th>已收量</th>
              <th>状态</th>
              <th class="purchase-archive-col">归档</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody>
            <tr
              v-for="order in paginatedOrders"
              :key="order.purchase_order_id"
              :class="{ 'row-selected': selectedOrderId === order.purchase_order_id, 'purchase-warning-row': isPurchaseWarning(order) }"
            >
              <td class="select-col">
                <input
                  type="checkbox"
                  :checked="selectedOrderIdSet.has(Number(order.purchase_order_id))"
                  title="选择生成采购合同"
                  @change="toggleOrderSelection(order.purchase_order_id)"
                />
              </td>
              <td>
                <button class="link-button" type="button" @click="openDetailDrawer(order)">
                  {{ order.po_no }}
                </button>
              </td>
              <td>
                <span class="table-chip">{{ purchaseTargetLabel(order.target_warehouse_type) }}</span>
              </td>
              <td>
                <div class="purchase-source-cell">
                  <span
                    v-for="source in sourceCardsForOrder(order)"
                    :key="source.key"
                    class="purchase-source-chip"
                    @mouseenter="showHoverCard($event, source.title, source.subtitle)"
                    @mouseleave="hideHoverCard"
                  >
                    <strong>{{ source.title }}</strong>
                    <small>{{ source.subtitle }}</small>
                  </span>
                </div>
              </td>
              <td>{{ order.supplier_name }}</td>
              <td>
                <div class="material-item-cell">
                  <span
                    v-for="item in orderMaterialItems(order.purchase_order_id)"
                    :key="item.purchase_order_item_id"
                    class="material-item-chip"
                    @mouseenter="showHoverCard($event, item.material_name, materialHoverSubtitle(item))"
                    @mouseleave="hideHoverCard"
                  >
                    <strong>{{ item.material_name }}</strong>
                    <small>{{ materialChipSubtitle(item) }}</small>
                    <small class="material-performance-line">性能要求：{{ materialPerformanceRequirement(item) || "未维护" }}</small>
                  </span>
                  <span v-if="!orderMaterialItems(order.purchase_order_id).length" class="empty-inline">暂无明细</span>
                </div>
              </td>
              <td>
                <span>{{ formatDate(order.expected_date) }}</span>
                <small v-if="isPurchaseWarning(order)" class="warning-inline">提前{{ order.warning_lead_days }}天预警</small>
              </td>
              <td>¥{{ formatAmount(order.total_amount) }}</td>
              <td>{{ formatOrderTotal(order) }}</td>
              <td>{{ formatReceivedTotal(order) }}</td>
              <td>
                <span class="status-badge-stack">
                  <StatusBadge :value="order.display_status || order.status" :text="formatStatusLabel(order.display_status || order.status)" />
                  <StatusBadge v-if="isPurchaseWarning(order)" value="PENDING" text="到货预警" />
                  <StatusBadge v-if="order.has_return" value="HAS_RETURN" text="存在退货" />
                </span>
              </td>
              <td class="purchase-archive-cell">
                <div class="purchase-archive-actions-compact">
                  <DocumentArchiveActions
                    :status="order.archive_status"
                    @preview="previewDocumentArchive('purchase-order', order.purchase_order_id)"
                    @download="downloadDocumentArchive('purchase-order', order.purchase_order_id, `${order.po_no || '采购订单'}归档.pdf`)"
                    @regenerate="regenerateDocumentArchive('purchase-order', order.purchase_order_id)"
                  />
                </div>
              </td>
              <td class="action-row">
                <button
                  class="ghost-button table-action-button"
                  type="button"
                  :disabled="!canEditOrder(order)"
                  :title="editOrderTitle(order)"
                  @click="openEditDrawer(order)"
                >
                  编辑
                </button>
                <button
                  class="ghost-button table-action-button danger-ghost"
                  type="button"
                  :disabled="!canDeleteOrder(order)"
                  :title="deleteOrderTitle(order)"
                  @click="deletePurchaseOrderRow(order)"
                >
                  删除
                </button>
                <button
                  class="ghost-button table-action-button"
                  type="button"
                  :disabled="!canLockOrder(order)"
                  :title="lockOrderTitle(order)"
                  @click="lockPurchaseOrder(order)"
                >
                  锁单
                </button>
              </td>
            </tr>
            <tr v-if="!filteredOrders.length">
              <td colspan="13" class="empty-row">暂无采购订单，请点击右上角新增采购订单。</td>
            </tr>
          </tbody>
        </table>
      </div>
      <PaginationBar v-model:page="orderPage" v-model:page-size="orderPageSize" :total="filteredOrders.length" />
    </section>

    <FormDrawer
      :open="drawerOpen"
      eyebrow="采购订单"
      :title="orderDrawerTitle"
      :description="orderDrawerDescription"
      tag="采购执行"
      wide
      @close="closeOrderDrawer"
    >
      <form class="stack-form purchase-document-form" @submit.prevent="submitOrder">
        <DocumentPaper
          title="采购订单"
          :document-no="displayPurchaseOrderNo"
          :signature-labels="['采购确认', '供应商确认', '仓库接收', '制单人']"
          tone="green"
        >
          <section class="document-form-section purchase-route-section">
            <div class="document-section-title-row">
              <h2>路径信息</h2>
            </div>
            <div class="purchase-decision-panel document-purchase-decision-panel">
              <section class="purchase-decision-section">
                <div class="purchase-decision-title">
                  <span class="purchase-decision-index">01</span>
                  <div>
                    <strong>到货仓库</strong>
                  </div>
                </div>

                <div class="purchase-choice-grid">
                  <button
                    class="purchase-choice-card warehouse-choice"
                    :class="{ active: form.target_warehouse_type === 'RAW' }"
                    type="button"
                    title="钢材、铝材等参与产品主材核算的材料。"
                    @click="setTargetWarehouseType('RAW')"
                  >
                    <span class="choice-check"></span>
                    <span class="choice-main">
                      <strong>原材料库</strong>
                    </span>
                  </button>
                  <button
                    class="purchase-choice-card warehouse-choice"
                    :class="{ active: form.target_warehouse_type === 'AUX' }"
                    type="button"
                    title="手套、薄膜、纸箱、螺丝钉等生产消耗品。"
                    @click="setTargetWarehouseType('AUX')"
                  >
                    <span class="choice-check"></span>
                    <span class="choice-main">
                      <strong>辅料库</strong>
                    </span>
                  </button>
                </div>
              </section>

              <section class="purchase-decision-section purchase-mode-section">
                <div class="purchase-decision-title">
                  <span class="purchase-decision-index">02</span>
                  <div>
                    <strong>采购方式</strong>
                  </div>
                </div>

                <div class="purchase-choice-grid">
                  <button
                    class="purchase-choice-card mode-choice"
                    :class="{ active: form.purchase_type === 'STOCKING' }"
                    type="button"
                    title="提前备货，按库存或经验需求采购。"
                    @click="setPurchaseType('STOCKING')"
                  >
                    <span class="choice-check"></span>
                    <span class="choice-main">
                      <strong>备料采购</strong>
                    </span>
                  </button>
                  <button
                    v-if="form.target_warehouse_type === 'RAW'"
                    class="purchase-choice-card mode-choice"
                    :class="{ active: form.purchase_type === 'SALES_ORDER' }"
                    type="button"
                    title="关联销售订单，按订单物料需求带出采购明细。"
                    @click="setPurchaseType('SALES_ORDER')"
                  >
                    <span class="choice-check"></span>
                    <span class="choice-main">
                      <strong>销售订单采购</strong>
                    </span>
                  </button>
                  <div v-else class="purchase-choice-card mode-choice disabled-choice" title="辅料库不参与销售订单物料需求计算，只能做备料采购。">
                    <span class="choice-lock">!</span>
                    <span class="choice-main">
                      <strong>销售订单采购不可用</strong>
                    </span>
                  </div>
                </div>
              </section>
            </div>
          </section>

          <DocumentGrid :fields="purchaseDocumentHeaderFields" columns="3">
            <template #po_no>
              <input :value="displayPurchaseOrderNo" type="text" disabled readonly />
            </template>
            <template #target_warehouse_type>
              <span class="document-static-value">{{ purchaseTargetLabel(form.target_warehouse_type) }}</span>
            </template>
            <template #purchase_type>
              <span class="document-static-value">{{ form.purchase_type === "SALES_ORDER" ? "销售订单采购" : "备料采购" }}</span>
            </template>
            <template #supplier>
              <select v-model.number="form.supplier_id" required>
                <option disabled value="">请选择供应商</option>
                <option v-for="supplier in suppliers" :key="supplier.id" :value="supplier.id">
                  {{ supplier.supplier_name }}
                </option>
              </select>
            </template>
            <template #purchaser>
              <select v-model.number="form.purchaser_employee_id">
                <option value="">请选择</option>
                <option v-for="employee in employees" :key="employee.id" :value="employee.id">
                  {{ employeeOptionLabel(employee) }}
                </option>
              </select>
            </template>
            <template #expected_date>
              <input v-model="form.expected_date" type="date" />
            </template>
            <template #warning_lead_days>
              <input v-model.number="form.warning_lead_days" type="number" min="0" step="1" />
            </template>
            <template #tax_rate>
              <input v-model.number="form.tax_rate" type="number" min="0" step="0.0001" />
            </template>
            <template #sales_orders>
              <div
                v-if="form.purchase_type === 'SALES_ORDER'"
                ref="salesOrderPickerRef"
                class="order-tag-picker document-order-tag-picker"
                @pointerdown.stop
                @mousedown.stop
                @click.stop
              >
                <label class="form-field">
                  <span>关联销售订单</span>
                  <input
                    v-model.trim="salesOrderKeyword"
                    type="text"
                    placeholder="搜索销售订单号、客户、产品、状态"
                    @focus="salesOrderPickerOpen = true"
                    @keydown.esc.prevent="salesOrderPickerOpen = false"
                  />
                </label>
                <div class="selected-order-tags">
                  <span v-for="order in selectedSalesOrders" :key="order.order_id" class="selected-lot-tag">
                    {{ order.order_no }}
                    <small>{{ order.customer_name || "-" }}</small>
                    <button type="button" class="tag-remove" aria-label="移除销售订单" @click.stop="removeSalesOrder(order.order_id)">×</button>
                  </span>
                  <span v-if="!selectedSalesOrders.length" class="empty-inline">请选择至少一张销售订单</span>
                </div>
                <div v-if="salesOrderPickerOpen" class="stock-lot-dropdown order-tag-dropdown">
                  <button
                    v-for="order in filteredSalesOrders"
                    :key="order.order_id"
                    type="button"
                    class="stock-lot-option"
                    :class="{ 'stock-lot-option-selected': isSalesOrderSelected(order.order_id) }"
                    @click.stop="toggleSalesOrder(order.order_id)"
                  >
                    <span class="lot-main">{{ order.order_no }} · {{ order.customer_name || "-" }}</span>
                    <span class="lot-meta">{{ salesOrderProductNames(order) }} · {{ formatStatusLabel(order.status) }}</span>
                    <em>{{ isSalesOrderSelected(order.order_id) ? "已选择，点击取消" : "点击选择" }}</em>
                  </button>
                  <div v-if="!filteredSalesOrders.length" class="stock-lot-empty">没有匹配的销售订单</div>
                </div>
              </div>
              <span v-else class="document-static-value">不关联销售订单</span>
            </template>
            <template #remark>
              <textarea v-model.trim="form.remark" rows="2"></textarea>
            </template>
          </DocumentGrid>

          <section class="document-form-section">
            <aside v-if="form.purchase_type === 'STOCKING' && form.target_warehouse_type === 'RAW'" class="purchase-demand-calculator document-demand-panel">
              <div class="subsection-head">
                <span class="title-with-help">
                  <strong>采购需求计算器</strong>
                  <FieldHint text="根据当前明细原材料反查产品需规，按预计成品数量和产品毛重计算原材料需求。" />
                </span>
                <span class="panel-tag">参考</span>
              </div>

              <div class="document-calculator-grid">
                <label class="form-field">
                  <span>关联采购明细</span>
                  <select v-model.number="calculator.line_index">
                    <option v-for="(_, index) in form.items" :key="index" :value="index">
                      明细 {{ index + 1 }}
                    </option>
                  </select>
                </label>

                <div class="calculator-selected-material">
                  <span>当前原材料</span>
                  <strong>{{ selectedCalculatorMaterial ? `${selectedCalculatorMaterial.item_code} · ${selectedCalculatorMaterial.item_name}` : "请先在明细中选择原材料" }}</strong>
                </div>

                <label class="form-field">
                  <span>对应产品</span>
                  <select v-model="calculator.product_key" :disabled="!calculatorProductOptions.length">
                    <option disabled value="">请选择产品</option>
                    <option v-for="option in calculatorProductOptions" :key="option.key" :value="option.key">
                      {{ option.product_code }} · {{ option.product_name }} · {{ option.version_no }}
                    </option>
                  </select>
                </label>

                <label class="form-field">
                  <span>预计成品数量</span>
                  <input v-model.number="calculator.planned_finished_qty" type="number" min="0" step="1" />
                </label>
              </div>
              <p v-if="selectedCalculatorMaterial && !calculatorProductOptions.length" class="calculator-warning">
                未在 BOM 或小程序产品清单中找到使用该原材料的产品。
              </p>
              <p v-else-if="selectedCalculatorProduct && calculatorGrossWeight <= 0" class="calculator-warning">
                已匹配到产品，但该产品未维护产品毛重，无法计算需求量。
              </p>

              <div class="calculator-result-grid">
                <article>
                  <span>产品毛重</span>
                  <strong>{{ formatWeight(calculatorGrossWeight) }}</strong>
                  <small>{{ formatTonHint(calculatorGrossWeight) }}</small>
                </article>
                <article>
                  <span>需求量</span>
                  <strong>{{ formatWeight(calculatorDemandWeight) }}</strong>
                  <small>{{ formatTonHint(calculatorDemandWeight) }}</small>
                </article>
                <article>
                  <span>可用库存</span>
                  <strong>{{ formatWeight(calculatorStockWeight) }}</strong>
                  <small>{{ formatTonHint(calculatorStockWeight) }}</small>
                </article>
                <article class="calculator-focus-result">
                  <span>最小采购量</span>
                  <strong>{{ formatWeight(calculatorMinPurchaseWeight) }}</strong>
                  <small>{{ formatTonHint(calculatorMinPurchaseWeight) }}</small>
                </article>
              </div>

              <button
                class="ghost-button"
                type="button"
                :disabled="calculatorMinPurchaseWeight <= 0 || !currentCalculatorRow"
                @click="applyCalculatorWeight"
              >
                填入当前明细采购重量
              </button>
            </aside>

            <aside v-else-if="form.purchase_type === 'STOCKING'" class="purchase-demand-calculator document-demand-panel">
              <div class="subsection-head">
                <span class="title-with-help">
                  <strong>辅料备料采购</strong>
                  <FieldHint text="辅料库用于手套、薄膜、纸箱、螺丝钉等生产消耗品；该类型只支持备料采购，不关联销售订单物料需求计算。" />
                </span>
                <span class="panel-tag">辅料库</span>
              </div>
            </aside>

            <aside v-else class="purchase-demand-calculator document-demand-panel">
              <div class="subsection-head">
                <strong>销售订单需求</strong>
                <span class="panel-tag">自动带出</span>
              </div>
              <div class="calculator-selected-material">
                <span>关联订单</span>
                <strong>{{ selectedSalesOrderSummary }}</strong>
              </div>
              <div class="calculator-result-grid">
                <article>
                  <span>物料需求行数</span>
                  <strong>{{ salesOrderDemandRows.length }}</strong>
                </article>
                <article>
                  <span>建议采购重量</span>
                  <strong>{{ formatWeight(salesOrderDemandWeight) }}</strong>
                  <small>{{ formatTonHint(salesOrderDemandWeight) }}</small>
                </article>
              </div>
              <button class="ghost-button" type="button" :disabled="!form.sales_order_ids.length || salesOrderLoading" @click="applySalesOrderPurchase">
                {{ salesOrderLoading ? "生成中..." : "重新带出采购明细" }}
              </button>
            </aside>
          </section>

          <DocumentLineTable title="采购明细" :columns="purchaseDocumentLineColumns">
            <template #actions>
              <button class="ghost-button" type="button" @click="addRow">增加一行</button>
            </template>
            <tr v-for="(item, index) in form.items" :key="index">
              <td class="document-line-index">{{ index + 1 }}</td>
              <td>
                <select v-model.number="item.material_item_id" required @change="applyMaterial(index)">
                  <option disabled value="">请选择{{ form.target_warehouse_type === "AUX" ? "辅料" : "原材料" }}</option>
                  <option v-for="material in materialOptionsForRow(item)" :key="material.item_id" :value="material.item_id">
                    {{ formatMaterialOptionLabel(material, item) }}
                  </option>
                </select>
              </td>
              <td>
                <input
                  v-if="form.target_warehouse_type === 'AUX'"
                  v-model.number="item.order_qty"
                  type="number"
                  min="0.001"
                  step="0.001"
                  required
                />
                <template v-else>
                  <input v-model.number="item.order_weight_kg" type="number" min="0.001" step="0.001" required />
                  <small class="weight-ton-hint">{{ formatTonHint(item.order_weight_kg) }}</small>
                </template>
              </td>
              <td>
                <input v-model.number="item.unit_price" type="number" min="0" step="0.0001" />
                <small v-if="form.target_warehouse_type !== 'AUX'" class="weight-ton-hint">{{ formatUnitPriceTonHint(item.unit_price) }}</small>
              </td>
              <td>
                <button
                  v-if="form.items.length > 1"
                  class="ghost-button danger-ghost table-action-button"
                  type="button"
                  @click="removeRow(index)"
                >
                  删除
                </button>
              </td>
            </tr>
          </DocumentLineTable>
        </DocumentPaper>

        <div class="drawer-form-actions purchase-document-actions">
          <button class="primary-button purchase-submit-button" type="submit" :disabled="submitting">
            {{ submitting ? "保存并归档中..." : submitButtonText }}
          </button>
        </div>
      </form>
    </FormDrawer>

    <FormDrawer
      :open="detailDrawerOpen"
      eyebrow="采购明细"
      :title="activeOrder ? `${activeOrder.po_no} · ${activeOrder.supplier_name}` : '采购明细'"
      tag="只读明细"
      size="xl"
      @close="detailDrawerOpen = false"
    >
      <TableControls
        v-model:search="itemControls.search.value"
        v-model:sort-key="itemControls.sortKey.value"
        v-model:sort-direction="itemControls.sortDirection.value"
        :sort-options="itemControls.sortOptions"
        placeholder="搜索行号、物料、状态"
      />
      <DrawerDataTable
        v-model:expanded-rows="expandedPurchaseOrderItemRows"
        :rows="paginatedItems"
        :columns="purchaseOrderItemDrawerColumns"
        row-key="purchase_order_item_id"
        empty-text="暂无采购明细"
      >
        <template #cell-status="{ row }">
          <span class="status-badge-stack">
            <StatusBadge :value="row.display_status || row.status" :text="formatStatusLabel(row.display_status || row.status)" />
            <StatusBadge v-if="row.has_return" value="HAS_RETURN" text="存在退货" />
          </span>
        </template>
        <template #detail="{ row }">
          <div class="drawer-row-detail-grid">
            <article><span>{{ purchaseTargetForItem(row) === "AUX" ? "采购数量" : "采购重量" }}</span><strong>{{ formatOrderValue(row) }}</strong></article>
            <article><span>{{ purchaseTargetForItem(row) === "AUX" ? "已收数量" : "已收重量" }}</span><strong>{{ formatReceivedValue(row) }}</strong></article>
            <article><span>退货重量</span><strong>{{ formatWeight(row.returned_weight_kg) }}</strong></article>
            <article><span>净入库重量</span><strong>{{ formatWeight(row.net_received_weight_kg) }}</strong></article>
            <article><span>单价</span><strong>{{ formatPurchaseUnitPriceDisplay(row) }}</strong></article>
            <article>
              <span>状态</span>
              <strong class="status-badge-stack">
                <StatusBadge :value="row.display_status || row.status" :text="formatStatusLabel(row.display_status || row.status)" />
                <StatusBadge v-if="row.has_return" value="HAS_RETURN" text="存在退货" />
              </strong>
            </article>
          </div>
        </template>
      </DrawerDataTable>
      <PaginationBar v-model:page="itemPage" v-model:page-size="itemPageSize" :total="filteredItems.length" />
    </FormDrawer>

    <Teleport to="body">
      <div
        v-if="hoverCard.visible"
        class="floating-info-card"
        :style="{ left: `${hoverCard.left}px`, top: `${hoverCard.top}px` }"
      >
        <strong>{{ hoverCard.title }}</strong>
        <small>{{ hoverCard.subtitle }}</small>
      </div>
    </Teleport>
  </section>
</template>

<script setup>
import { computed, onMounted, onUnmounted, reactive, ref, watch } from "vue";

import DrawerDataTable from "../components/DrawerDataTable.vue";
import FieldHint from "../components/FieldHint.vue";
import DocumentArchiveActions from "../components/documentForms/DocumentArchiveActions.vue";
import DocumentGrid from "../components/documentForms/DocumentGrid.vue";
import DocumentLineTable from "../components/documentForms/DocumentLineTable.vue";
import DocumentPaper from "../components/documentForms/DocumentPaper.vue";
import FormDrawer from "../components/FormDrawer.vue";
import PaginationBar from "../components/PaginationBar.vue";
import StatusBadge from "../components/StatusBadge.vue";
import TableControls from "../components/TableControls.vue";
import { deleteResource, downloadResource, fetchResource, openResource, postDownloadResource, postResource, putResource } from "../services/api";
import { PERSONNEL_PERMISSION_CODES, employeeOptionLabel, fetchPermissionEmployeeOptions } from "../services/employeeOptions";
import { formatPurchaseSourceTypeLabel, formatStatusLabel, formatWarehouseTypeLabel } from "../utils/dictionaries";
import { formatAmount, formatDate, formatWeight } from "../utils/formatters";
import { usePagination } from "../utils/pagination";
import { useTableControls } from "../utils/tableControls";

const suppliers = ref([]);
const employees = ref([]);
const materials = ref([]);
const boms = ref([]);
const miniappProducts = ref([]);
const stockBalances = ref([]);
const salesOrders = ref([]);
const salesOrderItems = ref([]);
const mrpDemands = ref([]);
const orders = ref([]);
const orderItems = ref([]);
const selectedOrderId = ref(null);
const selectedOrderIds = ref([]);
const feedbackMessage = ref("");
const errorMessage = ref("");
const submitting = ref(false);
const salesOrderLoading = ref(false);
const generatedSalesOrderIdsSnapshot = ref([]);
const salesOrderKeyword = ref("");
const salesOrderPickerOpen = ref(false);
const salesOrderPickerRef = ref(null);
const drawerOpen = ref(false);
const detailDrawerOpen = ref(false);
const expandedPurchaseOrderItemRows = ref([]);
const editingOrderId = ref(null);
const editingOrderNo = ref("");
const hoverCard = reactive({
  visible: false,
  title: "",
  subtitle: "",
  left: 0,
  top: 0
});

let salesOrderAutoFillTimer = null;
let salesOrderAutoFillToken = 0;

const nextWeek = new Date(Date.now() + 7 * 24 * 3600 * 1000).toISOString().slice(0, 10);

const form = reactive(buildEmptyForm());
const calculator = reactive({
  line_index: 0,
  product_key: "",
  planned_finished_qty: 0
});

const purchaseDocumentLineColumns = [
  { key: "index", label: "序号", width: "64px", class: "document-line-index" },
  { key: "material", label: "物料", width: "42%" },
  { key: "order_value", label: "采购数量/重量", width: "20%" },
  { key: "unit_price", label: "采购单价", width: "20%" },
  { key: "actions", label: "操作", width: "92px" }
];

const activeOrder = computed(() => orders.value.find((order) => order.purchase_order_id === selectedOrderId.value) || null);
const selectedOrderIdSet = computed(() => new Set(selectedOrderIds.value.map((id) => Number(id))));
const selectedSalesOrderIds = computed(() => new Set(form.sales_order_ids.map((id) => Number(id))));
const selectedSalesOrders = computed(() =>
  salesOrders.value.filter((order) => selectedSalesOrderIds.value.has(Number(order.order_id)))
);
const selectedSalesOrderNos = computed(() => new Set(selectedSalesOrders.value.map((order) => String(order.order_no || ""))));
const filteredSalesOrders = computed(() => {
  const keywords = normalizeText(salesOrderKeyword.value).split(/\s+/).filter(Boolean);
  if (!keywords.length) {
    return salesOrders.value;
  }
  return salesOrders.value.filter((order) => {
    const body = normalizeText(
      `${order.order_no || ""} ${order.customer_name || ""} ${salesOrderProductNames(order)} ${order.status || ""} ${formatStatusLabel(order.status)}`
    );
    return keywords.every((keyword) => body.includes(keyword));
  });
});
const salesOrderDemandRows = computed(() =>
  mrpDemands.value.filter(
    (demand) =>
      (!selectedSalesOrderNos.value.size || selectedSalesOrderNos.value.has(String(demand.order_no || "")))
  )
);
const salesOrderPurchaseRows = computed(() =>
  salesOrderDemandRows.value.filter((demand) => Number(demand.suggested_purchase_weight_kg || 0) > 0)
);
const salesOrderDemandWeight = computed(() =>
  salesOrderPurchaseRows.value.reduce((total, demand) => total + Number(demand.suggested_purchase_weight_kg || 0), 0)
);
const selectedSalesOrderSummary = computed(() => {
  if (!selectedSalesOrders.value.length) {
    return "请选择销售订单";
  }
  const orderNos = selectedSalesOrders.value.map((order) => order.order_no).filter(Boolean);
  return `${selectedSalesOrders.value.length}张订单：${orderNos.join("、")}`;
});

const visibleItems = computed(() => {
  if (!selectedOrderId.value) {
    return orderItems.value;
  }
  return orderItems.value.filter((item) => item.purchase_order_id === selectedOrderId.value);
});
const currentCalculatorRow = computed(() => form.items[calculator.line_index] || null);
const calculatorMaterialId = computed(() => Number(currentCalculatorRow.value?.material_item_id || 0));
const selectedCalculatorMaterial = computed(() =>
  materials.value.find((item) => Number(item.item_id) === calculatorMaterialId.value) || null
);
const calculatorProductOptions = computed(() => {
  if (!calculatorMaterialId.value) {
    return [];
  }
  const options = [];
  const seen = new Set();
  boms.value.forEach((bom) => {
    (bom.items || [])
      .filter((item) => Number(item.material_item_id) === calculatorMaterialId.value)
      .forEach((item) => {
        const key = `${bom.bom_id}-${item.bom_item_id || item.seq_no}`;
        if (seen.has(key)) {
          return;
        }
        seen.add(key);
        options.push({
          key,
          source: "BOM",
          bom_id: bom.bom_id,
          bom_code: bom.bom_code,
          product_item_id: bom.product_item_id,
          product_code: bom.product_code,
          product_name: bom.product_name,
          version_no: bom.version_no,
          gross_weight_per_piece_kg: Number(item.gross_weight_per_piece_kg || 0)
        });
      });
  });
  miniappProducts.value
    .filter((product) => miniappMaterialMatches(product, selectedCalculatorMaterial.value))
    .forEach((product) => {
      const matchedBom = findBomForMiniappProduct(product);
      const matchedBomItem = matchedBom?.items?.find((item) => bomItemMatchesMaterial(item, selectedCalculatorMaterial.value));
      const key = `miniapp-${product.attendance_point_name || ""}-${product.project_no || ""}-${product.product_name || ""}`;
      if (seen.has(key)) {
        return;
      }
      seen.add(key);
      options.push({
        key,
        source: "MINIAPP",
        attendance_point_name: product.attendance_point_name || "",
        bom_id: matchedBom?.bom_id || null,
        bom_code: matchedBom?.bom_code || null,
        product_item_id: matchedBom?.product_item_id || null,
        product_code: matchedBom?.product_code || product.project_no || "小程序项目",
        product_name: product.product_name,
        version_no: matchedBom?.version_no || `小程序清单${product.attendance_point_name ? ` · ${product.attendance_point_name}` : ""}`,
        gross_weight_per_piece_kg: pickNumber(
          product.product_gross_weight_kg,
          matchedBomItem?.gross_weight_per_piece_kg,
          matchedBom?.items?.[0]?.gross_weight_per_piece_kg,
          0
        )
      });
    });
  return options.sort((left, right) => {
    const nameCompare = String(left.product_name || "").localeCompare(String(right.product_name || ""), "zh-CN");
    return nameCompare || String(left.version_no || "").localeCompare(String(right.version_no || ""), "zh-CN");
  });
});
const selectedCalculatorProduct = computed(
  () => calculatorProductOptions.value.find((item) => item.key === calculator.product_key) || calculatorProductOptions.value[0] || null
);
const calculatorGrossWeight = computed(() => Number(selectedCalculatorProduct.value?.gross_weight_per_piece_kg || 0));
const calculatorDemandWeight = computed(() =>
  Number(calculator.planned_finished_qty || 0) * calculatorGrossWeight.value
);
const calculatorStockWeight = computed(() =>
  stockBalances.value
    .filter((item) => Number(item.item_id) === calculatorMaterialId.value)
    .reduce((total, item) => total + Number(item.weight_available_kg || 0), 0)
);
const calculatorMinPurchaseWeight = computed(() =>
  Math.max(calculatorDemandWeight.value - calculatorStockWeight.value, 0)
);
const purchaseOrderNoPreview = computed(() => buildNextPurchaseOrderNo(orders.value));
const displayPurchaseOrderNo = computed(() => editingOrderId.value ? editingOrderNo.value : purchaseOrderNoPreview.value);
const orderDrawerTitle = computed(() => editingOrderId.value ? "编辑采购订单" : "新增采购订单");
const orderDrawerDescription = computed(() =>
  editingOrderId.value ? "未锁单采购订单可以调整供应商、预计到货和采购明细；锁单后不能再修改。" : "选择供应商和采购明细，系统按仓库口径计算采购金额。"
);
const submitButtonText = computed(() => editingOrderId.value ? "更新并生成PDF归档" : "保存并生成PDF归档");
const purchaseDocumentHeaderFields = computed(() => [
  { key: "po_no", label: "采购单号", value: displayPurchaseOrderNo.value },
  { key: "target_warehouse_type", label: "到货仓库", value: purchaseTargetLabel(form.target_warehouse_type) },
  { key: "purchase_type", label: "采购方式", value: form.purchase_type === "SALES_ORDER" ? "销售订单采购" : "备料采购" },
  { key: "supplier", label: "供应商", value: form.supplier_id || "" },
  { key: "purchaser", label: "采购员", value: form.purchaser_employee_id || "" },
  { key: "expected_date", label: "预计到货", value: form.expected_date || "" },
  { key: "warning_lead_days", label: "提前预警(天)", value: form.warning_lead_days },
  { key: "tax_rate", label: "税率", value: form.tax_rate },
  { key: "sales_orders", label: "关联销售订单", value: selectedSalesOrderSummary.value, class: "document-grid-cell-wide" },
  { key: "remark", label: "备注", value: form.remark || "-", class: "document-grid-cell-wide" }
]);
const orderControls = useTableControls(orders, {
  searchFields: [
    "po_no",
    "target_warehouse_type",
    (row) => purchaseTargetLabel(row.target_warehouse_type),
    (row) => formatPurchaseSourceTypeLabel(row.source_type),
    "source_order_nos",
    "supplier_name",
    "status",
    "display_status",
    (row) => isPurchaseWarning(row) ? "到货预警 提前预警 黄色提醒" : "",
    (row) => row.has_return ? "存在退货 HAS_RETURN" : ""
  ],
  sortOptions: [
    { key: "po_no", label: "采购单号" },
    { key: "target_warehouse_type", label: "采购仓库" },
    { key: "source_type", label: "采购来源" },
    { key: "supplier_name", label: "供应商" },
    { key: "expected_date", label: "预计到货" },
    { key: "warning_lead_days", label: "提前预警" },
    { key: "total_amount", label: "总金额" },
    { key: "total_order_weight_kg", label: "订单量" },
    { key: "total_received_weight_kg", label: "已收量" },
    { key: "display_status", label: "状态" }
  ],
  defaultSortKey: "po_no",
  defaultSortDirection: "desc"
});
const filteredOrders = orderControls.rows;
const itemControls = useTableControls(visibleItems, {
  searchFields: ["line_no", "material_name", "status", "display_status", (row) => row.has_return ? "存在退货 HAS_RETURN" : ""],
  sortOptions: [
    { key: "line_no", label: "行号" },
    { key: "material_name", label: "原材料" },
    { key: "order_weight_kg", label: "采购量" },
    { key: "received_weight_kg", label: "已收量" },
    { key: "returned_weight_kg", label: "退货重量" },
    { key: "net_received_weight_kg", label: "净入库重量" },
    { key: "unit_price", label: "单价" },
    { key: "display_status", label: "状态" }
  ],
  defaultSortKey: "line_no",
  defaultSortDirection: "asc"
});
const filteredItems = itemControls.rows;
const purchaseOrderItemDrawerColumns = computed(() => [
  { key: "line_no", label: "行号", type: "number", width: "70px" },
  { key: "material_name", label: "物料", type: "longText", width: "28%" },
  { key: "order_weight_kg", label: "采购量", type: "number", width: "112px", format: (_value, row) => formatOrderValue(row) },
  { key: "received_weight_kg", label: "已收量", type: "number", width: "112px", format: (_value, row) => formatReceivedValue(row) },
  { key: "unit_price", label: "单价", type: "number", width: "112px", format: (_value, row) => formatPurchaseUnitPriceDisplay(row) },
  { key: "status", label: "状态", type: "status", width: "128px", format: (_value, row) => formatStatusLabel(row.display_status || row.status) },
  { key: "returned_weight_kg", label: "退货重量", detailOnly: true, format: (value) => formatWeight(value) },
  { key: "net_received_weight_kg", label: "净入库重量", detailOnly: true, format: (value) => formatWeight(value) }
]);
const {
  page: orderPage,
  pageSize: orderPageSize,
  rows: paginatedOrders
} = usePagination(filteredOrders);
const visibleOrderIds = computed(() => paginatedOrders.value.map((order) => Number(order.purchase_order_id)));
const allVisibleOrdersSelected = computed(
  () => visibleOrderIds.value.length > 0 && visibleOrderIds.value.every((orderId) => selectedOrderIdSet.value.has(orderId))
);
const someVisibleOrdersSelected = computed(() => visibleOrderIds.value.some((orderId) => selectedOrderIdSet.value.has(orderId)));
const {
  page: itemPage,
  pageSize: itemPageSize,
  rows: paginatedItems
} = usePagination(filteredItems);

watch(
  calculatorProductOptions,
  (options) => {
    if (!options.some((item) => item.key === calculator.product_key)) {
      calculator.product_key = options[0]?.key || "";
    }
  },
  { immediate: true }
);

watch(
  () => normalizedSalesOrderIds(form.sales_order_ids).join(","),
  () => {
    if (!drawerOpen.value || form.purchase_type !== "SALES_ORDER") {
      return;
    }
    scheduleSalesOrderPurchaseAutoFill();
  }
);

function buildItemRow() {
  return {
    source_demand_id: null,
    material_item_id: "",
    order_qty: 0,
    order_weight_kg: 0,
    unit_price: 0
  };
}

function buildEmptyForm() {
  return {
    target_warehouse_type: "RAW",
    purchase_type: "STOCKING",
    sales_order_ids: [],
    supplier_id: "",
    purchaser_employee_id: "",
    expected_date: nextWeek,
    warning_lead_days: 0,
    tax_rate: 0,
    remark: "",
    items: [buildItemRow()]
  };
}

function buildNextPurchaseOrderNo(rows) {
  const year = String(new Date().getFullYear());
  const prefix = `采购${year}`;
  let maxNo = 0;
  (rows || []).forEach((order) => {
    const match = String(order?.po_no || "").trim().match(new RegExp(`^${prefix}-(\\d{5})$`));
    if (match) {
      maxNo = Math.max(maxNo, Number(match[1]));
    }
  });
  return `${prefix}-${String(maxNo + 1).padStart(5, "0")}`;
}

function resetForm() {
  cancelSalesOrderPurchaseAutoFill();
  generatedSalesOrderIdsSnapshot.value = [];
  Object.assign(form, buildEmptyForm());
  calculator.line_index = 0;
  calculator.product_key = "";
  calculator.planned_finished_qty = 0;
  salesOrderKeyword.value = "";
  salesOrderPickerOpen.value = false;
}

function openCreateDrawer() {
  editingOrderId.value = null;
  editingOrderNo.value = "";
  resetForm();
  drawerOpen.value = true;
}

function closeOrderDrawer() {
  drawerOpen.value = false;
  editingOrderId.value = null;
  editingOrderNo.value = "";
  resetForm();
}

function normalizeInputDate(value) {
  if (!value) {
    return "";
  }
  return String(value).slice(0, 10);
}

function inferSalesOrderIds(order) {
  const explicitIds = Array.isArray(order?.sales_order_ids)
    ? order.sales_order_ids.map((id) => Number(id)).filter(Boolean)
    : [];
  if (explicitIds.length) {
    return Array.from(new Set(explicitIds));
  }
  const sourceNos = String(order?.source_order_nos || "")
    .split(/[,，、]/)
    .map((item) => item.trim())
    .filter(Boolean);
  if (!sourceNos.length) {
    return [];
  }
  return salesOrders.value
    .filter((salesOrder) => sourceNos.includes(String(salesOrder.order_no)))
    .map((salesOrder) => Number(salesOrder.order_id))
    .filter(Boolean);
}

function openEditDrawer(order) {
  if (!canEditOrder(order)) {
    return;
  }
  resetForm();
  editingOrderId.value = Number(order.purchase_order_id);
  editingOrderNo.value = order.po_no;
  form.purchase_type = order.source_type === "SALES_ORDER" ? "SALES_ORDER" : "STOCKING";
  form.target_warehouse_type = normalizePurchaseTargetType(order.target_warehouse_type);
  if (form.target_warehouse_type === "AUX") {
    form.purchase_type = "STOCKING";
  }
  form.sales_order_ids = form.purchase_type === "SALES_ORDER" ? inferSalesOrderIds(order) : [];
  form.supplier_id = Number(order.supplier_id);
  form.purchaser_employee_id = order.purchaser_employee_id ? Number(order.purchaser_employee_id) : "";
  form.expected_date = normalizeInputDate(order.expected_date);
  form.warning_lead_days = Number(order.warning_lead_days || 0);
  form.tax_rate = Number(order.tax_rate || 0);
  form.remark = order.remark || "";
  const rows = orderMaterialItems(order.purchase_order_id);
  form.items.splice(
    0,
    form.items.length,
    ...(rows.length
      ? rows.map((item) => ({
          source_demand_id: item.source_demand_id ? Number(item.source_demand_id) : null,
          material_item_id: Number(item.material_item_id),
          order_qty: Number(item.order_qty || 0),
          order_weight_kg: Number(item.order_weight_kg || 0),
          unit_price: Number(item.unit_price || 0),
          remark: item.remark || null
        }))
      : [buildItemRow()])
  );
  generatedSalesOrderIdsSnapshot.value = form.purchase_type === "SALES_ORDER" ? normalizedSalesOrderIds(form.sales_order_ids) : [];
  calculator.line_index = 0;
  drawerOpen.value = true;
}

function openDetailDrawer(order) {
  selectedOrderId.value = order.purchase_order_id;
  expandedPurchaseOrderItemRows.value = [];
  detailDrawerOpen.value = true;
}

function splitSourceOrderNos(order) {
  return String(order?.source_order_nos || "")
    .split(/[,，、]/)
    .map((item) => item.trim())
    .filter(Boolean);
}

function formatQty(value) {
  return Number(value || 0).toLocaleString("zh-CN", {
    maximumFractionDigits: 3
  });
}

function purchaseTargetForItem(item) {
  const order = orders.value.find((row) => Number(row.purchase_order_id) === Number(item?.purchase_order_id));
  return normalizePurchaseTargetType(order?.target_warehouse_type);
}

function formatOrderTotal(order) {
  return normalizePurchaseTargetType(order?.target_warehouse_type) === "AUX"
    ? `${formatQty(order.total_order_qty)} 件`
    : formatWeight(order.total_order_weight_kg);
}

function formatReceivedTotal(order) {
  return normalizePurchaseTargetType(order?.target_warehouse_type) === "AUX"
    ? `${formatQty(order.total_received_qty)} 件`
    : formatWeight(order.total_received_weight_kg);
}

function salesOrderProductSummary(orderNo) {
  const salesOrder = salesOrders.value.find((item) => String(item.order_no || "") === String(orderNo));
  const rows = salesOrderItems.value.filter(
    (item) =>
      String(item.order_no || "") === String(orderNo) ||
      (salesOrder && Number(item.sales_order_id) === Number(salesOrder.order_id))
  );
  if (!rows.length) {
    return "产品信息待同步";
  }
  return rows
    .map((item) => {
      const product = item.product_code ? `${item.product_name}（${item.product_code}）` : item.product_name;
      return `${product} × ${formatQty(item.order_qty)}件`;
    })
    .join("、");
}

function salesOrderProductNames(order) {
  const explicitNames = String(order?.product_names || "").trim();
  if (explicitNames) {
    return explicitNames;
  }
  const rows = salesOrderItems.value.filter(
    (item) =>
      String(item.order_no || "") === String(order?.order_no || "") ||
      Number(item.sales_order_id) === Number(order?.order_id)
  );
  const names = Array.from(new Set(rows.map((item) => String(item.product_name || "").trim()).filter(Boolean)));
  return names.length ? names.join("、") : "-";
}

function normalizedSalesOrderIds(ids) {
  return Array.from(new Set((ids || []).map((id) => Number(id)).filter(Boolean))).sort((left, right) => left - right);
}

function sameSalesOrderIds(left, right) {
  const normalizedLeft = normalizedSalesOrderIds(left);
  const normalizedRight = normalizedSalesOrderIds(right);
  return normalizedLeft.length === normalizedRight.length && normalizedLeft.every((id, index) => id === normalizedRight[index]);
}

function salesOrderLabel(orderId) {
  const order = salesOrders.value.find((item) => Number(item.order_id) === Number(orderId));
  return order?.order_no ? `${order.order_no}` : `销售订单ID ${orderId}`;
}

function clearGeneratedSalesOrderPurchaseRows() {
  generatedSalesOrderIdsSnapshot.value = [];
  mrpDemands.value = [];
  form.items.splice(0, form.items.length, buildItemRow());
  calculator.line_index = 0;
}

function cancelSalesOrderPurchaseAutoFill() {
  if (salesOrderAutoFillTimer) {
    clearTimeout(salesOrderAutoFillTimer);
    salesOrderAutoFillTimer = null;
  }
  salesOrderAutoFillToken += 1;
}

function scheduleSalesOrderPurchaseAutoFill() {
  const selectedIds = normalizedSalesOrderIds(form.sales_order_ids);
  cancelSalesOrderPurchaseAutoFill();
  if (!drawerOpen.value || form.purchase_type !== "SALES_ORDER") {
    return;
  }
  if (!selectedIds.length) {
    clearGeneratedSalesOrderPurchaseRows();
    feedbackMessage.value = "";
    errorMessage.value = "";
    return;
  }
  if (sameSalesOrderIds(selectedIds, generatedSalesOrderIdsSnapshot.value)) {
    return;
  }
  const token = salesOrderAutoFillToken;
  salesOrderAutoFillTimer = setTimeout(() => {
    salesOrderAutoFillTimer = null;
    if (token !== salesOrderAutoFillToken) {
      return;
    }
    void applySalesOrderPurchase({ automatic: true });
  }, 180);
}

function isSalesOrderSelected(orderId) {
  return selectedSalesOrderIds.value.has(Number(orderId));
}

function toggleSalesOrder(orderId) {
  const id = Number(orderId);
  if (!id) {
    return;
  }
  if (isSalesOrderSelected(id)) {
    removeSalesOrder(id);
    return;
  }
  form.sales_order_ids = [...form.sales_order_ids.map((value) => Number(value)).filter(Boolean), id];
  salesOrderKeyword.value = "";
  salesOrderPickerOpen.value = false;
}

function removeSalesOrder(orderId) {
  form.sales_order_ids = form.sales_order_ids.filter((value) => Number(value) !== Number(orderId));
  salesOrderPickerOpen.value = false;
}

function sourceCardsForOrder(order) {
  if (String(order?.source_type || "").toUpperCase() === "SALES_ORDER") {
    const orderNos = splitSourceOrderNos(order);
    if (!orderNos.length) {
      return [
        {
          key: `${order.purchase_order_id}-sales-fallback`,
          title: formatPurchaseSourceTypeLabel("SALES_ORDER"),
          subtitle: "产品信息待同步"
        }
      ];
    }
    return orderNos.map((orderNo) => ({
      key: `${order.purchase_order_id}-${orderNo}`,
      title: orderNo,
      subtitle: salesOrderProductSummary(orderNo)
    }));
  }
  return [
    {
      key: `${order.purchase_order_id}-stocking`,
      title: formatPurchaseSourceTypeLabel(order?.source_type || "STOCKING"),
      subtitle: `采购时间 ${formatDate(order.order_date)}`
    }
  ];
}

function normalizePurchaseTargetType(value) {
  return String(value || "RAW").toUpperCase() === "AUX" ? "AUX" : "RAW";
}

function purchaseTargetLabel(value) {
  return formatWarehouseTypeLabel(normalizePurchaseTargetType(value));
}

function isPurchaseWarning(order) {
  return Boolean(order?.is_warning_active);
}

function showHoverCard(event, title, subtitle) {
  const rect = event.currentTarget.getBoundingClientRect();
  const maxLeft = Math.max(12, window.innerWidth - 560);
  hoverCard.title = title || "-";
  hoverCard.subtitle = subtitle || "-";
  hoverCard.left = Math.min(Math.max(12, rect.left), maxLeft);
  hoverCard.top = Math.min(Math.max(12, rect.bottom + 8), Math.max(12, window.innerHeight - 120));
  hoverCard.visible = true;
}

function hideHoverCard() {
  hoverCard.visible = false;
}

function handleSalesOrderPickerPointerDown(event) {
  if (!salesOrderPickerRef.value?.contains(event.target)) {
    salesOrderPickerOpen.value = false;
  }
}

function canLockOrder(order) {
  return String(order?.status || "").toUpperCase() === "OPEN";
}

function canEditOrder(order) {
  return String(order?.status || "").toUpperCase() === "OPEN";
}

function canDeleteOrder(order) {
  return canEditOrder(order);
}

function lockOrderTitle(order) {
  if (canLockOrder(order)) {
    return "锁单后表示已通知供应商供货，采购订单不能再修改";
  }
  return "只有未开始的采购订单可以锁单";
}

function editOrderTitle(order) {
  if (canEditOrder(order)) {
    return "未锁单采购订单可以修改";
  }
  return "采购订单已锁单或已进入后续流程，不能修改";
}

function deleteOrderTitle(order) {
  if (canDeleteOrder(order)) {
    return "未锁单采购订单可以删除";
  }
  return "采购订单已锁单或已进入后续流程，不能删除";
}

function getSupplier(supplierId) {
  return suppliers.value.find((item) => Number(item.id) === Number(supplierId)) || null;
}

function orderMaterialItems(purchaseOrderId) {
  return orderItems.value.filter((item) => Number(item.purchase_order_id) === Number(purchaseOrderId));
}

function materialPerformanceRequirement(item) {
  const fromItem = String(item?.performance_requirement || "").trim();
  if (fromItem) {
    return fromItem;
  }
  if (item?.item_code || item?.item_name) {
    const fromMaterial = String(item?.remark || item?.quality_rule || "").trim();
    if (fromMaterial) {
      return fromMaterial;
    }
  }
  const materialId = item?.material_item_id ?? item?.item_id;
  const material = materials.value.find((row) => Number(row.item_id) === Number(materialId));
  return String(material?.remark || material?.quality_rule || "").trim();
}

function formatMaterialOptionLabel(material, item) {
  const labelParts = [
    material.item_code,
    material.item_name,
    material.material_grade || "未维护材质",
    material.specification || "未维护规格"
  ];
  if (form.target_warehouse_type !== "AUX") {
    const performance = materialPerformanceRequirement(material) || "未维护";
    labelParts.push(`性能要求：${performance}`);
  }
  return labelParts.filter(Boolean).join(" · ");
}

function materialChipSubtitle(item) {
  return `${formatOrderValue(item)} / 已收 ${formatReceivedValue(item)} / ${formatPurchaseUnitPriceDisplay(item)}`;
}

function materialHoverSubtitle(item) {
  const performance = materialPerformanceRequirement(item) || "未维护";
  return `${formatOrderValue(item)} / 已收 ${formatReceivedValue(item)} / ${formatPurchaseUnitPriceDisplay(item)} / 性能要求：${performance}`;
}

function toggleOrderSelection(orderId) {
  const normalizedId = Number(orderId);
  if (selectedOrderIdSet.value.has(normalizedId)) {
    selectedOrderIds.value = selectedOrderIds.value.filter((id) => Number(id) !== normalizedId);
    return;
  }
  selectedOrderIds.value = [...selectedOrderIds.value, normalizedId];
}

function toggleVisibleOrders() {
  if (allVisibleOrdersSelected.value) {
    selectedOrderIds.value = selectedOrderIds.value.filter((id) => !visibleOrderIds.value.includes(Number(id)));
    return;
  }
  selectedOrderIds.value = Array.from(new Set([...selectedOrderIds.value, ...visibleOrderIds.value].map((id) => Number(id))));
}

function selectedContractOrders() {
  const selectedSet = selectedOrderIdSet.value;
  return orders.value.filter((order) => selectedSet.has(Number(order.purchase_order_id)));
}

function escapeHtml(value) {
  return String(value ?? "")
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

function normalizeContractText(value, fallback = "-") {
  const text = String(value ?? "").trim();
  return text || fallback;
}

function currentDateText() {
  const now = new Date();
  const pad = (value) => String(value).padStart(2, "0");
  return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
}

function currentTimestampText() {
  const now = new Date();
  const pad = (value) => String(value).padStart(2, "0");
  return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
}

function buildPurchaseContractNo(contractOrders) {
  const firstPoNo = String(contractOrders[0]?.po_no || "PO").replace(/[^a-zA-Z0-9]/g, "").slice(-8) || "PO";
  return `JH-PC-${currentTimestampText()}-${firstPoNo}`;
}

function buildPurchaseContractLineRows(contractOrders) {
  return contractOrders.flatMap((order) =>
    orderMaterialItems(order.purchase_order_id).map((item) => ({
      po_no: order.po_no,
      target_warehouse_type: order.target_warehouse_type,
      expected_date: order.expected_date,
      material_code: item.material_code,
      material_name: item.material_name,
      specification: item.specification,
      material_grade: item.material_grade,
      performance_requirement: materialPerformanceRequirement(item),
      order_qty: Number(item.order_qty || 0),
      order_weight_kg: Number(item.order_weight_kg || 0),
      received_weight_kg: Number(item.received_weight_kg || 0),
      unit_price: Number(item.unit_price || 0),
      line_amount: Number(item.line_amount || 0),
      status: item.status
    }))
  );
}

function renderPurchaseContractHtml(contractOrders) {
  const supplier = getSupplier(contractOrders[0].supplier_id);
  const lines = buildPurchaseContractLineRows(contractOrders);
  const totalAmount = lines.reduce((total, item) => total + Number(item.line_amount || 0), 0);
  const totalQty = lines.reduce((total, item) => total + Number(item.order_qty || 0), 0);
  const totalWeight = lines.reduce((total, item) => total + Number(item.order_weight_kg || 0), 0);
  const contractNo = buildPurchaseContractNo(contractOrders);
  const poNos = contractOrders.map((order) => order.po_no).join("、");
  const warehouseLabels = Array.from(new Set(contractOrders.map((order) => purchaseTargetLabel(order.target_warehouse_type)))).join("、");
  const expectedDates = Array.from(new Set(contractOrders.map((order) => formatDate(order.expected_date)).filter((dateText) => dateText !== "-"))).join("、");
  const lineRowsHtml = lines
    .map(
      (item, index) => `
        <tr>
          <td>${index + 1}</td>
          <td>${escapeHtml(item.po_no)}</td>
          <td>${escapeHtml(purchaseTargetLabel(item.target_warehouse_type))}</td>
	          <td>${escapeHtml(item.material_code || "-")}</td>
	          <td>${escapeHtml(item.material_name || "-")}</td>
	          <td>${escapeHtml(item.material_grade || "-")}</td>
	          <td>${escapeHtml(item.specification || "-")}</td>
	          <td>${escapeHtml(item.performance_requirement || "-")}</td>
	          <td class="number">${escapeHtml(item.target_warehouse_type === "AUX" ? `${formatQty(item.order_qty)} 件` : formatWeight(item.order_weight_kg))}</td>
	          <td class="number">${escapeHtml(item.target_warehouse_type === "AUX" ? `¥${formatAmount(item.unit_price)}/件` : formatUnitPriceDisplay(item.unit_price))}</td>
          <td class="number">¥${escapeHtml(formatAmount(item.line_amount))}</td>
          <td>${escapeHtml(formatDate(item.expected_date))}</td>
        </tr>`
    )
    .join("");

  return `<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8" />
  <title>${escapeHtml(contractNo)} 采购合同</title>
  <style>
    * { box-sizing: border-box; }
    body { margin: 0; background: #eef3f8; color: #1f2937; font-family: "Songti SC", "SimSun", "Microsoft YaHei", serif; }
    .toolbar { position: sticky; top: 0; z-index: 5; display: flex; justify-content: flex-end; gap: 10px; padding: 12px 24px; background: rgba(255,255,255,.92); border-bottom: 1px solid #d9e2ec; }
    .toolbar button { border: 1px solid #2563eb; border-radius: 8px; background: #2563eb; color: #fff; padding: 8px 16px; cursor: pointer; font-weight: 700; }
    .contract-page { width: 210mm; min-height: 297mm; margin: 18px auto; padding: 20mm 18mm; background: #fff; box-shadow: 0 18px 50px rgba(15, 23, 42, .16); }
    h1 { margin: 0 0 10px; text-align: center; letter-spacing: 10px; font-size: 28px; }
    .contract-no { text-align: right; color: #475569; margin-bottom: 22px; }
    .meta-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 24px; margin-bottom: 18px; line-height: 1.8; }
    .section-title { margin: 22px 0 10px; padding-left: 10px; border-left: 4px solid #2563eb; font-weight: 800; font-size: 16px; }
    table { width: 100%; border-collapse: collapse; margin: 8px 0 14px; font-size: 12px; }
    th, td { border: 1px solid #94a3b8; padding: 7px 6px; vertical-align: middle; }
    th { background: #eaf2ff; text-align: center; }
    .number { text-align: right; white-space: nowrap; }
    .summary { display: flex; justify-content: flex-end; gap: 28px; margin: 12px 0 20px; font-weight: 800; }
    .terms { margin: 0; padding-left: 22px; line-height: 1.9; }
    .signature { display: grid; grid-template-columns: 1fr 1fr; gap: 46px; margin-top: 38px; }
    .signature-box { min-height: 118px; border-top: 1px solid #334155; padding-top: 12px; line-height: 2; }
    .muted { color: #64748b; }
    @media print {
      body { background: #fff; }
      .toolbar { display: none; }
      .contract-page { width: auto; min-height: auto; margin: 0; padding: 0; box-shadow: none; }
      @page { size: A4; margin: 18mm 14mm; }
    }
  </style>
</head>
<body>
  <div class="toolbar">
    <button onclick="window.print()">打印 / 另存为 PDF</button>
  </div>
  <main class="contract-page">
    <h1>采购合同</h1>
    <div class="contract-no">合同编号：${escapeHtml(contractNo)}</div>

    <div class="meta-grid">
      <div><strong>甲方（采购方）：</strong>${escapeHtml("嘉恒智能五金")}</div>
      <div><strong>乙方（供应方）：</strong>${escapeHtml(normalizeContractText(supplier?.supplier_name))}</div>
      <div><strong>乙方联系人：</strong>${escapeHtml(normalizeContractText(supplier?.contact_name))}</div>
      <div><strong>乙方电话：</strong>${escapeHtml(normalizeContractText(supplier?.contact_phone))}</div>
      <div><strong>乙方地址：</strong>${escapeHtml(normalizeContractText(supplier?.address))}</div>
      <div><strong>合同日期：</strong>${escapeHtml(currentDateText())}</div>
      <div><strong>来源采购订单：</strong>${escapeHtml(poNos)}</div>
      <div><strong>采购到货库：</strong>${escapeHtml(warehouseLabels)}</div>
      <div><strong>预计到货：</strong>${escapeHtml(normalizeContractText(expectedDates || "按采购订单明细执行"))}</div>
    </div>

    <div class="section-title">一、采购物料与价格</div>
    <table>
      <thead>
        <tr>
          <th>序号</th>
          <th>采购单号</th>
          <th>到货库</th>
          <th>物料编码</th>
	          <th>物料名称</th>
	          <th>材质</th>
	          <th>规格</th>
	          <th>性能要求</th>
	          <th>重量</th>
	          <th>单价(元/kg / 元/t)</th>
          <th>金额</th>
          <th>预计到货</th>
        </tr>
      </thead>
      <tbody>${lineRowsHtml}</tbody>
    </table>
    <div class="summary">
      <span>合计数量：${escapeHtml(formatQty(totalQty))} 件</span>
      <span>合计重量：${escapeHtml(formatWeight(totalWeight))}</span>
      <span>合同金额：¥${escapeHtml(formatAmount(totalAmount))}</span>
    </div>

    <div class="section-title">二、基础条款</div>
    <ol class="terms">
      <li>乙方应按本合同载明的物料编码、名称、材质、规格、重量和到货时间供货。</li>
      <li>采购单价按系统采购订单中的元/kg 单价生成；系统未维护税率时，默认按税前金额处理。</li>
      <li>到货后甲方按实际入库重量、质量检验结果和双方确认的结算规则进行验收与结算。</li>
	      <li>若到货重量、材质、规格或质量与约定不符，甲方有权要求乙方补发、换货、退货或协商扣款。</li>
      <li>付款方式、账期、违约责任等商务条款，待双方确认正式合同模板后补充完善。</li>
      <li>本合同为系统基础模板生成文件，正式签署前应由双方业务负责人复核采购内容、金额、交期和条款。</li>
    </ol>

    <div class="signature">
      <div class="signature-box">
        <strong>甲方（盖章）：</strong><br />
        授权代表：<br />
        日期：
      </div>
      <div class="signature-box">
        <strong>乙方（盖章）：</strong><br />
        授权代表：<br />
        日期：
      </div>
    </div>
    <p class="muted">注：该合同由嘉恒智能五金 ERP 按当前采购订单数据自动生成。</p>
  </main>
</body>
</html>`;
}

function generatePurchaseContract() {
  feedbackMessage.value = "";
  errorMessage.value = "";
  const contractOrders = selectedContractOrders();
  if (!contractOrders.length) {
    errorMessage.value = "请先勾选需要生成合同的采购订单";
    return;
  }
  const supplierIds = Array.from(new Set(contractOrders.map((order) => Number(order.supplier_id))));
  if (supplierIds.length > 1) {
    errorMessage.value = "采购合同只能按同一供应商生成，请不要混选不同供应商的采购订单";
    return;
  }
  const lines = buildPurchaseContractLineRows(contractOrders);
  if (!lines.length) {
    errorMessage.value = "所选采购订单没有采购明细，无法生成合同";
    return;
  }
  const contractWindow = window.open("", "_blank");
  if (!contractWindow) {
    errorMessage.value = "浏览器阻止了合同窗口，请允许弹窗后重试";
    return;
  }
  contractWindow.document.open();
  contractWindow.document.write(renderPurchaseContractHtml(contractOrders));
  contractWindow.document.close();
  feedbackMessage.value = `已生成 ${contractOrders.length} 张采购订单的基础采购合同`;
}

async function previewDocumentArchive(typeKey, businessId) {
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    await openResource(`/document-archives/${typeKey}/${businessId}/latest/preview`);
  } catch (error) {
    errorMessage.value = error.message || "PDF归档预览失败";
  }
}

async function downloadDocumentArchive(typeKey, businessId, fallbackFilename) {
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    await downloadResource(`/document-archives/${typeKey}/${businessId}/latest/download`, fallbackFilename);
    feedbackMessage.value = "PDF归档已下载";
  } catch (error) {
    errorMessage.value = error.message || "PDF归档下载失败";
  }
}

async function regenerateDocumentArchive(typeKey, businessId) {
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    const result = await postResource(`/document-archives/${typeKey}/${businessId}/generate`, {});
    feedbackMessage.value = result.message || "PDF归档已重新生成";
    await loadAll();
  } catch (error) {
    errorMessage.value = error.message || "PDF归档重新生成失败";
  }
}

async function batchDownloadPurchaseArchives() {
  feedbackMessage.value = "";
  errorMessage.value = "";
  const businessIds = selectedOrderIds.value.map((id) => Number(id)).filter(Boolean);
  if (!businessIds.length) {
    errorMessage.value = "请先勾选需要下载PDF归档的采购订单";
    return;
  }

  try {
    await postDownloadResource("/document-archives/batch-download", { document_type: "purchase-order", business_ids: businessIds }, "采购订单归档.zip");
    feedbackMessage.value = `已下载 ${businessIds.length} 张采购订单PDF归档`;
  } catch (error) {
    errorMessage.value = error.message || "采购订单PDF归档批量下载失败";
  }
}

function addRow() {
  form.items.push(buildItemRow());
  calculator.line_index = form.items.length - 1;
}

function removeRow(index) {
  form.items.splice(index, 1);
  if (calculator.line_index >= form.items.length) {
    calculator.line_index = Math.max(form.items.length - 1, 0);
  } else if (calculator.line_index > index) {
    calculator.line_index -= 1;
  }
}

function applyMaterial(index) {
  const row = form.items[index];
  calculator.line_index = index;
  if (row) {
    row.source_demand_id = null;
  }
}

function materialForDemand(demand) {
  return materials.value.find((item) => Number(item.item_id) === Number(demand.material_item_id)) || null;
}

function applyPurchaseType() {
  cancelSalesOrderPurchaseAutoFill();
  feedbackMessage.value = "";
  errorMessage.value = "";
  generatedSalesOrderIdsSnapshot.value = [];
  mrpDemands.value = [];
  if (form.target_warehouse_type === "AUX" && form.purchase_type === "SALES_ORDER") {
    form.purchase_type = "STOCKING";
  }
  if (form.purchase_type === "STOCKING") {
    form.sales_order_ids = [];
    salesOrderKeyword.value = "";
    salesOrderPickerOpen.value = false;
    form.items.splice(0, form.items.length, buildItemRow());
    return;
  }
  form.items.splice(0, form.items.length, buildItemRow());
}

function setPurchaseType(type) {
  if (type === "SALES_ORDER" && form.target_warehouse_type !== "RAW") {
    return;
  }
  if (form.purchase_type === type) {
    return;
  }
  form.purchase_type = type;
  applyPurchaseType();
}

function applyTargetWarehouseType() {
  feedbackMessage.value = "";
  errorMessage.value = "";
  if (form.target_warehouse_type === "AUX") {
    form.purchase_type = "STOCKING";
  }
  applyPurchaseType();
}

function setTargetWarehouseType(type) {
  if (form.target_warehouse_type === type) {
    return;
  }
  form.target_warehouse_type = normalizePurchaseTargetType(type);
  applyTargetWarehouseType();
}

async function applySalesOrderPurchase({ automatic = false } = {}) {
  if (form.purchase_type !== "SALES_ORDER") {
    return;
  }
  if (!form.sales_order_ids.length) {
    if (!automatic) {
      errorMessage.value = "请先选择至少一张销售订单，再生成采购建议";
    }
    feedbackMessage.value = "";
    return;
  }
  if (!automatic) {
    cancelSalesOrderPurchaseAutoFill();
  }
  const requestToken = salesOrderAutoFillToken;
  const selectedIds = normalizedSalesOrderIds(form.sales_order_ids);
  salesOrderLoading.value = true;
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    const results = await Promise.allSettled(
      selectedIds.map((orderId) => postResource(`/planning/generate-mrp/${Number(orderId)}`, {}))
    );
    if (automatic && (requestToken !== salesOrderAutoFillToken || !sameSalesOrderIds(form.sales_order_ids, selectedIds))) {
      return;
    }
    const failedRows = results
      .map((result, index) => ({ result, orderId: selectedIds[index] }))
      .filter(({ result }) => result.status === "rejected");
    if (failedRows.length) {
      clearGeneratedSalesOrderPurchaseRows();
      errorMessage.value = `以下销售订单生成采购建议失败：${failedRows
        .map(({ orderId, result }) => {
          const reason = result.reason?.message || String(result.reason || "").trim();
          return reason ? `${salesOrderLabel(orderId)}（${reason}）` : salesOrderLabel(orderId);
        })
        .join("、")}；未生成采购明细，请稍后重试。`;
      return;
    }
    const allDemandRows = results.flatMap(({ value }) => value.demands || value.demand_rows || []);
    mrpDemands.value = allDemandRows;
    const demandRows = allDemandRows.filter((demand) => Number(demand.suggested_purchase_weight_kg || 0) > 0);
    if (!demandRows.length) {
      form.items.splice(0, form.items.length, buildItemRow());
      generatedSalesOrderIdsSnapshot.value = selectedIds;
      errorMessage.value = allDemandRows.length
        ? `${selectedIds.length}张销售订单原材料需求已计算，但当前库存足够，缺口为0，无需销售订单采购；如仍要备料，请切换为备料采购。`
        : `${selectedIds.length}张销售订单没有可生成采购建议的产品需规/BOM数据`;
      return;
    }

    const supplierWarning = applyDemandRowsToPurchaseItems(demandRows);
    generatedSalesOrderIdsSnapshot.value = selectedIds;
    calculator.line_index = 0;
    feedbackMessage.value = `${automatic ? "已自动按" : "已按"} ${selectedIds.length} 张销售订单生成采购建议，生成 ${form.items.length} 条原材料明细`;
    if (supplierWarning) {
      feedbackMessage.value = `${feedbackMessage.value}；${supplierWarning}`;
    }
  } catch (error) {
    errorMessage.value = error.message || "按销售订单生成采购建议失败";
  } finally {
    salesOrderLoading.value = false;
  }
}

function applyDemandRowsToPurchaseItems(rows) {
  const demandRows = rows
    .filter((row) => Number(row.material_item_id))
    .map((row) => ({
      ...row,
      source_demand_id: row.demand_id || row.source_demand_id || null
    }));
  const defaultSupplierIds = Array.from(
    new Set(
      demandRows
        .map((demand) => materialForDemand(demand)?.default_supplier_id)
        .map((id) => Number(id || 0))
        .filter(Boolean)
    )
  );
  let supplierWarning = "";
  if (!form.supplier_id && defaultSupplierIds.length === 1) {
    form.supplier_id = defaultSupplierIds[0];
  } else if (!form.supplier_id && defaultSupplierIds.length === 0) {
    supplierWarning = "物料未维护默认供应商，请手动选择供应商";
  } else if (!form.supplier_id && defaultSupplierIds.length > 1) {
    supplierWarning = "涉及多个默认供应商，请手动确认供应商";
  }

  form.items.splice(
    0,
    form.items.length,
    ...demandRows.map((row, index) => ({
      line_no: index + 1,
      source_demand_id: row.source_demand_id,
      material_item_id: Number(row.material_item_id),
      order_qty: 0,
      order_weight_kg: Number(row.suggested_purchase_weight_kg || 0),
      unit_price: Number(row.reference_unit_price || 0),
      remark: `销售订单采购：${form.sales_order_ids.length}张订单需求`
    }))
  );
  return supplierWarning;
}

function materialOptionsForRow() {
  return materials.value;
}

function applyCalculatorWeight() {
  if (!currentCalculatorRow.value || calculatorMinPurchaseWeight.value <= 0) {
    return;
  }
  currentCalculatorRow.value.order_weight_kg = Number(calculatorMinPurchaseWeight.value.toFixed(3));
}

function normalizeText(value) {
  return String(value || "").trim().toLowerCase();
}

function sameText(left, right) {
  return normalizeText(left) === normalizeText(right);
}

function hasNumberValue(value) {
  return value !== null && value !== undefined && value !== "";
}

function pickNumber(...values) {
  const matched = values.find((value) => hasNumberValue(value));
  return Number(matched || 0);
}

function miniappMaterialMatches(product, material) {
  if (!product || !material) {
    return false;
  }
  return sameText(product.material_code, material.item_code) || sameText(product.material_name, material.item_name);
}

function bomItemMatchesMaterial(item, material) {
  if (!item || !material) {
    return false;
  }
  return (
    Number(item.material_item_id) === Number(material.item_id) ||
    sameText(item.material_code, material.item_code) ||
    sameText(item.material_name, material.item_name)
  );
}

function findBomForMiniappProduct(product) {
  return (
    boms.value.find((bom) => sameText(bom.product_name, product.product_name)) ||
    boms.value.find((bom) => sameText(bom.product_code, product.project_no)) ||
    null
  );
}

function formatOrderValue(item) {
  return purchaseTargetForItem(item) === "AUX" ? `${formatQty(item.order_qty)} 件` : formatWeight(item.order_weight_kg);
}

function formatReceivedValue(item) {
  return purchaseTargetForItem(item) === "AUX" ? `${formatQty(item.received_qty)} 件` : formatWeight(item.received_weight_kg);
}

function formatTonHint(value) {
  const tonValue = Number(value || 0) / 1000;
  return `≈ ${tonValue.toLocaleString("zh-CN", {
    minimumFractionDigits: 3,
    maximumFractionDigits: 3
  })} t`;
}

function formatUnitPriceTonHint(value) {
  const tonPrice = Number(value || 0) * 1000;
  return `≈ ¥${formatAmount(tonPrice)}/t`;
}

function formatUnitPriceDisplay(value) {
  return `¥${formatAmount(value)}/kg · ${formatUnitPriceTonHint(value).replace("≈ ", "")}`;
}

function formatPurchaseUnitPriceDisplay(item) {
  return purchaseTargetForItem(item) === "AUX" ? `¥${formatAmount(item?.unit_price || 0)}/件` : formatUnitPriceDisplay(item?.unit_price || 0);
}

async function loadAll() {
  const [supplierRows, employeeRows, materialRows, bomRows, miniappProductRows, stockBalanceRows, salesOrderRows, salesOrderItemRows, orderRows, itemRows] = await Promise.all([
    fetchResource("/purchase/suppliers?limit=500", []),
    fetchPermissionEmployeeOptions(PERSONNEL_PERMISSION_CODES.PURCHASE_ORDER, 200),
    fetchResource("/master-data/materials?limit=200", []),
    fetchResource("/master-data/boms?limit=500", []),
    fetchResource("/master-data/miniapp-products?limit=1000", []),
    fetchResource("/inventory/stock-balances?limit=500", []),
    fetchResource("/sales/orders?limit=500", []),
    fetchResource("/sales/order-items?limit=1000", []),
    fetchResource("/purchase/orders?limit=500", []),
    fetchResource("/purchase/order-items?limit=500", [])
  ]);
  suppliers.value = supplierRows;
  employees.value = employeeRows;
  materials.value = materialRows;
  boms.value = bomRows;
  miniappProducts.value = miniappProductRows;
  stockBalances.value = stockBalanceRows;
  salesOrders.value = salesOrderRows;
  salesOrderItems.value = salesOrderItemRows;
  orders.value = orderRows;
  orderItems.value = itemRows;
  selectedOrderIds.value = selectedOrderIds.value.filter((id) => orderRows.some((order) => Number(order.purchase_order_id) === Number(id)));
}

function buildOrderPayload() {
  return {
    target_warehouse_type: form.target_warehouse_type,
    sales_order_ids: form.purchase_type === "SALES_ORDER" ? form.sales_order_ids.map(Number).filter(Boolean) : [],
    supplier_id: Number(form.supplier_id),
    purchaser_employee_id: form.purchaser_employee_id ? Number(form.purchaser_employee_id) : null,
    expected_date: form.expected_date || null,
    warning_lead_days: Number(form.warning_lead_days || 0),
    tax_rate: Number(form.tax_rate || 0),
    remark: form.remark || null,
    items: form.items.map((item) => ({
      source_demand_id: item.source_demand_id ? Number(item.source_demand_id) : null,
      material_item_id: Number(item.material_item_id),
      order_qty: form.target_warehouse_type === "AUX" ? Number(item.order_qty || 0) : 0,
      order_weight_kg: form.target_warehouse_type === "AUX" ? 0 : Number(item.order_weight_kg || 0),
      unit_price: Number(item.unit_price || 0),
      remark: item.remark || null
    }))
  };
}

async function submitOrder() {
  if (form.purchase_type === "SALES_ORDER" && !form.sales_order_ids.length) {
    feedbackMessage.value = "";
    errorMessage.value = "销售订单采购请先选择至少一张销售订单";
    return;
  }
  if (
    form.purchase_type === "SALES_ORDER" &&
    form.items.some((item) => item.source_demand_id) &&
    !sameSalesOrderIds(form.sales_order_ids, generatedSalesOrderIdsSnapshot.value)
  ) {
    scheduleSalesOrderPurchaseAutoFill();
    feedbackMessage.value = "";
    errorMessage.value = salesOrderLoading.value
      ? "销售订单采购明细正在自动带出，请稍后提交"
      : "销售订单选择已变化，系统正在重新带出采购明细，请生成完成后再提交";
    return;
  }
  submitting.value = true;
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    const payload = buildOrderPayload();
    const result = editingOrderId.value
      ? await putResource(`/purchase/orders/${Number(editingOrderId.value)}`, payload)
      : await postResource("/purchase/orders", payload);
    feedbackMessage.value = `采购订单 ${result.po_no} 已${editingOrderId.value ? "更新" : "创建"}`;
    await loadAll();
    selectedOrderId.value = result.purchase_order_id;
    closeOrderDrawer();
  } catch (error) {
    errorMessage.value = error.message || "采购订单保存失败";
  } finally {
    submitting.value = false;
  }
}

async function deletePurchaseOrderRow(order) {
  if (!canDeleteOrder(order)) {
    return;
  }
  const confirmed = window.confirm(`确认删除采购订单 ${order.po_no}？删除后会撤回未被其他采购订单引用的采购需求状态。`);
  if (!confirmed) {
    return;
  }
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    const result = await deleteResource(`/purchase/orders/${Number(order.purchase_order_id)}`);
    feedbackMessage.value = result.message || `采购订单 ${order.po_no} 已删除`;
    if (selectedOrderId.value === order.purchase_order_id) {
      selectedOrderId.value = null;
    }
    await loadAll();
  } catch (error) {
    errorMessage.value = error.message || "采购订单删除失败";
  }
}

async function lockPurchaseOrder(order) {
  if (!canLockOrder(order)) {
    return;
  }
  feedbackMessage.value = "";
  errorMessage.value = "";
  try {
    const result = await postResource(`/purchase/orders/${Number(order.purchase_order_id)}/lock`, {});
    feedbackMessage.value = `采购订单 ${result.po_no} 已锁单`;
    await loadAll();
  } catch (error) {
    errorMessage.value = error.message || "采购订单锁单失败";
  }
}

onMounted(async () => {
  document.addEventListener("pointerdown", handleSalesOrderPickerPointerDown, true);
  await loadAll();
});

onUnmounted(() => {
  cancelSalesOrderPurchaseAutoFill();
  document.removeEventListener("pointerdown", handleSalesOrderPickerPointerDown, true);
});
</script>

<style scoped>
.purchase-warning-row {
  background: linear-gradient(90deg, rgba(230, 162, 60, 0.2) 0%, rgba(253, 246, 236, 0.94) 100%);
  box-shadow: inset 4px 0 0 #e6a23c;
}

.purchase-warning-row:hover {
  background: linear-gradient(90deg, rgba(230, 162, 60, 0.26) 0%, #fdf6ec 100%);
}

.warning-inline {
  display: block;
  margin-top: 3px;
  color: #b88230;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}

.purchase-meta-grid {
  display: grid;
  grid-template-columns: 1.1fr 0.95fr 0.85fr 1fr;
  gap: 14px;
}

.weight-ton-hint,
.calculator-result-grid small {
  display: block;
  margin-top: 4px;
  color: #909399;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
}

.purchase-contract-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 86px;
  min-height: 38px;
  padding: 0 16px;
  border: 1px solid #409eff;
  border-radius: 10px;
  background: linear-gradient(180deg, #66b1ff 0%, #409eff 100%);
  color: #fff;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 8px 20px rgba(64, 158, 255, 0.22);
  cursor: pointer;
  transition: transform 0.16s ease, box-shadow 0.16s ease, opacity 0.16s ease;
}

.purchase-contract-button:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 12px 26px rgba(64, 158, 255, 0.28);
}

.purchase-contract-button:disabled {
  cursor: not-allowed;
  opacity: 0.52;
}

.select-col {
  width: 44px;
  text-align: center;
}

.select-col input {
  width: 16px;
  height: 16px;
  accent-color: #409eff;
  cursor: pointer;
}

.purchase-archive-col,
.purchase-archive-cell {
  width: 188px;
  min-width: 188px;
}

.purchase-archive-cell {
  overflow: visible;
  white-space: normal;
}

.purchase-archive-actions-compact {
  width: 172px;
}

.purchase-archive-actions-compact :deep(.document-archive-actions) {
  display: grid;
  gap: 6px;
}

.purchase-archive-actions-compact :deep(.document-archive-status) {
  min-height: 24px;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 11px;
  line-height: 1.2;
  white-space: nowrap;
}

.purchase-archive-actions-compact :deep(.document-archive-buttons) {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px;
}

.purchase-archive-actions-compact :deep(.document-archive-button) {
  min-height: 26px;
  padding: 0 5px;
  border-radius: 8px;
  font-size: 11px;
  line-height: 1;
  white-space: nowrap;
}

.purchase-archive-actions-compact :deep(.document-archive-icon) {
  display: none;
}

.purchase-source-cell {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  max-width: 320px;
}

.purchase-source-chip {
  display: inline-grid;
  gap: 2px;
  max-width: 260px;
  padding: 6px 9px;
  border: 1px solid #d9ecff;
  border-radius: 10px;
  background: linear-gradient(180deg, #ffffff 0%, #ecf5ff 100%);
  color: #303133;
  box-shadow:
    0 4px 10px rgba(64, 158, 255, 0.08),
    inset 0 1px 0 rgba(255, 255, 255, 0.9);
  cursor: default;
}

.purchase-source-chip strong,
.purchase-source-chip small {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.purchase-source-chip strong {
  color: #409eff;
  font-size: 12px;
}

.purchase-source-chip small {
  color: #606266;
  font-size: 11px;
}

.floating-info-card {
  position: fixed;
  z-index: 10000;
  display: grid;
  gap: 4px;
  width: max-content;
  max-width: min(540px, calc(100vw - 24px));
  padding: 10px 13px;
  border: 1px solid #b9dcff;
  border-radius: 12px;
  background: linear-gradient(180deg, #ffffff 0%, #ecf5ff 100%);
  color: #303133;
  box-shadow:
    0 18px 38px rgba(64, 158, 255, 0.24),
    0 0 0 1px rgba(64, 158, 255, 0.12),
    inset 0 1px 0 rgba(255, 255, 255, 0.96);
  pointer-events: none;
}

.floating-info-card strong {
  color: #409eff;
  font-size: 13px;
  line-height: 1.45;
  white-space: normal;
}

.floating-info-card small {
  color: #606266;
  font-size: 12px;
  line-height: 1.55;
  white-space: normal;
}

.document-form-section {
  display: grid;
  gap: 12px;
  margin-bottom: 18px;
}

.purchase-document-form {
  padding-bottom: 86px;
}

.document-section-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.document-section-title-row h2 {
  margin: 0;
  color: var(--document-paper-ink, #17120a);
  font-size: 15px;
  font-weight: 900;
  letter-spacing: 0.1em;
}

.purchase-route-section {
  gap: 8px;
}

.document-purchase-decision-panel {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
  padding: 0;
  overflow: hidden;
  border: 2px solid var(--document-paper-grid, rgba(20, 14, 6, 0.88));
  border-radius: 0;
  background:
    linear-gradient(90deg, rgba(31, 122, 74, 0.05), transparent 38%),
    rgba(255, 250, 240, 0.44);
  box-shadow: none;
}

.document-demand-panel {
  position: relative;
  top: auto;
  max-height: none;
  overflow: visible;
  overscroll-behavior: auto;
  border-color: rgba(20, 14, 6, 0.64);
  background: rgba(255, 250, 240, 0.58);
}

.document-static-value {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  color: #303133;
  font-weight: 800;
}

.document-order-tag-picker {
  padding: 0;
  border: 0;
  background: transparent;
}

.document-calculator-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.purchase-decision-section {
  min-width: 0;
  padding: 0;
  border: 0;
  border-right: 2px solid var(--document-paper-grid, rgba(20, 14, 6, 0.88));
  border-radius: 0;
  background: transparent;
}

.purchase-mode-section {
  border-right: 0;
  background: transparent;
}

.purchase-decision-title {
  display: flex;
  align-items: center;
  gap: 0;
  min-height: 40px;
  margin: 0;
  border-bottom: 1.5px solid var(--document-paper-grid, rgba(20, 14, 6, 0.88));
  background: rgba(227, 207, 161, 0.62);
}

.purchase-decision-title div {
  display: grid;
  gap: 2px;
}

.purchase-decision-title strong {
  color: var(--document-paper-ink, #17120a);
  font-size: 14px;
  font-weight: 900;
  letter-spacing: 0.08em;
}

.purchase-decision-title small {
  color: #909399;
  font-size: 12px;
}

.purchase-decision-index {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: stretch;
  width: 48px;
  height: auto;
  border-right: 1.5px solid var(--document-paper-grid, rgba(20, 14, 6, 0.88));
  border-radius: 0;
  background: rgba(255, 246, 223, 0.62);
  color: var(--document-paper-stamp, #1f7a4a);
  font-family: var(--ui-font-display);
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.08em;
}

.purchase-choice-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
}

.purchase-choice-card {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 58px;
  padding: 14px 16px;
  border: 0;
  border-right: 1.5px solid rgba(20, 14, 6, 0.5);
  border-radius: 0;
  background: rgba(255, 250, 240, 0.34);
  color: var(--document-paper-ink, #17120a);
  text-align: left;
  cursor: pointer;
  transition:
    background 0.18s ease,
    box-shadow 0.18s ease,
    color 0.18s ease,
    transform 0.18s ease;
}

.purchase-choice-card:last-child {
  border-right: 0;
}

.purchase-choice-card.active {
  color: var(--document-paper-stamp, #1f7a4a);
  background:
    linear-gradient(135deg, rgba(31, 122, 74, 0.16), rgba(255, 250, 240, 0.68)),
    repeating-linear-gradient(-45deg, rgba(31, 122, 74, 0.08) 0 4px, transparent 4px 10px);
  box-shadow:
    inset 0 0 0 2px rgba(31, 122, 74, 0.72),
    inset 0 0 0 999px rgba(255, 246, 223, 0.08);
}

.purchase-choice-card:hover:not(.disabled-choice) {
  background: rgba(31, 122, 74, 0.08);
}

.purchase-choice-card.disabled-choice {
  cursor: not-allowed;
  opacity: 0.54;
  background:
    repeating-linear-gradient(-45deg, rgba(106, 86, 49, 0.08) 0 4px, transparent 4px 8px),
    rgba(239, 224, 185, 0.36);
}

.choice-check,
.choice-lock {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin-top: 0;
  border: 2px solid rgba(23, 18, 10, 0.5);
  border-radius: 50%;
  color: var(--document-paper-stamp, #1f7a4a);
  font-size: 11px;
  font-weight: 800;
  background: rgba(255, 246, 223, 0.68);
}

.purchase-choice-card.active .choice-check {
  border-color: currentColor;
  background: radial-gradient(circle at center, currentColor 0 34%, transparent 37%);
  box-shadow:
    inset 0 0 0 4px rgba(255, 246, 223, 0.94),
    0 0 0 3px rgba(31, 122, 74, 0.12);
}

.choice-lock {
  border-color: rgba(106, 86, 49, 0.5);
  background: rgba(106, 86, 49, 0.42);
  color: #fff6df;
}

.choice-main {
  display: grid;
  gap: 4px;
}

.purchase-choice-card strong {
  font-size: 14px;
  color: currentColor;
  font-weight: 900;
  letter-spacing: 0.05em;
}

.purchase-choice-card small {
  font-size: 12px;
  color: #909399;
  line-height: 1.3;
}

.purchase-choice-card.active small {
  color: #606266;
}

.purchase-document-actions {
  position: fixed;
  right: max(38px, env(safe-area-inset-right));
  bottom: max(28px, env(safe-area-inset-bottom));
  z-index: 90;
  display: flex;
  justify-content: flex-end;
  width: auto;
  margin: 0;
  padding: 0;
  background: transparent;
  pointer-events: none;
}

.purchase-document-actions .purchase-submit-button {
  min-width: 220px;
  min-height: 44px;
  pointer-events: auto;
  box-shadow:
    0 14px 28px rgba(31, 122, 74, 0.22),
    inset 0 1px 0 rgba(255, 255, 255, 0.55);
}

.table-action-button {
  min-height: 30px;
  padding: 0 10px;
  white-space: nowrap;
}

.order-tag-picker {
  position: relative;
  display: grid;
  gap: 8px;
  padding: 12px;
  border: 1px solid #d9ecff;
  border-radius: 12px;
  background: #fbfdff;
}

.selected-order-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  min-height: 30px;
}

.selected-lot-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  padding: 5px 9px;
  border: 1px solid #d9ecff;
  border-radius: 999px;
  background: #ecf5ff;
  color: #409eff;
  font-size: 12px;
  font-weight: 700;
}

.selected-lot-tag small {
  max-width: 160px;
  overflow: hidden;
  color: #67a8e8;
  font-weight: 500;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tag-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: 0;
  border-radius: 999px;
  background: rgba(64, 158, 255, 0.12);
  color: #409eff;
  cursor: pointer;
}

.tag-remove:hover {
  background: #409eff;
  color: #fff;
}

.stock-lot-dropdown {
  position: absolute;
  z-index: 20;
  right: 12px;
  left: 12px;
  top: calc(100% - 8px);
  display: grid;
  gap: 6px;
  max-height: 320px;
  overflow: auto;
  padding: 8px;
  border: 1px solid #c6e2ff;
  border-radius: 10px;
  background: #ffffff;
  box-shadow: 0 14px 32px rgba(64, 158, 255, 0.18);
}

.stock-lot-option {
  display: grid;
  gap: 4px;
  padding: 9px 10px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: #fff;
  color: #303133;
  text-align: left;
  cursor: pointer;
}

.stock-lot-option:hover,
.stock-lot-option-selected {
  border-color: #b3d8ff;
  background: #ecf5ff;
}

.lot-main,
.lot-meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lot-main {
  color: #303133;
  font-size: 13px;
  font-weight: 700;
}

.lot-meta {
  color: #606266;
  font-size: 12px;
}

.stock-lot-option em {
  color: #409eff;
  font-size: 11px;
  font-style: normal;
}

.stock-lot-empty {
  padding: 12px;
  color: #909399;
  text-align: center;
}

@media (max-width: 760px) {
  .purchase-meta-grid {
    grid-template-columns: 1fr;
  }

  .document-purchase-decision-panel,
  .purchase-choice-grid {
    grid-template-columns: 1fr;
  }

  .purchase-decision-section,
  .purchase-choice-card {
    border-right: 0;
  }

  .purchase-decision-section {
    border-bottom: 2px solid var(--document-paper-grid, rgba(20, 14, 6, 0.88));
  }

  .purchase-mode-section {
    border-bottom: 0;
  }

  .purchase-choice-card {
    border-bottom: 1.5px solid rgba(20, 14, 6, 0.5);
  }

  .purchase-choice-card:last-child {
    border-bottom: 0;
  }

  .document-calculator-grid {
    grid-template-columns: 1fr;
  }

  .purchase-document-actions {
    right: max(18px, env(safe-area-inset-right));
    bottom: max(18px, env(safe-area-inset-bottom));
    padding-right: 8px;
    padding-left: 8px;
    width: calc(100vw - 36px);
  }

  .purchase-document-actions .purchase-submit-button {
    width: 100%;
  }

  .stock-lot-dropdown {
    position: static;
    max-height: 260px;
  }
}
</style>
