import {
  Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
  AlignmentType, BorderStyle, WidthType, ShadingType, VerticalAlign,
  LevelFormat, Header, Footer, PageNumber, PageBreak, HeadingLevel,
  TabStopType, TabStopPosition,
} from "docx";
import { writeFileSync } from "fs";

// ── Palette ───────────────────────────────────────────────────────────────────
const NAVY   = "1B2A4A";
const ACCENT = "2E86C1";
const GREEN  = "1A6B2A";
const GRAY   = "F4F6F8";
const LGRAY  = "EEEEEE";
const DGRAY  = "555555";
const WHITE  = "FFFFFF";
const BLACK  = "000000";
const BD     = { style: BorderStyle.SINGLE, size: 1, color: "CCCCCC" };
const allBd  = { top: BD, bottom: BD, left: BD, right: BD };
const noBd   = { top: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
                 bottom: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
                 left:   { style: BorderStyle.NONE, size: 0, color: "FFFFFF" },
                 right:  { style: BorderStyle.NONE, size: 0, color: "FFFFFF" } };
const W = 9026; // A4 content width (1" margins each side)

// ── Helpers ───────────────────────────────────────────────────────────────────
const sp = (before = 0, after = 120) => ({ before, after });

function h1(text, id) {
  const para = new Paragraph({
    spacing: sp(360, 120),
    border: { bottom: { style: BorderStyle.SINGLE, size: 8, color: ACCENT, space: 4 } },
    children: [new TextRun({ text, bold: true, size: 32, color: NAVY, font: "Arial" })],
  });
  return para;
}

function h2(text) {
  return new Paragraph({
    spacing: sp(240, 100),
    children: [
      new TextRun({ text: "  ", size: 24, font: "Arial" }),
      new TextRun({ text, bold: true, size: 24, color: ACCENT, font: "Arial" }),
    ],
    border: { left: { style: BorderStyle.THICK, size: 10, color: ACCENT, space: 8 } },
  });
}

function p(text, opts = {}) {
  const { bold = false, size = 20, color = "333333", indent = false, spacing = sp(0, 100) } = opts;
  return new Paragraph({
    spacing,
    indent: indent ? { left: 360 } : undefined,
    children: [new TextRun({ text, bold, size, color, font: "Arial" })],
  });
}

function note(text) {
  return new Paragraph({
    spacing: sp(80, 160),
    indent: { left: 200 },
    border: { left: { style: BorderStyle.SINGLE, size: 6, color: "F39C12", space: 6 } },
    children: [new TextRun({ text: `\u26A0  ${text}`, size: 18, italics: true, color: "7D6608", font: "Arial" })],
  });
}

function bullet(text, sub = false) {
  return new Paragraph({
    numbering: { reference: sub ? "sub-bullets" : "bullets", level: 0 },
    spacing: sp(0, 80),
    children: [new TextRun({ text, size: 20, font: "Arial", color: "333333" })],
  });
}

