<template>
  <Teleport to="body">
    <div v-if="open" class="workflow-drawer-mask stocktake-mask" @click.self="$emit('close')">
      <section class="stocktake-shell">
        <header class="stocktake-head">
          <div>
            <p class="eyebrow">嘉恒仓库 · 盘库</p>
            <h3>{{ activeStocktake ? activeStocktake.stocktake_no : "新建盘库" }}</h3>
          </div>
          <button class="ghost-button" type="button" @click="$emit('close')">关闭</button>
        </header>

        <nav class="stocktake-steps stocktake-progress-rail" aria-label="盘库流程">
          <span
            v-for="(step, index) in flowSteps"
            :key="step.key"
            class="stocktake-step"
            :class="{
              active: activePanel === step.key,
              done: index < currentFlowIndex
            }"
          >
            <span>{{ step.no }}</span>
            <strong>{{ step.label }}</strong>
          </span>
        </nav>

        <div class="stocktake-notice-row" :class="{ empty: !dialogMessage && !dialogError }" aria-live="polite">
          <div v-if="dialogMessage" class="feedback-banner">{{ dialogMessage }}</div>
          <div v-if="dialogError" class="feedback-banner error-banner">{{ dialogError }}</div>
        </div>

        <div class="stocktake-main">
          <div class="stocktake-flow-column">
            <section v-if="activePanel === 'export'" class="stocktake-panel stocktake-single-panel">
              <div class="stocktake-action-card stocktake-action-card-wide">
                <span class="stocktake-stage-tag">当前仓库：{{ currentWarehouseName }}</span>
                <strong>01 确认盘库并导出仓库清单</strong>
                <p>点击后系统会锁定当前仓库，并导出本次盘库 Excel 清单。盘库结束前该仓库不能出入库。</p>
                <div class="stocktake-inline-actions">
                  <button class="primary-button" type="button" :disabled="busy || !currentWarehouseId" @click="startAndExportStocktake">
                    {{ busy ? "处理中..." : "确认盘库并导出仓库清单" }}
                  </button>
                  <button v-if="activeStocktake?.status === 'LOCKED'" class="ghost-button" type="button" :disabled="busy" @click="exportStocktake">
                    重新导出清单
                  </button>
                </div>
              </div>
            </section>

            <section v-if="activePanel === 'import'" class="stocktake-panel stocktake-panel-import">
              <div class="stocktake-action-card stocktake-action-card-wide">
                <span class="stocktake-stage-tag">当前盘库单：{{ activeStocktake?.stocktake_no || "-" }}</span>
                <strong>02 导入盘点后的 Excel</strong>
                <p>只允许导入当前仓库、本次盘库单导出的清单。导入成功后会立刻弹出差异对比。</p>
                <label class="import-dropzone">
                  <input ref="fileInputRef" class="hidden-file-input" type="file" accept=".xlsx,.xlsm" :disabled="busy" @change="importStocktake" />
                  <strong>{{ busy ? "导入中..." : "选择盘点后的 Excel" }}</strong>
                  <span>如果差异确认时取消，可以修改 Excel 后重新导入覆盖旧差异。</span>
                </label>
              </div>
            </section>
          </div>

          <section class="stocktake-panel stocktake-panel-history">
            <div class="table-wrap">
              <table class="data-table compact-table">
                <thead>
                  <tr>
                    <th>盘库单号</th>
                    <th>仓库</th>
                    <th>状态</th>
                    <th>开始时间</th>
                    <th>确认时间</th>
                    <th>盘盈</th>
                    <th>盘亏</th>
                    <th>新增批次</th>
                    <th>缺失批次</th>
                    <th>影响金额</th>
                  </tr>
                </thead>
                <tbody>
                  <tr v-for="row in paginatedHistoryRows" :key="row.id">
                    <td>{{ row.stocktake_no }}</td>
                    <td>{{ stocktakeWarehouseNames(row) }}</td>
                    <td>{{ formatStocktakeStatusLabel(row.status) }}</td>
                    <td>{{ formatDateTime(row.started_at) }}</td>
                    <td>{{ formatDateTime(row.confirmed_at) }}</td>
                    <td>{{ stocktakeSummaryValue(row, "gain_count") }}</td>
                    <td>{{ stocktakeSummaryValue(row, "loss_count") }}</td>
                    <td>{{ stocktakeSummaryValue(row, "new_lot_count") }}</td>
                    <td>{{ stocktakeSummaryValue(row, "missing_count") }}</td>
                    <td>¥{{ formatAmount(stocktakeSummaryValue(row, "diff_amount")) }}</td>
                  </tr>
                  <tr v-if="!currentWarehouseHistoryRows.length">
                    <td colspan="10" class="empty-row">暂无盘库记录</td>
                  </tr>
                </tbody>
              </table>
            </div>
            <PaginationBar
              v-model:page="historyPage"
              v-model:page-size="historyPageSize"
              :total="currentWarehouseHistoryRows.length"
              :page-size-options="[6]"
            />
          </section>
        </div>

        <div v-if="diffDialogOpen" class="stocktake-diff-modal-mask" @click.self="closeDiffDialog">
          <section class="stocktake-diff-modal">
            <header class="stocktake-diff-modal-head">
              <div>
                <p class="eyebrow">盘库差异对比</p>
                <h3>{{ activeStocktake?.stocktake_no }} · {{ currentWarehouseName }}</h3>
              </div>
              <button class="ghost-button" type="button" :disabled="busy" @click="closeDiffDialog">取消，重新导入</button>
            </header>
            <div class="stocktake-summary-grid">
              <article v-for="card in summaryCards" :key="card.key" class="stocktake-summary-card" :class="card.tone">
                <span>{{ card.label }}</span>
                <strong>{{ card.value }}</strong>
              </article>
            </div>
            <div v-if="isCleanEmptyStocktake" class="stocktake-empty-state">
              <strong>空库盘库清单已确认到差异页</strong>
              <span>系统库存快照和盘点清单都没有明细。确认盘库后只会解锁仓库，不会生成库存调整流水。</span>
            </div>
            <div class="stocktake-diff-toolbar">
              <button class="ghost-button" type="button" :class="{ active: diffFilter === 'ALL' }" @click="diffFilter = 'ALL'">全部</button>
              <button class="ghost-button" type="button" :class="{ active: diffFilter === 'DIFF' }" @click="diffFilter = 'DIFF'">只看差异</button>
              <button class="ghost-button" type="button" :class="{ active: diffFilter === 'ERROR' }" @click="diffFilter = 'ERROR'">只看异常</button>
            </div>
            <div class="stocktake-diff-table stocktake-diff-table-v2">
              <div class="stocktake-diff-header">系统快照</div>
              <div class="stocktake-diff-change-header">变化</div>
              <div class="stocktake-diff-header">实盘结果</div>

              <template v-for="line in filteredLines" :key="line.id">
                <div class="stocktake-diff-cell stocktake-diff-cell-left" :class="diffClass(line)">
                  <strong>{{ line.item_code }} · {{ line.item_name }}</strong>
                  <span>批次：{{ line.lot_no || "-" }}</span>
                  <span>来源库存批次号：{{ line.source_material_sub_batch_no || "-" }}</span>
                  <span>重量：{{ formatWeight(line.snapshot_weight_kg) }}</span>
                  <span v-if="!isWeightOnlyStocktakeLine(line)">数量：{{ formatQty(line.snapshot_qty) }}</span>
                  <span>单价：¥{{ formatAmount(line.snapshot_unit_cost) }}</span>
                </div>
                <div class="stocktake-diff-change" :class="diffClass(line)">
                  <strong>{{ formatStocktakeDiffTypeLabel(line.diff_type) }}</strong>
                  <span>行状态：{{ formatStocktakeRowStatusLabel(line.row_status) }}</span>
                  <span>重量差：{{ formatWeight(line.diff_weight_kg) }}</span>
                  <span v-if="!isWeightOnlyStocktakeLine(line)">数量差：{{ formatQty(line.diff_qty) }}</span>
                  <span>金额影响：¥{{ formatAmount(line.diff_amount) }}</span>
                  <em v-if="line.error_message">{{ line.error_message }}</em>
                </div>
                <div class="stocktake-diff-cell stocktake-diff-cell-right" :class="diffClass(line)">
                  <strong>{{ line.item_code }} · {{ line.item_name }}</strong>
                  <span>批次：{{ line.lot_no || "-" }}</span>
                  <span>盘点重量：{{ formatWeight(line.counted_weight_kg) }}</span>
                  <span v-if="!isWeightOnlyStocktakeLine(line)">盘点数量：{{ formatQty(line.counted_qty) }}</span>
                  <span>备注：{{ line.remark || "-" }}</span>
                </div>
              </template>

              <div v-if="!filteredLines.length" class="stocktake-diff-empty-v2">
                <strong>没有需要展示的差异行</strong>
                <span v-if="isCleanEmptyStocktake">这是空库盘库，确认后只解锁仓库，不生成库存调整流水。</span>
                <span v-else>当前筛选条件下没有明细。</span>
              </div>
            </div>
            <div class="stocktake-footer">
              <button class="primary-button" type="button" :disabled="busy || !canConfirmCurrentStocktake" @click="openConfirmDialog">
                {{ busy ? "确认中..." : "确认更新库存并解锁" }}
              </button>
            </div>
          </section>
        </div>
      </section>

      <div v-if="confirmDialogOpen" class="stocktake-confirm-mask" @click.self="closeConfirmDialog">
        <section class="stocktake-confirm-dialog">
          <strong>是否确认盘库？</strong>
          <span>确认后系统会按当前差异重置库存，并解锁本次盘库仓库。该操作会写入盘库记录。</span>
          <div class="stocktake-confirm-actions">
            <button class="ghost-button" type="button" :disabled="busy" @click="closeConfirmDialog">取消</button>
            <button class="primary-button" type="button" :disabled="busy" @click="confirmStocktake">
              {{ busy ? "确认中..." : "确认盘库" }}
            </button>
          </div>
        </section>
      </div>
    </div>
  </Teleport>
