const assert = require("assert");
const fs = require("fs");
const path = require("path");
const vm = require("vm");

const {
  LABEL_TEMPLATES,
  getLabelTemplatesByKind,
  getLabelTemplateById,
  buildTemplateFormState,
  buildTemplatePreviewItems,
} = require("../static/label-templates.js");

{
  const source = fs.readFileSync(path.join(__dirname, "../static/label-templates.js"), "utf8");
  const context = {
    module: { exports: {} },
    exports: {},
    require,
    console,
  };

  vm.runInNewContext(source, context, { filename: "label-templates.js" });
  assert(context.module.exports.getLabelTemplates, "module export should load without globalThis");
}

assert(LABEL_TEMPLATES.length >= 8, "should expose a common template library");

{
  const blankTemplates = getLabelTemplatesByKind("blank");
  const businessTemplates = getLabelTemplatesByKind("business");

  assert(blankTemplates.length >= 5, "should include several blank templates");
  assert(businessTemplates.length >= 4, "should include several business templates");
}

{
  const shipping = buildTemplateFormState("shipping-waybill");

  assert.strictEqual(shipping.labelType, "roll");
  assert.strictEqual(shipping.widthMm, 100);
  assert.strictEqual(shipping.heightMm, 150);
  assert.strictEqual(shipping.paperPreset, "match");
  assert(shipping.content.length >= 5, "shipping template should carry default layout content");
}

{
  const a4 = buildTemplateFormState("blank-a4-63x38");

  assert.strictEqual(a4.labelType, "flat");
  assert.strictEqual(a4.paperPreset, "a4");
  assert.strictEqual(a4.paperWidthMm, 210);
  assert.strictEqual(a4.paperHeightMm, 297);
  assert(a4.marginTopMm > 0, "flat template should include paper margins");
  assert(a4.gapXmm >= 0, "flat template should include column gap");
}

{
  const a4Template = getLabelTemplateById("blank-a4-63x38");

  assert.strictEqual(a4Template.labelType, "flat");
  assert.strictEqual(a4Template.paper.matchLabel, false);
}

{
  const product = getLabelTemplateById("product-price-tag");
  const objectTypes = product.content.map((item) => item.type);

  assert(objectTypes.includes("barcode"), "product template should include a barcode");
  assert(objectTypes.includes("text"), "product template should include text content");
}

{
  const items = buildTemplatePreviewItems("product-price-tag");
  const barcodeItem = items.find((item) => item.type === "barcode");
  const titleItem = items.find((item) => item.type === "text");

  assert(barcodeItem, "preview items should include barcode blocks");
  assert(titleItem, "preview items should include text blocks");
  assert(barcodeItem.left >= 0 && barcodeItem.left <= 100, "preview position should be normalized");
  assert(barcodeItem.top >= 0 && barcodeItem.top <= 100, "preview position should be normalized");
  assert(barcodeItem.width > 0, "barcode preview should have width");
}

{
  const items = buildTemplatePreviewItems("shipping-waybill");
  const lineItem = items.find((item) => item.type === "line");
  const qrcodeItem = items.find((item) => item.type === "qrcode");

  assert(lineItem, "line-based templates should expose preview lines");
  assert(qrcodeItem, "preview items should include QR blocks");
  assert(lineItem.width > 0, "line preview should compute a visible width");
}

{
  const a4Template = getLabelTemplateById("blank-a4-63x38");
  const preview = buildTemplatePreviewItems("blank-a4-63x38");

  assert.strictEqual(a4Template.labelType, "flat");
  assert(preview.length > 3, "flat-paper preview should expose multiple sheet cells");
  assert(preview.some((item) => item.type === "sheet"), "flat-paper preview should include a sheet frame");
  assert(preview.filter((item) => item.type === "cell").length >= 3, "A4 three-column layout should expose multiple cells");
  assert(
    preview.some((item) => item.type === "cell" && item.emphasis === "primary"),
    "flat-paper preview should highlight the edited cell"
  );
}

{
  const discSmall = buildTemplateFormState("blank-disc-120-small-hub");
  const discSmallPreview = buildTemplatePreviewItems("blank-disc-120-small-hub");
  const discStandard = buildTemplateFormState("blank-disc-120-standard");
  const discStandardPreview = buildTemplatePreviewItems("blank-disc-120-standard");

  assert.strictEqual(discSmall.labelType, "roll");
  assert.strictEqual(discSmall.widthMm, 120);
  assert.strictEqual(discSmall.heightMm, 120);
  assert.strictEqual(discSmall.paperPreset, "match");
  assert.strictEqual(discStandard.paperPreset, "match");
  assert.strictEqual(discSmallPreview.filter((item) => item.type === "circle").length, 2, "small-hub disc template should expose outer and inner guide rings");
  assert.strictEqual(discStandardPreview.filter((item) => item.type === "circle").length, 2, "standard disc template should expose outer and inner guide rings");
  const smallInnerRing = discSmallPreview.filter((item) => item.type === "circle").sort((a, b) => a.width - b.width)[0];
  const standardInnerRing = discStandardPreview.filter((item) => item.type === "circle").sort((a, b) => a.width - b.width)[0];
  assert(smallInnerRing.width < standardInnerRing.width, "small-hub template should use a smaller inner ring than the standard template");
}

{
  const productItems = buildTemplatePreviewItems("product-price-tag");

  assert(productItems.some((item) => item.type === "text"), "business preview should still include text objects");
  assert(!productItems.some((item) => item.type === "sheet"), "business preview should not switch to sheet mode");
}

console.log("label template tests passed");
