import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";

import {
  canContinueStocktake,
  diffTone,
  filterStocktakesForWarehouse,
  findActiveStocktakeForWarehouse,
  findOnlyActiveStocktake,
  hasBlockingDiffErrors,
  isEmptyStocktakeRead,
  nextStocktakePanel,
  splitDiffLines,
  stocktakeBelongsToWarehouse,
  stocktakeSummaryLineCount,
  warehouseStocktakeStatus
} from "../src/utils/stocktakeWorkflow.js";

const emptyExported = {
  id: 10,
  status: "EXPORTED",
  summary: {
    match_count: 0,
    gain_count: 0,
    loss_count: 0,
    new_lot_count: 0,
    missing_count: 0,
    error_count: 0
  },
  warehouses: [{ warehouse_id: 4, warehouse_name: "辅料库" }]
};

const importedWithDiff = {
  id: 11,
  status: "IMPORTED",
  summary: {
    match_count: 2,
    gain_count: 1,
    loss_count: 1,
    new_lot_count: 0,
    missing_count: 0,
    error_count: 0
  },
  warehouses: [{ warehouse_id: 1, warehouse_name: "原材料库" }]
};

const lockedRaw = {
  id: 12,
  status: "LOCKED",
  stocktake_no: "PK-20260530-012",
  warehouses: [{ warehouse_id: 1, warehouse_name: "原材料库" }]
};

assert.equal(stocktakeSummaryLineCount(emptyExported.summary), 0);
assert.equal(isEmptyStocktakeRead(emptyExported), true);
assert.equal(isEmptyStocktakeRead(importedWithDiff), false);
assert.equal(isEmptyStocktakeRead({ status: "EXPORTED" }), false);

assert.equal(nextStocktakePanel(null), "overview");
assert.equal(nextStocktakePanel({ status: "LOCKED" }), "export");
assert.equal(nextStocktakePanel({ status: "EXPORTED" }), "import");
assert.equal(nextStocktakePanel(emptyExported), "diff");
assert.equal(nextStocktakePanel({ ...emptyExported, summary: { match_count: 1 } }), "import");
assert.equal(nextStocktakePanel(importedWithDiff), "diff");
assert.equal(nextStocktakePanel({ status: "CONFIRMED" }), "history");

assert.equal(canContinueStocktake({ status: "LOCKED" }), true);
assert.equal(canContinueStocktake({ status: "EXPORTED" }), true);
assert.equal(canContinueStocktake({ status: "IMPORTED" }), true);
assert.equal(canContinueStocktake({ status: " imported " }), true);
assert.equal(canContinueStocktake({ status: "CONFIRMED" }), false);

assert.equal(findActiveStocktakeForWarehouse([importedWithDiff, lockedRaw], 1).id, 11);
assert.equal(findActiveStocktakeForWarehouse([emptyExported], 4).id, 10);
assert.equal(findActiveStocktakeForWarehouse([emptyExported], 999), null);
assert.equal(findActiveStocktakeForWarehouse([{ status: "LOCKED", warehouses: null }], 1), null);
assert.equal(stocktakeBelongsToWarehouse(lockedRaw, 1), true);
assert.equal(stocktakeBelongsToWarehouse(lockedRaw, 4), false);
assert.deepEqual(filterStocktakesForWarehouse([lockedRaw, emptyExported], 1).map((row) => row.id), [12]);
assert.equal(findOnlyActiveStocktake([lockedRaw]).id, 12);
assert.equal(findOnlyActiveStocktake([lockedRaw, importedWithDiff]), null);
assert.equal(findOnlyActiveStocktake([{ status: "CONFIRMED" }]), null);

const lines = [
  { id: 1, diff_type: "MATCH", row_status: "READY" },
  { id: 2, diff_type: "LOSS", row_status: "READY" },
  { id: 3, diff_type: "GAIN", row_status: "READY" },
  { id: 4, diff_type: "MATCH", row_status: "ERROR" }
];

assert.deepEqual(splitDiffLines(lines, "ALL").map((line) => line.id), [4, 2, 3, 1]);
assert.deepEqual(splitDiffLines(lines, "DIFF").map((line) => line.id), [4, 2, 3]);
assert.deepEqual(splitDiffLines(lines, "ERROR").map((line) => line.id), [4]);
assert.deepEqual(lines.map((line) => line.id), [1, 2, 3, 4]);
assert.equal(hasBlockingDiffErrors(lines), true);
assert.equal(diffTone({ diff_type: "GAIN", row_status: "READY" }), "gain");
assert.equal(diffTone({ diff_type: "LOSS", row_status: "READY" }), "loss");
assert.equal(diffTone({ diff_type: "NEW_LOT", row_status: "READY" }), "new");
assert.equal(diffTone({ diff_type: "MISSING", row_status: "READY" }), "missing");
assert.equal(diffTone({ diff_type: "MATCH", row_status: "ERROR" }), "error");
assert.equal(diffTone({ diff_type: "MATCH", row_status: "READY" }), "match");

const warehouseStatus = warehouseStocktakeStatus(
  { id: 1, warehouse_name: "原材料库", warehouse_type: "RAW" },
  [lockedRaw]
);

assert.equal(warehouseStatus.locked, true);
assert.equal(warehouseStatus.activeStocktake.stocktake_no, "PK-20260530-012");
assert.equal(warehouseStatus.label, "盘库中");

const componentSource = readFileSync(
  fileURLToPath(new URL("../src/components/StocktakeDialog.vue", import.meta.url)),
  "utf8"
);