</template>

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

import PaginationBar from "./PaginationBar.vue";
import { downloadResource, fetchResource, postResource, uploadResource } from "../services/api";
import { formatStocktakeDiffTypeLabel, formatStocktakeRowStatusLabel, formatStocktakeStatusLabel } from "../utils/dictionaries";
import { formatAmount, formatDateTime, formatQty, formatWeight } from "../utils/formatters";
import { usePagination } from "../utils/pagination";
import {
  diffTone,
  filterStocktakesForWarehouse,
  findActiveStocktakeForWarehouse,
  hasBlockingDiffErrors,
  isEmptyStocktakeRead,
  nextStocktakePanel,
  splitDiffLines
} from "../utils/stocktakeWorkflow";

const props = defineProps({
  open: { type: Boolean, default: false },
  warehouses: { type: Array, default: () => [] },
  defaultWarehouseId: { type: Number, default: 0 }
});
const emit = defineEmits(["close", "changed", "message", "error"]);

const flowSteps = [
  { key: "export", no: "01", label: "确认盘库并导出" },
  { key: "import", no: "02", label: "导入清单" }
];

const activePanel = ref("export");
const activeStocktake = ref(null);
const previewLines = ref([]);
const previewSummary = ref({});
const busy = ref(false);
const fileInputRef = ref(null);
const diffFilter = ref("ALL");
const confirmDialogOpen = ref(false);
const diffDialogOpen = ref(false);
const historyRows = ref([]);
const currentFlowIndex = computed(() => Math.max(0, flowSteps.findIndex((step) => step.key === activePanel.value)));