// Code block: gray box, Courier New
function codeBlock(lines) {
  return new Table({
    width: { size: W, type: WidthType.DXA },
    columnWidths: [W],
    borders: { top: BD, bottom: BD, left: BD, right: BD, insideH: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" }, insideV: { style: BorderStyle.NONE, size: 0, color: "FFFFFF" } },
    rows: [
      new TableRow({
        children: [
          new TableCell({
            borders: noBd,
            width: { size: W, type: WidthType.DXA },
            shading: { fill: "F0F0F0", type: ShadingType.CLEAR },
            margins: { top: 120, bottom: 120, left: 200, right: 200 },
            children: lines.map(l => new Paragraph({
              spacing: sp(0, 40),
              children: [new TextRun({ text: l, size: 18, font: "Courier New", color: "1A1A2E" })],
            })),
          }),
        ],
      }),
    ],
  });
}

// Info box (blue bg)
function infoBox(lines) {
  return new Table({
    width: { size: W, type: WidthType.DXA },
    columnWidths: [W],
    rows: [new TableRow({ children: [new TableCell({
      borders: noBd,
      width: { size: W, type: WidthType.DXA },
      shading: { fill: "EAF4FB", type: ShadingType.CLEAR },
      margins: { top: 120, bottom: 120, left: 200, right: 200 },
      children: lines.map(l => new Paragraph({
        spacing: sp(0, 60),
        children: [new TextRun({ text: l, size: 19, font: "Arial", color: "1A4A6B" })],
      })),
    })] })],
  });
}

// Generic table
function makeTable(headers, rows, colWidths, headerBg = NAVY) {
  const total = colWidths.reduce((a, b) => a + b, 0);
  function hdrCell(text, w) {
    return new TableCell({
      borders: allBd, width: { size: w, type: WidthType.DXA },
      shading: { fill: headerBg, type: ShadingType.CLEAR },
      verticalAlign: VerticalAlign.CENTER,
      margins: { top: 80, bottom: 80, left: 120, right: 120 },
      children: [new Paragraph({ alignment: AlignmentType.CENTER, children: [new TextRun({ text, bold: true, size: 19, color: WHITE, font: "Arial" })] })],
    });
  }
  function dataCell(text, w, i) {
    const isCode = text.startsWith("$ ") || text.startsWith("pnpm ") || text.startsWith("pm2 ") || text.startsWith("systemctl ") || text.startsWith("curl ");
    return new TableCell({
      borders: allBd, width: { size: w, type: WidthType.DXA },
      shading: { fill: i % 2 === 0 ? WHITE : GRAY, type: ShadingType.CLEAR },
      verticalAlign: VerticalAlign.CENTER,
      margins: { top: 80, bottom: 80, left: 120, right: 120 },
      children: [new Paragraph({ children: [new TextRun({ text, size: 19, font: isCode ? "Courier New" : "Arial", color: isCode ? "1A1A2E" : "333333" })] })],
    });
  }
  return new Table({
    width: { size: total, type: WidthType.DXA },
    columnWidths: colWidths,
    rows: [
      new TableRow({ tableHeader: true, children: headers.map((h, i) => hdrCell(h, colWidths[i])) }),
      ...rows.map((row, ri) => new TableRow({ children: row.map((cell, ci) => dataCell(cell, colWidths[ci], ri)) })),
    ],
  });
}

function gap(n = 1) { return Array.from({ length: n }, () => new Paragraph({ spacing: sp(0, 60), children: [new TextRun("")] })); }
function pageBreak() { return new Paragraph({ children: [new PageBreak()] }); }

// ── Document ─────────────────────────────────────────────────────────────────
const doc = new Document({
  numbering: {
    config: [
      { reference: "bullets", levels: [{ level: 0, format: LevelFormat.BULLET, text: "\u2022", alignment: AlignmentType.LEFT, style: { paragraph: { indent: { left: 600, hanging: 300 } } } }] },
      { reference: "sub-bullets", levels: [{ level: 0, format: LevelFormat.BULLET, text: "\u25E6", alignment: AlignmentType.LEFT, style: { paragraph: { indent: { left: 900, hanging: 300 } } } }] },
    ],
  },
  styles: {
    default: { document: { run: { font: "Arial", size: 20, color: "333333" } } },
  },
  sections: [{
    properties: {
      page: {
        size: { width: 11906, height: 16838 }, // A4
        margin: { top: 1080, right: 1080, bottom: 1080, left: 1080 },
      },
    },
    headers: {
      default: new Header({ children: [
        new Paragraph({
          border: { bottom: { style: BorderStyle.SINGLE, size: 4, color: ACCENT, space: 4 } },
          spacing: sp(0, 120),
          children: [
            new TextRun({ text: "Homelegance Chatbot \u2014 \u751F\u4EA7\u90E8\u7F72\u6587\u6863", size: 17, color: "888888", font: "Arial" }),
            new TextRun({ text: "\t", size: 17, font: "Arial" }),
            new TextRun({ text: "2026\u5E744\u6708", size: 17, color: "888888", font: "Arial" }),
          ],
          tabStops: [{ type: TabStopType.RIGHT, position: TabStopPosition.MAX }],
        }),
      ] }),
    },
    footers: {
      default: new Footer({ children: [
        new Paragraph({
          border: { top: { style: BorderStyle.SINGLE, size: 2, color: "CCCCCC", space: 4 } },
          spacing: sp(80, 0),
          alignment: AlignmentType.CENTER,
          children: [
            new TextRun({ text: "United-US \u5185\u90E8\u6587\u6863  |  \u7AC5\u673A\u5BC6 \u2014 \u8BF7\u52FF\u5916\u4F20  |  \u7B2C ", size: 16, color: "888888", font: "Arial" }),
            new TextRun({ children: [PageNumber.CURRENT], size: 16, color: "888888", font: "Arial" }),
            new TextRun({ text: " \u9875", size: 16, color: "888888", font: "Arial" }),
          ],
        }),
      ] }),
    },
    children: [
      // ── Cover ──────────────────────────────────────────────────────────
      new Paragraph({ spacing: sp(400, 0), children: [new TextRun({ text: "", size: 20 })] }),
      new Paragraph({
        spacing: sp(0, 80),
        children: [new TextRun({ text: "Homelegance Chatbot", bold: true, size: 64, color: NAVY, font: "Arial" })],
      }),
      new Paragraph({
        spacing: sp(0, 60),
        children: [new TextRun({ text: "\u751F\u4EA7\u90E8\u7F72\u6587\u6863", bold: true, size: 44, color: ACCENT, font: "Arial" })],
      }),
      new Paragraph({
        spacing: sp(0, 400),
        border: { bottom: { style: BorderStyle.SINGLE, size: 6, color: ACCENT, space: 6 } },
        children: [new TextRun({ text: "AlmaLinux 8.10  |  Apache \u53CD\u5411\u4EE3\u7406  |  PostgreSQL \u72EC\u7ACB DB \u670D\u52A1\u5668", size: 20, color: DGRAY, font: "Arial" })],
      }),
      ...gap(2),
      infoBox([
        "\uD83D\uDDA5  Web \u670D\u52A1\u5668\uFF1A  aga-web1-services   /   AlmaLinux 8.10",
        "\uD83D\uDCC2  \u90E8\u7F72\u8DEF\u5F84\uFF1A     /redant/web/homelegance-chatbot",
        "\uD83D\uDD17  Git \u4ED3\u5E93\uFF1A     https://git.united-us.net/TonyT/chatbot.git",
        "\uD83E\uDD16  LLM\uFF1A          Anthropic Claude API  (claude-sonnet-4-6)",
        "\uD83D\uDDB3  \u6570\u636E\u5E93\uFF1A      \u5185\u7F51\u72EC\u7ACB PostgreSQL \u670D\u52A1\u5668  \u00B7  Schema: chatbot",
      ]),
      pageBreak(),

      // ── Ch1 ────────────────────────────────────────────────────────────
      h1("\u7B2C\u4E00\u7AE0  \u73AF\u5883\u8981\u6C42"),
      h2("1.1  \u670D\u52A1\u5668\u4FE1\u606F"),
      ...gap(),
      makeTable(
        ["\u9879\u76EE", "\u8BE6\u60C5"],
        [
          ["\u64CD\u4F5C\u7CFB\u7EDF",     "AlmaLinux 8.10"],
          ["Web \u670D\u52A1\u5668",        "Apache httpd\uFF08\u7EDF\u4E00\u51FA\u53E3\uFF09"],
          ["\u90E8\u7F72\u8DEF\u5F84",      "/redant/web/homelegance-chatbot"],
          ["Node.js",                        "v20.20.2 LTS"],
          ["\u5305\u7BA1\u7406\u5668",      "pnpm v10.x"],
          ["\u8FDB\u7A0B\u7BA1\u7406",      "PM2"],
          ["\u6570\u636E\u5E93\u670D\u52A1\u5668", "\u5185\u7F51\u72EC\u7ACB PostgreSQL \u670D\u52A1\u5668"],
          ["\u6570\u636E\u5E93 Schema",      "chatbot\uFF08\u72EC\u7ACB Schema\uFF09"],
          ["LLM API",                        "Anthropic Claude API\uFF08claude-sonnet-4-6\uFF09"],
          ["ERP \u6865\u63A5\u670D\u52A1",  "Python FastAPI\uFF08/redant/web/erp-bridge\uFF09"],
        ],
        [3000, 6026],
      ),
      ...gap(2),
      h2("1.2  \u7F51\u7EDC\u8981\u6C42"),
      ...gap(),
      bullet("Web \u670D\u52A1\u5668\u9700\u8BBF\u95EE npm registry\uFF08pnpm install \u4F9D\u8D56\u5B89\u88C5\uFF09"),
      bullet("Web \u670D\u52A1\u5668\u9700\u8BBF\u95EE api.anthropic.com\uFF08Claude API \u8C03\u7528\uFF09"),
      bullet("\u5185\u7F51\u53EF\u8BBF\u95EE PostgreSQL DB \u670D\u52A1\u5668\uFF085432 \u7AEF\u53E3\uFF09"),
      bullet("Apache \u5BF9\u5916\u5F00\u653E 80 / 443 \u7AEF\u53E3"),
      bullet("Node.js :3000 \u3001FastAPI :8080 \u4EC5\u672C\u673A\u8BBF\u95EE\uFF0C\u4E0D\u5BF9\u5916\u66B4\u9732"),
      pageBreak(),

      // ── Ch2 ────────────────────────────────────────────────────────────
      h1("\u7B2C\u4E8C\u7AE0  Node.js \u5B89\u88C5"),
      note("AlmaLinux 8 \u7CFB\u7EDF\u81EA\u5E26 Node.js 10\uFF0C\u4E0E\u9879\u76EE\u4E0D\u517C\u5BB9\uFF0C\u5FC5\u987B\u5347\u7EA7\u5230 v20\u3002"),
      ...gap(),
      h2("2.1  \u79FB\u9664\u65E7\u7248\u672C"),
      ...gap(),
      codeBlock([
        "dnf remove -y nodejs npm",
      ]),
      ...gap(),
      h2("2.2  \u5B89\u88C5 Node.js 20 LTS\uFF08\u901A\u8FC7 NodeSource\uFF09"),
      ...gap(),
      codeBlock([
        "curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -",
        "dnf install -y nodejs --allowerasing",
        "node --version    # \u5E94\u663E\u793A v20.x.x",
      ]),
      ...gap(),
      h2("2.3  \u5B89\u88C5 pnpm \u548C PM2"),
      ...gap(),
      codeBlock([
        "npm install -g pnpm",
        "npm install -g pm2",
        "pnpm --version",
        "pm2 --version",
      ]),
      ...gap(2),
      h2("2.4  \u5E38\u89C1\u95EE\u9898\uFF1Anode \u547D\u4EE4\u627E\u4E0D\u5230"),
      ...gap(),
      p("\u539F\u56E0\uFF1A\u65E7 nvm \u8DEF\u5F84\u6B8B\u7559\u5728 PATH \u4E2D\uFF0C\u89E3\u51B3\u65B9\u6CD5\uFF1A"),
      ...gap(),
      codeBlock([
        "unset NVM_DIR",
        "hash -r",
        "which node",
        "",
        "# \u5982\u4ECD\u65E0\u6CD5\u627E\u5230\uFF0C\u624B\u52A8\u8BBE\u7F6E PATH\uFF1A",
        "export PATH=\"/usr/bin:$PATH\"",
        "node --version",
      ]),
      pageBreak(),

      // ── Ch3 ────────────────────────────────────────────────────────────
      h1("\u7B2C\u4E09\u7AE0  \u4EE3\u7801\u90E8\u7F72"),
      h2("3.1  \u521B\u5EFA\u90E8\u7F72\u76EE\u5F55\u5E76\u62C9\u53D6\u4EE3\u7801"),
      ...gap(),
      codeBlock([
        "mkdir -p /redant/web/homelegance-chatbot",
        "cd /redant/web/homelegance-chatbot",
        "git clone https://git.united-us.net/TonyT/chatbot.git .",
      ]),
      ...gap(),
      h2("3.2  \u5B89\u88C5\u4F9D\u8D56"),
      ...gap(),
      codeBlock(["pnpm install"]),
      p("\u5B89\u88C5\u6210\u529F\u6807\u5FD7\uFF1A\u663E\u793A \u201CDone in Xs using pnpm vX.X.X\u201D", { color: GREEN, indent: true }),
      ...gap(),
      h2("3.3  \u914D\u7F6E\u73AF\u5883\u53D8\u91CF"),
      ...gap(),
      codeBlock([
        "cp deploy/env.production.example .env.production",
        "vi .env.production",
      ]),
      ...gap(),
      p(".env.production \u5185\u5BB9\uFF08\u9700\u586B\u5199\u5B9E\u9645\u503C\uFF09\uFF1A"),
      ...gap(),
      codeBlock([
        "NODE_ENV=production",
        "PORT=3000",
        "DATABASE_URL=postgresql://chatbot_user:PASSWORD@DB_SERVER_IP:5432/homelegance",
        "JWT_SECRET=\uFF08\u4F7F\u7528 openssl rand -hex 32 \u751F\u6210\uFF09",
        "ANTHROPIC_API_KEY=sk-ant-xxxxxxxx",
        "ERP_API_URL=http://127.0.0.1:8080",
        "ERP_API_KEY=\uFF08\u5185\u90E8\u968F\u673A\u5BC6\u9470\uFF09",
        "DEALER_PORTAL_SSO_SECRET=\uFF08\u4E0E Dealer Portal \u7EA6\u5B9A\u7684\u5171\u4EAB\u5BC6\u9470\uFF09",
      ]),
      ...gap(),
      h2("3.4  \u6784\u5EFA\u9879\u76EE"),
      ...gap(),
      codeBlock(["pnpm build"]),
      ...gap(),
      p("\u6784\u5EFA\u8F93\u51FA\uFF1A"),
      bullet("dist/public/    \u524D\u7AEF\u9759\u6001\u6587\u4EF6\uFF08\u7531 Apache \u76F4\u63A5\u670D\u52A1\uFF09"),
      bullet("dist/index.js   \u540E\u7AEF Node.js bundle\uFF08\u7531 PM2 \u8FD0\u884C\uFF09"),
      pageBreak(),

      // ── Ch4 ────────────────────────────────────────────────────────────
      h1("\u7B2C\u56DB\u7AE0  \u6570\u636E\u5E93\u521D\u59CB\u5316"),
      h2("4.1  DBA \u64CD\u4F5C\uFF08\u5728 DB \u670D\u52A1\u5668\u4E0A\u6267\u884C\uFF0C\u4EC5\u9700\u4E00\u6B21\uFF09"),
      ...gap(),
      codeBlock([
        "-- \u521B\u5EFA\u6570\u636E\u5E93\uFF08\u5982\u5C1A\u672A\u5B58\u5728\uFF09",
        "CREATE DATABASE homelegance;",
        "",
        "-- \u521B\u5EFA\u4E13\u7528\u7528\u6237",
        "CREATE USER chatbot_user WITH PASSWORD 'your_password';",
        "",
        "-- \u521B\u5EFA chatbot \u4E13\u5C5E Schema",
        "\\c homelegance",
        "CREATE SCHEMA chatbot;",
        "",
        "-- \u6388\u6743",
        "GRANT ALL ON SCHEMA chatbot TO chatbot_user;",
        "GRANT ALL PRIVILEGES ON DATABASE homelegance TO chatbot_user;",
        "ALTER DEFAULT PRIVILEGES IN SCHEMA chatbot",
        "  GRANT ALL ON TABLES TO chatbot_user;",
        "ALTER DEFAULT PRIVILEGES IN SCHEMA chatbot",
        "  GRANT ALL ON SEQUENCES TO chatbot_user;",
      ]),
      ...gap(),
      h2("4.2  \u5728 Web \u670D\u52A1\u5668\u4E0A\u521D\u59CB\u5316\u8868\u7ED3\u6784"),
      ...gap(),
      codeBlock([
        "cd /redant/web/homelegance-chatbot",
        "pnpm db:push",
      ]),
      ...gap(),
      p("\u6B64\u547D\u4EE4\u4F1A\u5728 chatbot schema \u4E0B\u81EA\u52A8\u521B\u5EFA\u6240\u6709\u8868\u548C\u679A\u4E3E\u7C7B\u578B\uFF1A"),
      ...gap(),
      makeTable(
        ["\u8868\u540D", "\u7528\u9014"],
        [
          ["chatbot.users",               "\u7528\u6237 / Agent \u8D26\u53F7"],
          ["chatbot.conversations",        "\u5BF9\u8BDD\u4F1A\u8BDD"],
          ["chatbot.messages",            "\u804A\u5929\u6D88\u606F"],
          ["chatbot.invitations",          "\u9080\u8BF7\u94FE\u63A5"],
          ["chatbot.audit_logs",          "\u5BA1\u8BA1\u65E5\u5FD7"],
          ["chatbot.workflow_nodes/edges", "\u5DE5\u4F5C\u6D41\u8BBE\u8BA1\u5668"],
          ["chatbot.analytics_events",    "\u8BBF\u95EE\u5206\u6790"],
          ["chatbot.data_sources",        "\u77E5\u8BC6\u5E93\u914D\u7F6E"],
          ["chatbot.api_connections",     "API \u8FDE\u63A5\u914D\u7F6E"],
        ],
        [3500, 5526],
      ),
      pageBreak(),

      // ── Ch5 ────────────────────────────────────────────────────────────
      h1("\u7B2C\u4E94\u7AE0  PM2 \u8FDB\u7A0B\u914D\u7F6E"),
      h2("5.1  \u542F\u52A8\u670D\u52A1"),
      ...gap(),
      codeBlock([
        "cd /redant/web/homelegance-chatbot",
        "pm2 start ecosystem.config.cjs",
        "pm2 status",
      ]),
      ...gap(),
      h2("5.2  \u8BBE\u7F6E\u5F00\u673A\u81EA\u542F"),
      ...gap(),
      codeBlock([
        "pm2 save",
        "pm2 startup systemd",
        "# \u6309\u7167\u8F93\u51FA\u63D0\u793A\u6267\u884C\u5BF9\u5E94\u7684 systemctl \u547D\u4EE4",
      ]),
      ...gap(),
      h2("5.3  \u5E38\u7528 PM2 \u547D\u4EE4"),
      ...gap(),
      makeTable(
        ["\u547D\u4EE4", "\u8BF4\u660E"],
        [
          ["pm2 status",                           "\u67E5\u770B\u670D\u52A1\u72B6\u6001"],
          ["pm2 logs homelegance-chat",            "\u5B9E\u65F6\u67E5\u770B\u65E5\u5FD7"],
          ["pm2 restart homelegance-chat",         "\u91CD\u542F\u670D\u52A1"],
          ["pm2 stop homelegance-chat",            "\u505C\u6B62\u670D\u52A1"],
          ["pm2 reload homelegance-chat",          "\u96F6\u505C\u673A\u91CD\u8F7D\uFF08\u66F4\u65B0\u4EE3\u7801\u540E\u4F7F\u7528\uFF09"],
        ],
        [4000, 5026],
      ),
      pageBreak(),

      // ── Ch6 ────────────────────────────────────────────────────────────
      h1("\u7B2C\u516D\u7AE0  Apache \u53CD\u5411\u4EE3\u7406\u914D\u7F6E"),
      h2("6.1  \u9A8C\u8BC1\u5FC5\u8981\u6A21\u5757"),
      ...gap(),
      codeBlock(["httpd -M | grep -E \"proxy|rewrite|headers\""]),
      ...gap(),
      h2("6.2  \u90E8\u7F72\u865A\u62DF\u4E3B\u673A\u914D\u7F6E"),
      ...gap(),
      codeBlock([
        "cp /redant/web/homelegance-chatbot/deploy/homelegance-chat.conf /etc/httpd/conf.d/",
        "vi /etc/httpd/conf.d/homelegance-chat.conf   # \u586B\u5199\u57DF\u540D\u548C SSL \u8BC1\u4E66\u8DEF\u5F84",
      ]),
      ...gap(),
      h2("6.3  \u914D\u7F6E\u8981\u70B9"),
      ...gap(),
      bullet("DocumentRoot \u2192 /redant/web/homelegance-chatbot/dist/public\uFF08\u9759\u6001\u6587\u4EF6\u7531 Apache \u76F4\u63A5\u670D\u52A1\uFF09"),
      bullet("/api/* \u8BF7\u6C42 ProxyPass \u8F6C\u53D1\u81F3 Node.js localhost:3000"),
      bullet("\u975E\u6587\u4EF6\u8DEF\u5F84\u8BF7\u6C42 Rewrite \u81F3 index.html\uFF08\u652F\u6301 React SPA \u8DEF\u7531\uFF09"),
      bullet("80 \u7AEF\u53E3\u81EA\u52A8\u8DF3\u8F6C HTTPS"),
      ...gap(),
      h2("6.4  \u9A8C\u8BC1\u5E76\u91CD\u8F7D"),
      ...gap(),
      codeBlock([
        "apachectl configtest    # \u9A8C\u8BC1\u914D\u7F6E\u8BED\u6CD5",
        "systemctl reload httpd  # \u91CD\u8F7D\u914D\u7F6E",
      ]),
      ...gap(),
      h2("6.5  \u9632\u706B\u5899\u8BBE\u7F6E"),
      ...gap(),
      codeBlock([
        "firewall-cmd --permanent --add-service=http",
        "firewall-cmd --permanent --add-service=https",
        "firewall-cmd --reload",
        "# Node.js :3000 \u548C FastAPI :8080 \u4E0D\u5BF9\u5916\u5F00\u653E",
      ]),
      pageBreak(),

      // ── Ch7 ────────────────────────────────────────────────────────────
      h1("\u7B2C\u4E03\u7AE0  ERP FastAPI \u6865\u63A5\u670D\u52A1"),
      h2("7.1  \u5B89\u88C5 Python \u4F9D\u8D56"),
      ...gap(),
      codeBlock([
        "dnf install -y python3.11 python3.11-pip",
        "pip3.11 install fastapi uvicorn asyncpg python-dotenv",
      ]),
      ...gap(),
      h2("7.2  \u521B\u5EFA\u670D\u52A1\u76EE\u5F55"),
      ...gap(),
      codeBlock(["mkdir -p /redant/web/erp-bridge"]),
      ...gap(),
      h2("7.3  \u914D\u7F6E\u73AF\u5883\u53D8\u91CF"),
      ...gap(),
      p("\u521B\u5EFA /redant/web/erp-bridge/.env\uFF1A"),
      ...gap(),
      codeBlock([
        "ERP_DATABASE_URL=postgresql://chatbot_readonly:PASSWORD@ERP_DB_SERVER:5432/erp_db",
        "ERP_API_KEY=\uFF08\u4E0E chatbot .env.production \u4E2D ERP_API_KEY \u76F8\u540C\uFF09",
        "PORT=8080",
      ]),
      ...gap(),
      h2("7.4  ERP \u6570\u636E\u5E93\u53EA\u8BFB\u8D26\u53F7\uFF08\u7531 ERP DBA \u521B\u5EFA\uFF09"),
      ...gap(),
      codeBlock([
        "CREATE USER chatbot_readonly WITH PASSWORD 'readonly_password';",
        "GRANT SELECT ON TABLE",
        "  items, contacts, sales_orders, sales_order_items, stock",
        "  TO chatbot_readonly;",
      ]),
      ...gap(),
      h2("7.5  \u90E8\u7F72 Systemd \u670D\u52A1"),
      ...gap(),
      codeBlock([
        "cp /redant/web/homelegance-chatbot/deploy/erp-bridge.service /etc/systemd/system/",
        "systemctl daemon-reload",
        "systemctl enable --now erp-bridge",
        "systemctl status erp-bridge",
      ]),
      pageBreak(),

      // ── Ch8 ────────────────────────────────────────────────────────────
      h1("\u7B2C\u516B\u7AE0  \u66F4\u65B0\u90E8\u7F72\u6D41\u7A0B"),
      h2("8.1  \u5E38\u89C4\u4EE3\u7801\u66F4\u65B0"),
      ...gap(),
      codeBlock([
        "cd /redant/web/homelegance-chatbot",
        "git pull origin master",
        "pnpm install              # \u5982\u6709\u65B0\u4F9D\u8D56",
        "pnpm build                # \u91CD\u65B0\u6784\u5EFA",
        "pm2 reload homelegance-chat   # \u96F6\u505C\u673A\u91CD\u8F7D",
      ]),
      ...gap(),
      h2("8.2  \u5982\u6709\u6570\u636E\u5E93 Schema \u53D8\u66F4"),
      ...gap(),
      codeBlock(["pnpm db:push"]),
      pageBreak(),

      // ── Ch9 ────────────────────────────────────────────────────────────
      h1("\u7B2C\u4E5D\u7AE0  \u9A8C\u8BC1\u68C0\u67E5\u6E05\u5355"),
      h2("9.1  \u670D\u52A1\u72B6\u6001\u68C0\u67E5"),
      ...gap(),
      makeTable(
        ["\u68C0\u67E5\u9879", "\u547D\u4EE4", "\u671F\u671B\u7ED3\u679C"],
        [
          ["Node.js \u670D\u52A1",   "pm2 status",                                        "online"],
          ["Apache \u670D\u52A1",    "systemctl status httpd",                             "active (running)"],
          ["ERP Bridge",             "systemctl status erp-bridge",                        "active (running)"],
          ["\u5065\u5EB7\u68C0\u67E5", "curl http://localhost:3000/api/trpc/system.health", "\u8FD4\u56DE 200"],
          ["\u524D\u7AEF\u8BBF\u95EE", "curl -I https://chat.homelegance.com",             "HTTP 200"],
        ],
        [2200, 4500, 2326],
      ),
      ...gap(2),
      h2("9.2  \u65E5\u5FD7\u4F4D\u7F6E"),
      ...gap(),
      makeTable(
        ["\u65E5\u5FD7\u7C7B\u578B", "\u8DEF\u5F84"],
        [
          ["Node.js \u8F93\u51FA\u65E5\u5FD7",  "/var/log/pm2/homelegance-chat-out.log"],
          ["Node.js \u9519\u8BEF\u65E5\u5FD7",  "/var/log/pm2/homelegance-chat-error.log"],
          ["Apache \u8BBF\u95EE\u65E5\u5FD7",   "/var/log/httpd/homelegance-chat-access.log"],
          ["Apache \u9519\u8BEF\u65E5\u5FD7",   "/var/log/httpd/homelegance-chat-error.log"],
          ["ERP Bridge \u65E5\u5FD7",            "journalctl -u erp-bridge -f"],
        ],
        [3000, 6026],
      ),
      pageBreak(),

      // ── Ch10 ───────────────────────────────────────────────────────────
      h1("\u7B2C\u5341\u7AE0  \u73AF\u5883\u53D8\u91CF\u5B8C\u6574\u53C2\u8003"),
      ...gap(),
      makeTable(
        ["\u53D8\u91CF\u540D", "\u8BF4\u660E", "\u793A\u4F8B\u503C", "\u5FC5\u586B"],
        [
          ["NODE_ENV",                "\u8FD0\u884C\u73AF\u5883",               "production",                          "\u662F"],
          ["PORT",                    "Node.js \u76D1\u542C\u7AEF\u53E3",       "3000",                                "\u5426\uFF08\u9ED8\u8BA43000\uFF09"],
          ["DATABASE_URL",            "Chatbot PostgreSQL \u8FDE\u63A5\u4E32",  "postgresql://user:pwd@host:5432/db",  "\u662F"],
          ["JWT_SECRET",              "Session \u7B7E\u540D\u5BC6\u9470",       "openssl rand -hex 32 \u751F\u6210",   "\u662F"],
          ["ANTHROPIC_API_KEY",       "Claude API \u5BC6\u9470",                "sk-ant-...",                          "\u662F"],
          ["ERP_API_URL",             "ERP Bridge \u5185\u7F51\u5730\u5740",    "http://127.0.0.1:8080",               "\u662F"],
          ["ERP_API_KEY",             "ERP Bridge \u8BBF\u95EE\u5BC6\u9470",    "\u968F\u673A\u5B57\u7B26\u4E32",      "\u662F"],
          ["DEALER_PORTAL_SSO_SECRET","Dealer Portal SSO \u5171\u4EAB\u5BC6\u9470","Portal \u56E2\u961F\u7EA6\u5B9A",  "SSO \u542F\u7528\u65F6"],
        ],
        [2600, 2800, 2400, 1226],
      ),
      pageBreak(),

      // ── Appendix ───────────────────────────────────────────────────────
      h1("\u9644\u5F55  Git \u4ED3\u5E93\u4E0E\u914D\u7F6E\u6587\u4EF6"),
      ...gap(),
      infoBox([
        "\uD83D\uDD17  \u4ED3\u5E93\u5730\u5740\uFF1A  https://git.united-us.net/TonyT/chatbot.git",
        "\uD83C\uDF3F  \u4E3B\u5206\u652F\uFF1A    master",
        "\uD83D\uDCC2  \u914D\u7F6E\u6587\u4EF6\u76EE\u5F55\uFF1A deploy/",
      ]),
      ...gap(2),
      makeTable(
        ["\u6587\u4EF6\u540D", "\u7528\u9014", "\u90E8\u7F72\u76EE\u6807\u8DEF\u5F84"],
        [
          ["homelegance-chat.conf",   "Apache \u865A\u62DF\u4E3B\u673A\u914D\u7F6E",   "/etc/httpd/conf.d/"],
          ["erp-bridge.service",      "ERP Bridge systemd \u670D\u52A1",                "/etc/systemd/system/"],
          ["env.production.example",  "\u73AF\u5883\u53D8\u91CF\u6A21\u677F",            ".env.production\uFF08\u586B\u5199\u540E\uFF09"],
          ["ecosystem.config.cjs",    "PM2 \u8FDB\u7A0B\u914D\u7F6E",                   "\u9879\u76EE\u6839\u76EE\u5F55\uFF08\u5DF2\u5305\u542B\uFF09"],
        ],
        [2800, 3000, 3226],
      ),
    ],
  }],
});

const out = "C:\\Codes\\homelegance-chatbot\\deploy\\Homelegance_Chatbot_\u90E8\u7F72\u6587\u6863.docx";
Packer.toBuffer(doc).then(buf => {
  writeFileSync(out, buf);
  console.log("Created:", out);
});