assert.match(componentSource, /async function applyLoadedStocktake\(stocktake, options = \{\}\)/);
assert.match(componentSource, /await applyLoadedStocktake\(stocktake, options\);/);
assert.match(componentSource, /await applyLoadedStocktake\(exportedStocktake, \{ silent: true \}\);/);
assert.doesNotMatch(componentSource, /findOnlyActiveStocktake\(historyRows\.value\)/);
assert.match(componentSource, /findActiveStocktakeForWarehouse\(historyRows\.value, currentWarehouseId\.value\)/);
assert.match(componentSource, /\/inventory\/stocktakes\?warehouse_id=\$\{currentWarehouseId\.value\}/);
assert.match(componentSource, /import PaginationBar from "\.\/PaginationBar\.vue";/);
assert.match(componentSource, /import \{ usePagination \} from "\.\.\/utils\/pagination";/);
assert.match(componentSource, /usePagination\(currentWarehouseHistoryRows, 6\)/);
assert.match(componentSource, /class="stocktake-main"/);
assert.match(componentSource, /class="stocktake-flow-column"/);
assert.match(componentSource, /:page-size-options="\[6\]"/);
assert.match(componentSource, /v-for="row in paginatedHistoryRows"/);
assert.doesNotMatch(componentSource, /v-for="row in currentWarehouseHistoryRows"/);
assert.doesNotMatch(componentSource, /<th>操作<\/th>/);
assert.doesNotMatch(componentSource, /继续处理\s*<\/button>/);
assert.doesNotMatch(componentSource, /v-if="canContinueStocktake\(row\)"/);
assert.match(componentSource, /hasBlockingDiffErrors\(previewLines\.value\)/);
assert.match(componentSource, /盘点清单已导入：发现/);

const styleSource = readFileSync(
  fileURLToPath(new URL("../src/styles/main.css", import.meta.url)),
  "utf8"
);
assert.match(styleSource, /\.stocktake-diff-modal \.stocktake-diff-table-v2[\s\S]*margin: 14px 18px 0;/);
assert.match(styleSource, /\.stocktake-diff-modal \.stocktake-footer[\s\S]*min-height: 72px;/);
assert.match(styleSource, /\.stocktake-diff-modal-mask[\s\S]*box-sizing: border-box;/);
assert.match(styleSource, /\.stocktake-diff-modal-mask[\s\S]*z-index: 3;/);
assert.match(styleSource, /\.stocktake-diff-modal[\s\S]*height: min\(820px, 100%\);/);
assert.match(styleSource, /\.stocktake-diff-modal[\s\S]*max-height: 100%;/);
assert.doesNotMatch(styleSource, /\.stocktake-diff-modal[\s\S]*calc\(100vh - 64px\)/);
assert.match(styleSource, /\.stocktake-diff-modal \.stocktake-footer[\s\S]*justify-content: flex-end;/);
assert.match(styleSource, /\.stocktake-confirm-mask[\s\S]*z-index: 4;/);
assert.match(styleSource, /\.stocktake-diff-cell,[\s\S]*overflow-wrap: anywhere;/);
assert.match(styleSource, /\.stocktake-diff-cell span,[\s\S]*line-height: 1\.55;/);

const applyLoadedStart = componentSource.indexOf("async function applyLoadedStocktake(stocktake, options = {})");
const activeStocktakeAssignment = componentSource.indexOf("activeStocktake.value = stocktake;", applyLoadedStart);
const clearConfirmDialogAssignment = componentSource.indexOf("confirmDialogOpen.value = false;", applyLoadedStart);
const clearPreviewLinesAssignment = componentSource.indexOf("previewLines.value = [];", applyLoadedStart);
const clearActiveStocktakeAssignment = componentSource.indexOf("activeStocktake.value = null;", applyLoadedStart);
const clearPreviewSummaryAssignment = componentSource.indexOf("previewSummary.value = {};", applyLoadedStart);
const lineFetchAssignment = componentSource.indexOf(
  "fetchResource(`/inventory/stocktakes/${stocktake.id}/lines?warehouse_id=${currentWarehouseId.value}`, null)",
  applyLoadedStart
);
const lineFetchGuard = componentSource.indexOf('throw new Error("读取盘库明细失败，请重新打开盘库单");', applyLoadedStart);
const activePanelAssignment = componentSource.indexOf(
  'activePanel.value = nextPanel === "diff" || nextPanel === "history" ? "import" : nextPanel;',
  applyLoadedStart
);

assert.notEqual(applyLoadedStart, -1);
assert.notEqual(activeStocktakeAssignment, -1);
assert.notEqual(clearConfirmDialogAssignment, -1);
assert.notEqual(clearPreviewLinesAssignment, -1);
assert.notEqual(clearActiveStocktakeAssignment, -1);
assert.notEqual(clearPreviewSummaryAssignment, -1);
assert.notEqual(lineFetchAssignment, -1);
assert.notEqual(lineFetchGuard, -1);
assert.notEqual(activePanelAssignment, -1);
assert.ok(clearConfirmDialogAssignment < lineFetchAssignment);
assert.ok(clearPreviewLinesAssignment < lineFetchAssignment);
assert.ok(clearActiveStocktakeAssignment < lineFetchAssignment);
assert.ok(clearPreviewSummaryAssignment < lineFetchAssignment);
assert.ok(lineFetchAssignment < activeStocktakeAssignment);
assert.ok(lineFetchAssignment < activePanelAssignment);

console.log("stocktake workflow tests passed");