const currentWarehouseId = computed(() => Number(props.defaultWarehouseId || 0));
const currentWarehouse = computed(
  () => props.warehouses.find((warehouse) => Number(warehouse.id) === currentWarehouseId.value) || null
);
const currentWarehouseName = computed(() => currentWarehouse.value?.warehouse_name || "未选择仓库");
const currentWarehouseHistoryRows = computed(() => filterStocktakesForWarehouse(historyRows.value, currentWarehouseId.value));
const {
  page: historyPage,
  pageSize: historyPageSize,
  rows: paginatedHistoryRows
} = usePagination(currentWarehouseHistoryRows, 6);

const canConfirmCurrentStocktake = computed(
  () => Boolean(activeStocktake.value?.id) && !hasBlockingDiffErrors(previewLines.value)
);

const dialogMessage = ref("");
const dialogError = ref("");

watch(
  () => props.open,
  async (open) => {
    if (!open) return;
    activePanel.value = "export";
    activeStocktake.value = null;
    previewLines.value = [];
    previewSummary.value = {};
    diffFilter.value = "ALL";
    confirmDialogOpen.value = false;
    diffDialogOpen.value = false;
    dialogMessage.value = "";
    dialogError.value = "";
    if (!currentWarehouseId.value) {
      setDialogError("请先在仓库栏选中一个仓库，再进行盘库");
      return;
    }
    await loadHistory();
    const activeRow = findActiveStocktakeForWarehouse(historyRows.value, currentWarehouseId.value);
    if (activeRow) {
      await continueStocktake(activeRow, { silent: true });
    }
  }
);

const summaryCards = computed(() => [
  { key: "match", label: "一致", value: previewSummary.value.match_count || 0, tone: "neutral" },
  { key: "gain", label: "盘盈", value: previewSummary.value.gain_count || 0, tone: "gain" },
  { key: "loss", label: "盘亏", value: previewSummary.value.loss_count || 0, tone: "loss" },
  { key: "new", label: "新增批次", value: previewSummary.value.new_lot_count || 0, tone: "new" },
  { key: "missing", label: "缺失批次", value: previewSummary.value.missing_count || 0, tone: "missing" },
  { key: "error", label: "异常", value: previewSummary.value.error_count || 0, tone: "error" },
  { key: "amount", label: "影响金额", value: `¥${formatAmount(previewSummary.value.diff_amount || 0)}`, tone: "amount" }
]);

const filteredLines = computed(() => splitDiffLines(previewLines.value, diffFilter.value));

const isCleanEmptyStocktake = computed(
  () =>
    diffDialogOpen.value &&
    ["EXPORTED", "IMPORTED"].includes(String(activeStocktake.value?.status || "").toUpperCase()) &&
    previewLines.value.length === 0
);

function isWeightOnlyStocktakeLine(line) {
  const warehouseType = String(line?.warehouse_type || currentWarehouse.value?.warehouse_type || "").toUpperCase();
  return ["RAW", "AUX", "SCRAP"].includes(warehouseType) || String(line?.item_type || "").toUpperCase() === "RAW_MATERIAL";
}

function diffClass(line) {
  return `diff-${diffTone(line)}`;
}

function stocktakeWarehouseNames(row) {
  return Array.isArray(row?.warehouses) ? row.warehouses.map((item) => item.warehouse_name).filter(Boolean).join("、") : "-";
}

function stocktakeSummaryValue(row, key) {
  return Number(row?.summary?.[key] || 0);
}

async function startAndExportStocktake() {
  clearDialogFeedback();
  if (!currentWarehouseId.value) {
    setDialogError("请先在仓库栏选中一个仓库");
    return;
  }
  busy.value = true;
  try {
    const stocktake = await postResource("/inventory/stocktakes", {
      warehouse_ids: [currentWarehouseId.value],
      remark: `${currentWarehouseName.value}盘库`
    });
    activeStocktake.value = stocktake;
    await downloadResource(`/inventory/stocktakes/${stocktake.id}/export`, `${stocktake.stocktake_no}_${currentWarehouseName.value}_盘库清单.xlsx`);
    const exportedStocktake = await fetchResource(`/inventory/stocktakes/${stocktake.id}`, null);
    if (!exportedStocktake) {
      throw new Error("导出后读取盘库单失败，请重新打开盘库");
    }
    await loadHistory();
    await applyLoadedStocktake(exportedStocktake, { silent: true });
    setDialogMessage(`盘库单 ${exportedStocktake.stocktake_no} 已导出，${currentWarehouseName.value} 已锁库`);
    emit("changed");
  } catch (error) {
    setDialogError(error.message || "开始盘库并导出失败");
  } finally {
    busy.value = false;
  }
}

async function loadHistory() {
  try {
    if (!currentWarehouseId.value) {
      historyRows.value = [];
      return;
    }
    historyRows.value = await fetchResource(`/inventory/stocktakes?warehouse_id=${currentWarehouseId.value}&limit=100`, []);
  } catch (error) {
    setDialogError(error.message || "读取盘库记录失败");
  }
}

function clearDialogFeedback() {
  dialogMessage.value = "";
  dialogError.value = "";
}

function setDialogMessage(message) {
  dialogMessage.value = message;
  dialogError.value = "";
  emit("message", message);
}

function setDialogError(message) {
  dialogError.value = message;
  dialogMessage.value = "";
  emit("error", message);
}

async function applyLoadedStocktake(stocktake, options = {}) {
  const nextPanel = nextStocktakePanel(stocktake);
  let loadedLines = [];
  confirmDialogOpen.value = false;
  diffDialogOpen.value = false;
  previewLines.value = [];
  activeStocktake.value = null;
  previewSummary.value = {};

  if (nextPanel === "diff" && String(stocktake?.status || "").toUpperCase() === "IMPORTED") {
    const lineRows = await fetchResource(`/inventory/stocktakes/${stocktake.id}/lines?warehouse_id=${currentWarehouseId.value}`, null);
    if (!Array.isArray(lineRows)) {
      throw new Error("读取盘库明细失败，请重新打开盘库单");
    }
    loadedLines = lineRows;
  }

  activeStocktake.value = stocktake;
  previewSummary.value = stocktake?.summary || {};
  previewLines.value = loadedLines;
  activePanel.value = nextPanel === "diff" || nextPanel === "history" ? "import" : nextPanel;
  diffDialogOpen.value = nextPanel === "diff";

  if (options.silent) return;
  if (nextPanel === "export") {
    setDialogMessage(`${stocktake.stocktake_no} 已锁库，请导出盘库清单`);
  } else if (nextPanel === "import") {
    setDialogMessage(`${stocktake.stocktake_no} 已导出，请导入盘点清单`);
  } else if (nextPanel === "diff" && isEmptyStocktakeRead(stocktake)) {
    setDialogMessage(`${stocktake.stocktake_no} 是空库盘库单，可确认后解锁`);
  } else if (nextPanel === "diff") {
    setDialogMessage(`${stocktake.stocktake_no} 已导入，请核对差异后确认`);
  }
}

async function continueStocktake(row, options = {}) {
  if (!row?.id) return;
  clearDialogFeedback();
  busy.value = true;
  try {
    const stocktake = await fetchResource(`/inventory/stocktakes/${row.id}`, row);
    await applyLoadedStocktake(stocktake, options);
  } catch (error) {
    setDialogError(error.message || "继续处理盘库单失败");
  } finally {
    busy.value = false;
  }
}

async function exportStocktake() {
  if (!activeStocktake.value?.id) return;
  clearDialogFeedback();
  busy.value = true;
  try {
    await downloadResource(`/inventory/stocktakes/${activeStocktake.value.id}/export`, `${activeStocktake.value.stocktake_no}_${currentWarehouseName.value}_盘库清单.xlsx`);
    const exportedStocktake = await fetchResource(`/inventory/stocktakes/${activeStocktake.value.id}`, null);
    if (!exportedStocktake) {
      throw new Error("导出后读取盘库单失败，请刷新后继续处理");
    }
    await applyLoadedStocktake(exportedStocktake, { silent: true });
    if (isEmptyStocktakeRead(exportedStocktake)) {
      setDialogMessage(`空盘库单 ${exportedStocktake.stocktake_no} 已导出，可直接确认盘库后解锁仓库`);
    } else {
      setDialogMessage(`盘库清单 ${exportedStocktake.stocktake_no} 已导出，请清点后导入`);
    }
  } catch (error) {
    setDialogError(error.message || "导出盘库清单失败");
  } finally {
    busy.value = false;
  }
}

async function importStocktake(event) {
  const file = event.target.files?.[0];
  if (!file) {
    setDialogError("请选择盘点后的 Excel 清单");
    return;
  }
  if (!activeStocktake.value?.id) {
    const fallbackRow = findActiveStocktakeForWarehouse(historyRows.value, currentWarehouseId.value);
    if (fallbackRow) {
      await continueStocktake(fallbackRow, { silent: true });
    }
    if (!activeStocktake.value?.id) {
      setDialogError("没有可导入的盘库单，请先创建盘库单或从盘库记录继续处理");
      if (fileInputRef.value) fileInputRef.value.value = "";
      return;
    }
  }
  clearDialogFeedback();
  busy.value = true;
  try {
    const formData = new FormData();
    formData.append("file", file);
    const result = await uploadResource(`/inventory/stocktakes/${activeStocktake.value.id}/import`, formData);
    if (!result?.stocktake) {
      throw new Error("导入接口返回异常，请重新导入盘点清单");
    }
    activeStocktake.value = result.stocktake;
    previewLines.value = Array.isArray(result.lines) ? result.lines : [];
    previewSummary.value = result.summary || {};
    confirmDialogOpen.value = false;
    diffDialogOpen.value = true;
    activePanel.value = "import";
    await loadHistory();
    if (!previewLines.value.length) {
      setDialogMessage(`空盘库单 ${result.stocktake.stocktake_no} 已导入：无库存差异，确认盘库后解锁仓库`);
    } else if (hasBlockingDiffErrors(previewLines.value)) {
      setDialogError(`盘点清单已导入，但存在 ${previewSummary.value.error_count || 0} 行异常，请处理后再确认`);
    } else {
      setDialogMessage(`盘点清单已导入：发现 ${previewSummary.value.gain_count || 0} 行盘盈、${previewSummary.value.loss_count || 0} 行盘亏、${previewSummary.value.new_lot_count || 0} 行新增批次、${previewSummary.value.missing_count || 0} 行缺失批次`);
    }
  } catch (error) {
    setDialogError(error.message || "导入盘点清单失败");
  } finally {
    busy.value = false;
    if (fileInputRef.value) fileInputRef.value.value = "";
  }
}

function openConfirmDialog() {
  clearDialogFeedback();
  if (!activeStocktake.value?.id) {
    setDialogError("没有可确认的盘库单，请先创建或继续处理盘库单");
    return;
  }
  if (!canConfirmCurrentStocktake.value) {
    setDialogError("存在异常行或没有可确认的盘库单，不能确认盘库");
    return;
  }
  confirmDialogOpen.value = true;
}

function closeConfirmDialog() {
  if (busy.value) return;
  confirmDialogOpen.value = false;
}

function closeDiffDialog() {
  if (busy.value) return;
  diffDialogOpen.value = false;
}

async function confirmStocktake() {
  clearDialogFeedback();
  if (!activeStocktake.value?.id) {
    setDialogError("没有可确认的盘库单，请先创建或继续处理盘库单");
    return;
  }
  if (!canConfirmCurrentStocktake.value) {
    setDialogError("存在异常行或没有可确认的盘库单，不能确认盘库");
    return;
  }
  busy.value = true;
  try {
    const confirmedStocktake = await postResource(`/inventory/stocktakes/${activeStocktake.value.id}/confirm`, {
      remark: "盘库确认"
    });
    activeStocktake.value = confirmedStocktake;
    await loadHistory();
    confirmDialogOpen.value = false;
    diffDialogOpen.value = false;
    activePanel.value = "export";
    activeStocktake.value = null;
    previewLines.value = [];
    previewSummary.value = {};
    setDialogMessage(`盘库单 ${confirmedStocktake.stocktake_no} 已确认并解锁`);
    emit("changed");
  } catch (error) {
    setDialogError(error.message || "确认盘库失败");
  } finally {
    busy.value = false;
  }
}
</script>
