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

const outFile = path.join(__dirname, "game-topup-automation-flowcharts.drawio");

function esc(value) {
  return String(value)
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;");
}

function node(id, value, x, y, w, h, style) {
  return `        <mxCell id="${id}" value="${esc(value)}" style="${style}" vertex="1" parent="1">
          <mxGeometry x="${x}" y="${y}" width="${w}" height="${h}" as="geometry"/>
        </mxCell>`;
}

function edge(id, from, to, label = "", color = "#64748b") {
  return `        <mxCell id="${id}" value="${esc(label)}" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=${color};strokeWidth=2;endArrow=block;endFill=1;fontSize=11;fontColor=${color};" edge="1" parent="1" source="${from}" target="${to}">
          <mxGeometry relative="1" as="geometry"/>
        </mxCell>`;
}

const styles = {
  title:
    "rounded=1;whiteSpace=wrap;html=1;arcSize=8;fillColor=#0f172a;strokeColor=#0f172a;fontColor=#ffffff;fontSize=24;fontStyle=1;align=center;verticalAlign=middle;spacing=12;",
  subtitle:
    "rounded=1;whiteSpace=wrap;html=1;arcSize=8;fillColor=#f8fafc;strokeColor=#cbd5e1;fontColor=#334155;fontSize=13;align=center;verticalAlign=middle;spacing=8;",
  start:
    "ellipse;whiteSpace=wrap;html=1;fillColor=#dcfce7;strokeColor=#16a34a;fontColor=#14532d;fontSize=14;fontStyle=1;align=center;verticalAlign=middle;",
  end:
    "ellipse;whiteSpace=wrap;html=1;fillColor=#e0f2fe;strokeColor=#0284c7;fontColor=#0c4a6e;fontSize=14;fontStyle=1;align=center;verticalAlign=middle;",
  process:
    "rounded=1;whiteSpace=wrap;html=1;arcSize=8;fillColor=#eff6ff;strokeColor=#2563eb;fontColor=#111827;fontSize=13;align=center;verticalAlign=middle;spacing=8;",
  backend:
    "rounded=1;whiteSpace=wrap;html=1;arcSize=8;fillColor=#f0fdf4;strokeColor=#16a34a;fontColor=#111827;fontSize=13;align=center;verticalAlign=middle;spacing=8;",
  automation:
    "rounded=1;whiteSpace=wrap;html=1;arcSize=8;fillColor=#f5f3ff;strokeColor=#7c3aed;fontColor=#111827;fontSize=13;align=center;verticalAlign=middle;spacing=8;",
  payment:
    "rounded=1;whiteSpace=wrap;html=1;arcSize=8;fillColor=#fef2f2;strokeColor=#dc2626;fontColor=#111827;fontSize=13;align=center;verticalAlign=middle;spacing=8;",
  notify:
    "rounded=1;whiteSpace=wrap;html=1;arcSize=8;fillColor=#fdf4ff;strokeColor=#c026d3;fontColor=#111827;fontSize=13;align=center;verticalAlign=middle;spacing=8;",
  warning:
    "rounded=1;whiteSpace=wrap;html=1;arcSize=8;fillColor=#fff7ed;strokeColor=#ea580c;fontColor=#111827;fontSize=13;align=center;verticalAlign=middle;spacing=8;",
  decision:
    "rhombus;whiteSpace=wrap;html=1;fillColor=#fef9c3;strokeColor=#ca8a04;fontColor=#713f12;fontSize=12;align=center;verticalAlign=middle;spacing=8;",
  data:
    "shape=cylinder3d;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=#f8fafc;strokeColor=#475569;fontColor=#111827;fontSize=13;align=center;verticalAlign=middle;spacing=8;",
  external:
    "rounded=1;whiteSpace=wrap;html=1;arcSize=8;fillColor=#ecfeff;strokeColor=#0891b2;fontColor=#164e63;fontSize=13;align=center;verticalAlign=middle;spacing=8;",
  manual:
    "rounded=1;whiteSpace=wrap;html=1;arcSize=8;fillColor=#f1f5f9;strokeColor=#64748b;fontColor=#111827;fontSize=13;align=center;verticalAlign=middle;spacing=8;",
};

function diagram(name, cells, width = 1400, height = 900) {
  return `  <diagram id="${esc(name.toLowerCase().replace(/[^a-z0-9]+/g, "-"))}" name="${esc(name)}">
    <mxGraphModel dx="1600" dy="1000" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="${width}" pageHeight="${height}" math="0" shadow="0">
      <root>
        <mxCell id="0"/>
        <mxCell id="1" parent="0"/>
${cells.join("\n")}
      </root>
    </mxGraphModel>
  </diagram>`;
}

function titleCells(prefix, title, subtitle) {
  return [
    node(`${prefix}-title`, `<b>${title}</b>`, 250, 30, 900, 70, styles.title),
    node(`${prefix}-sub`, subtitle, 330, 115, 740, 44, styles.subtitle),
  ];
}

const diagrams = [];

diagrams.push(
  diagram("1. Overall System Architecture", [
    ...titleCells("arch", "Overall System Architecture", "Master diagram: customer order, payment verification, queue automation, monitoring, and notifications."),
    node("arch-customer", "<b>Customer</b><br>Places order<br>Uploads payment proof<br>Tracks status", 50, 230, 170, 105, styles.start),
    node("arch-website", "<b>Website</b><br>Frontend pages<br>Order form<br>Tracking UI", 280, 230, 170, 105, styles.process),
    node("arch-api", "<b>Backend API</b><br>Orders<br>Payments<br>Admin routes", 510, 230, 170, 105, styles.backend),
    node("arch-db", "<b>Database</b><br>orders<br>smile_accounts<br>logs<br>order_queue", 740, 215, 170, 130, styles.data),
    node("arch-queue", "<b>Queue</b><br>waiting<br>processing<br>completed<br>failed", 970, 230, 170, 105, styles.backend),
    node("arch-worker", "<b>Puppeteer Worker</b><br>Reads queue<br>Runs automation<br>Updates status", 970, 430, 170, 115, styles.automation),
    node("arch-smile", "<b>Smile.one</b><br>Login/session<br>Game top-up<br>Purchase result", 740, 430, 170, 115, styles.external),
    node("arch-telegram", "<b>Telegram Bot</b><br>Payment proof<br>Confirm / Reject<br>Admin alerts", 280, 430, 170, 115, styles.notify),
    node("arch-email", "<b>Email System</b><br>Low balance<br>Failures<br>Critical errors", 510, 620, 170, 115, styles.notify),
    node("arch-admin", "<b>Admin</b><br>Checks wallet<br>Controls orders<br>Retries failures", 50, 430, 170, 115, styles.manual),
    edge("arch-e1", "arch-customer", "arch-website"),
    edge("arch-e2", "arch-website", "arch-api"),
    edge("arch-e3", "arch-api", "arch-db"),
    edge("arch-e4", "arch-db", "arch-queue"),
    edge("arch-e5", "arch-queue", "arch-worker"),
    edge("arch-e6", "arch-worker", "arch-smile"),
    edge("arch-e7", "arch-api", "arch-telegram", "payment notification", "#c026d3"),
    edge("arch-e8", "arch-telegram", "arch-admin", "admin action", "#c026d3"),
    edge("arch-e9", "arch-admin", "arch-api", "confirm / reject", "#64748b"),
    edge("arch-e10", "arch-worker", "arch-email", "failure alerts", "#c026d3"),
    edge("arch-e11", "arch-smile", "arch-db", "result + balance", "#0891b2"),
  ])
);

diagrams.push(
  diagram("2. Customer Order Flowchart", [
    ...titleCells("order", "Customer Order Flowchart", "How a customer creates an order and receives payment instructions."),
    node("order-start", "Start", 90, 260, 120, 70, styles.start),
    node("order-game", "Select game<br><b>PUBG UC</b> or <b>MLBB Diamonds</b>", 270, 250, 170, 90, styles.process),
    node("order-id", "Enter game ID<br>and server info if needed", 500, 250, 170, 90, styles.process),
    node("order-package", "Select package<br>UC / Diamonds amount", 730, 250, 170, 90, styles.process),
    node("order-payment", "Select payment method<br>KBZPay / AYA Pay", 960, 250, 170, 90, styles.payment),
    node("order-api", "Create order API<br>Validate fields", 270, 450, 170, 90, styles.backend),
    node("order-amount", "Generate amount<br>Base price + random digits<br>Example: 10000 + 37", 500, 440, 190, 110, styles.backend),
    node("order-store", "Store order<br>Status: pending", 760, 450, 170, 90, styles.data),
    node("order-show", "Show payment instructions<br>Order ID<br>Exact amount<br>Wallet number", 990, 440, 190, 110, styles.end),
    edge("order-e1", "order-start", "order-game"),
    edge("order-e2", "order-game", "order-id"),
    edge("order-e3", "order-id", "order-package"),
    edge("order-e4", "order-package", "order-payment"),
    edge("order-e5", "order-payment", "order-api"),
    edge("order-e6", "order-api", "order-amount"),
    edge("order-e7", "order-amount", "order-store"),
    edge("order-e8", "order-store", "order-show"),
  ])
);

diagrams.push(
  diagram("3. Payment Verification Flowchart", [
    ...titleCells("pay", "Payment Verification Flowchart", "KBZPay / AYA Pay screenshot verification with Telegram admin control."),
    node("pay-start", "Customer pays exact amount", 80, 250, 160, 80, styles.start),
    node("pay-upload", "Upload screenshot<br>Transaction ID optional", 300, 250, 170, 90, styles.payment),
    node("pay-store-img", "Store image<br>backend/uploads", 530, 250, 170, 90, styles.data),
    node("pay-status", "Update order<br>Status: waiting_verification", 760, 250, 190, 90, styles.backend),
    node("pay-telegram", "Send Telegram notification<br>Order + screenshot + buttons", 1010, 240, 200, 110, styles.notify),
    node("pay-wallet", "Admin checks wallet app<br>Amount / method / time", 300, 470, 190, 100, styles.manual),
    node("pay-valid", "Payment valid?", 560, 460, 150, 120, styles.decision),
    node("pay-confirm", "Confirm payment<br>Status: paid<br>Add to queue", 800, 450, 190, 110, styles.backend),
    node("pay-reject", "Reject payment<br>Status: rejected<br>Customer can contact support", 800, 610, 190, 110, styles.warning),
    node("pay-log", "Save verification log", 1050, 520, 170, 90, styles.data),
    edge("pay-e1", "pay-start", "pay-upload"),
    edge("pay-e2", "pay-upload", "pay-store-img"),
    edge("pay-e3", "pay-store-img", "pay-status"),
    edge("pay-e4", "pay-status", "pay-telegram"),
    edge("pay-e5", "pay-telegram", "pay-wallet"),
    edge("pay-e6", "pay-wallet", "pay-valid"),
    edge("pay-e7", "pay-valid", "pay-confirm", "yes", "#16a34a"),
    edge("pay-e8", "pay-valid", "pay-reject", "no", "#dc2626"),
    edge("pay-e9", "pay-confirm", "pay-log"),
    edge("pay-e10", "pay-reject", "pay-log"),
  ])
);

diagrams.push(
  diagram("4. Queue Processing Flowchart", [
    ...titleCells("queue", "Queue Processing Flowchart", "Safe sequential processing with retry and manual fallback."),
    node("queue-new", "Paid order", 80, 260, 140, 70, styles.start),
    node("queue-wait", "Waiting queue<br>status: waiting", 280, 250, 170, 90, styles.backend),
    node("queue-worker-check", "Worker checks queue<br>interval loop", 520, 250, 170, 90, styles.automation),
    node("queue-has-order", "Waiting order found?", 760, 235, 150, 120, styles.decision),
    node("queue-idle", "No order<br>sleep and check again", 1010, 170, 170, 90, styles.manual),
    node("queue-pick", "Pick one order<br>lock / mark processing", 1010, 360, 190, 90, styles.automation),
    node("queue-process", "Run Puppeteer automation", 760, 520, 190, 90, styles.automation),
    node("queue-success", "Success?", 520, 505, 150, 120, styles.decision),
    node("queue-done", "Mark completed<br>Save result", 280, 440, 170, 90, styles.end),
    node("queue-retry", "Attempts left?", 280, 610, 150, 120, styles.decision),
    node("queue-back", "Retry once<br>Return to waiting", 520, 660, 170, 90, styles.warning),
    node("queue-failed", "Mark failed<br>Manual fallback<br>Alert admin", 760, 660, 190, 100, styles.payment),
    edge("queue-e1", "queue-new", "queue-wait"),
    edge("queue-e2", "queue-wait", "queue-worker-check"),
    edge("queue-e3", "queue-worker-check", "queue-has-order"),
    edge("queue-e4", "queue-has-order", "queue-idle", "no", "#64748b"),
    edge("queue-e5", "queue-idle", "queue-worker-check", "loop", "#64748b"),
    edge("queue-e6", "queue-has-order", "queue-pick", "yes", "#16a34a"),
    edge("queue-e7", "queue-pick", "queue-process"),
    edge("queue-e8", "queue-process", "queue-success"),
    edge("queue-e9", "queue-success", "queue-done", "yes", "#16a34a"),
    edge("queue-e10", "queue-success", "queue-retry", "no", "#dc2626"),
    edge("queue-e11", "queue-retry", "queue-back", "yes", "#ea580c"),
    edge("queue-e12", "queue-back", "queue-wait"),
    edge("queue-e13", "queue-retry", "queue-failed", "no", "#dc2626"),
  ])
);

diagrams.push(
  diagram("5. Puppeteer Automation Flowchart", [
    ...titleCells("botflow", "Puppeteer Automation Flowchart", "Detailed Smile.one browser automation path with session handling and result capture."),
    node("bot-start", "Worker receives order", 60, 220, 160, 70, styles.start),
    node("bot-account", "Select Smile account<br>from pool", 280, 210, 170, 90, styles.automation),
    node("bot-launch", "Launch browser<br>visible test mode first", 510, 210, 170, 90, styles.automation),
    node("bot-session", "Load cookies/session<br>userDataDir per account", 740, 210, 190, 90, styles.automation),
    node("bot-open", "Open Smile.one", 990, 210, 170, 90, styles.external),
    node("bot-valid", "Session valid?", 1040, 380, 150, 120, styles.decision),
    node("bot-login", "Login manually/automated<br>Save refreshed session", 800, 395, 190, 90, styles.warning),
    node("bot-game", "Navigate to game page<br>PUBG / MLBB", 560, 395, 190, 90, styles.external),
    node("bot-fill", "Fill game ID<br>Validate input", 320, 395, 170, 90, styles.automation),
    node("bot-package", "Select package<br>UC / Diamonds", 80, 395, 170, 90, styles.automation),
    node("bot-confirm", "Confirm purchase<br>Final review", 80, 590, 170, 90, styles.payment),
    node("bot-read", "Read result<br>Success / error text<br>Reference if available", 320, 580, 190, 110, styles.automation),
    node("bot-ok", "Purchase successful?", 580, 575, 160, 120, styles.decision),
    node("bot-save-ok", "Save completed status<br>Update order + queue<br>Update balance", 810, 560, 200, 120, styles.end),
    node("bot-classify", "Classify failure<br>timeout / CAPTCHA / invalid ID / purchase failed", 810, 735, 220, 110, styles.payment),
    node("bot-save-fail", "Save failed status<br>Retry or manual fallback<br>Alert admin", 1080, 720, 200, 120, styles.warning),
    edge("bot-e1", "bot-start", "bot-account"),
    edge("bot-e2", "bot-account", "bot-launch"),
    edge("bot-e3", "bot-launch", "bot-session"),
    edge("bot-e4", "bot-session", "bot-open"),
    edge("bot-e5", "bot-open", "bot-valid"),
    edge("bot-e6", "bot-valid", "bot-login", "no", "#ea580c"),
    edge("bot-e7", "bot-login", "bot-game"),
    edge("bot-e8", "bot-valid", "bot-game", "yes", "#16a34a"),
    edge("bot-e9", "bot-game", "bot-fill"),
    edge("bot-e10", "bot-fill", "bot-package"),
    edge("bot-e11", "bot-package", "bot-confirm"),
    edge("bot-e12", "bot-confirm", "bot-read"),
    edge("bot-e13", "bot-read", "bot-ok"),
    edge("bot-e14", "bot-ok", "bot-save-ok", "yes", "#16a34a"),
    edge("bot-e15", "bot-ok", "bot-classify", "no", "#dc2626"),
    edge("bot-e16", "bot-classify", "bot-save-fail"),
  ], 1400, 950)
);

diagrams.push(
  diagram("6. Smile Account Pool Flowchart", [
    ...titleCells("pool", "Smile Account Pool Flowchart", "Multi-account routing using active status, balance, and round robin usage."),
    node("pool-start", "Worker needs account", 80, 270, 160, 70, styles.start),
    node("pool-table", "Read smile_accounts table", 300, 250, 170, 100, styles.data),
    node("pool-active", "Filter active accounts", 530, 250, 170, 100, styles.automation),
    node("pool-any", "Any active account?", 760, 240, 150, 120, styles.decision),
    node("pool-alert", "No account available<br>Pause job<br>Alert admin", 1000, 190, 190, 100, styles.payment),
    node("pool-balance", "Check balance<br>Enough for package?", 1000, 380, 190, 100, styles.automation),
    node("pool-enough", "Enough balance?", 760, 390, 150, 120, styles.decision),
    node("pool-route", "Apply routing strategy<br>Balance-aware or round robin", 530, 420, 190, 100, styles.backend),
    node("pool-assign", "Assign account to worker", 300, 430, 170, 90, styles.end),
    node("pool-update", "After purchase<br>Update balance<br>Update last_used", 80, 420, 170, 110, styles.data),
    edge("pool-e1", "pool-start", "pool-table"),
    edge("pool-e2", "pool-table", "pool-active"),
    edge("pool-e3", "pool-active", "pool-any"),
    edge("pool-e4", "pool-any", "pool-alert", "no", "#dc2626"),
    edge("pool-e5", "pool-any", "pool-balance", "yes", "#16a34a"),
    edge("pool-e6", "pool-balance", "pool-enough"),
    edge("pool-e7", "pool-enough", "pool-alert", "no", "#dc2626"),
    edge("pool-e8", "pool-enough", "pool-route", "yes", "#16a34a"),
    edge("pool-e9", "pool-route", "pool-assign"),
    edge("pool-e10", "pool-assign", "pool-update"),
  ])
);

diagrams.push(
  diagram("7. Balance Monitoring Flowchart", [
    ...titleCells("balance", "Balance Monitoring Flowchart", "Periodic Smile.one balance checking with warning and critical alerts."),
    node("balance-start", "Periodic checker<br>every 5 minutes", 80, 270, 170, 80, styles.start),
    node("balance-accounts", "Read active Smile accounts", 310, 260, 180, 90, styles.data),
    node("balance-read", "Open/read Smile balance<br>per account", 550, 260, 190, 90, styles.automation),
    node("balance-save", "Save latest balance", 800, 260, 170, 90, styles.data),
    node("balance-threshold", "Below threshold?", 1030, 245, 150, 120, styles.decision),
    node("balance-ok", "Balance OK<br>No alert<br>Next interval", 1030, 450, 170, 90, styles.end),
    node("balance-level", "Select level<br>Warning: 50000 MMK<br>Critical: 10000 MMK", 780, 450, 200, 110, styles.warning),
    node("balance-telegram", "Send Telegram alert", 530, 460, 170, 90, styles.notify),
    node("balance-email", "Send Email alert", 310, 460, 170, 90, styles.notify),
    node("balance-log", "Save monitoring log", 90, 460, 170, 90, styles.data),
    edge("balance-e1", "balance-start", "balance-accounts"),
    edge("balance-e2", "balance-accounts", "balance-read"),
    edge("balance-e3", "balance-read", "balance-save"),
    edge("balance-e4", "balance-save", "balance-threshold"),
    edge("balance-e5", "balance-threshold", "balance-ok", "no", "#16a34a"),
    edge("balance-e6", "balance-threshold", "balance-level", "yes", "#ea580c"),
    edge("balance-e7", "balance-level", "balance-telegram"),
    edge("balance-e8", "balance-telegram", "balance-email"),
    edge("balance-e9", "balance-email", "balance-log"),
  ])
);

diagrams.push(
  diagram("8. Notification System Flowchart", [
    ...titleCells("notify", "Notification System Flowchart", "Telegram and email alerts with typed messages, cooldown, and logging."),
    node("notify-trigger", "Trigger event<br>low balance / failure / critical / session expired", 80, 250, 210, 100, styles.start),
    node("notify-type", "Select alert type", 350, 260, 170, 80, styles.notify),
    node("notify-cooldown", "Cooldown active?", 580, 245, 150, 120, styles.decision),
    node("notify-skip", "Skip duplicate alert<br>Save skipped log", 810, 180, 190, 90, styles.manual),
    node("notify-compose", "Compose message<br>Order/account details<br>Error context", 810, 360, 190, 110, styles.notify),
    node("notify-tg", "Send Telegram", 570, 470, 170, 90, styles.notify),
    node("notify-email", "Send Email", 350, 470, 170, 90, styles.notify),
    node("notify-result", "Delivery successful?", 120, 455, 150, 120, styles.decision),
    node("notify-log-ok", "Save sent log", 120, 650, 170, 80, styles.data),
    node("notify-log-fail", "Save failure log<br>Keep admin-visible", 350, 650, 190, 90, styles.payment),
    edge("notify-e1", "notify-trigger", "notify-type"),
    edge("notify-e2", "notify-type", "notify-cooldown"),
    edge("notify-e3", "notify-cooldown", "notify-skip", "yes", "#64748b"),
    edge("notify-e4", "notify-cooldown", "notify-compose", "no", "#16a34a"),
    edge("notify-e5", "notify-compose", "notify-tg"),
    edge("notify-e6", "notify-tg", "notify-email"),
    edge("notify-e7", "notify-email", "notify-result"),
    edge("notify-e8", "notify-result", "notify-log-ok", "yes", "#16a34a"),
    edge("notify-e9", "notify-result", "notify-log-fail", "no", "#dc2626"),
  ])
);

diagrams.push(
  diagram("9. Error Handling Flowchart", [
    ...titleCells("error", "Error Handling Flowchart", "Failure classification, retry, manual fallback, and admin alerting."),
    node("error-start", "Failure detected", 80, 250, 160, 70, styles.start),
    node("error-classify", "Classify error<br>Browser crash<br>CAPTCHA<br>Timeout<br>Invalid ID<br>Purchase failure", 300, 220, 200, 130, styles.payment),
    node("error-browser", "Browser crash?<br>Restart browser/session", 560, 190, 180, 100, styles.warning),
    node("error-captcha", "CAPTCHA?<br>Pause automation<br>Manual login required", 560, 340, 180, 100, styles.warning),
    node("error-retry", "Retry available?", 820, 245, 150, 120, styles.decision),
    node("error-run-retry", "Retry once<br>Same or new account", 1060, 190, 180, 90, styles.automation),
    node("error-success", "Retry successful?", 1060, 350, 150, 120, styles.decision),
    node("error-complete", "Mark completed", 820, 520, 170, 80, styles.end),
    node("error-failed", "Mark failed<br>Manual fallback", 560, 520, 180, 90, styles.payment),
    node("error-alert", "Alert admin<br>Telegram + Email", 320, 520, 180, 90, styles.notify),
    node("error-log", "Save error log<br>Stack + screenshot<br>Order context", 80, 500, 180, 120, styles.data),
    edge("error-e1", "error-start", "error-classify"),
    edge("error-e2", "error-classify", "error-browser"),
    edge("error-e3", "error-classify", "error-captcha"),
    edge("error-e4", "error-browser", "error-retry"),
    edge("error-e5", "error-captcha", "error-retry"),
    edge("error-e6", "error-retry", "error-run-retry", "yes", "#ea580c"),
    edge("error-e7", "error-run-retry", "error-success"),
    edge("error-e8", "error-success", "error-complete", "yes", "#16a34a"),
    edge("error-e9", "error-success", "error-failed", "no", "#dc2626"),
    edge("error-e10", "error-retry", "error-failed", "no", "#dc2626"),
    edge("error-e11", "error-failed", "error-alert"),
    edge("error-e12", "error-alert", "error-log"),
  ])
);

diagrams.push(
  diagram("10. Admin Dashboard Flowchart", [
    ...titleCells("admin", "Admin Dashboard Flowchart", "Admin control panel for payments, orders, balances, retries, and logs."),
    node("admin-login", "Admin login<br>Protected route/token", 80, 250, 170, 90, styles.start),
    node("admin-dashboard", "Open dashboard", 310, 250, 170, 90, styles.process),
    node("admin-orders", "View orders<br>pending / paid / completed / failed", 540, 170, 190, 100, styles.backend),
    node("admin-payments", "Approve payments<br>Confirm / Reject", 540, 320, 190, 90, styles.payment),
    node("admin-balances", "Monitor balances<br>Warning / critical", 790, 170, 190, 100, styles.external),
    node("admin-retry", "Retry failed orders<br>Return to queue", 790, 320, 190, 90, styles.warning),
    node("admin-logs", "View logs<br>payment / automation / errors", 1040, 170, 190, 100, styles.data),
    node("admin-actions", "Admin action API<br>Update database<br>Trigger notifications", 1040, 320, 190, 110, styles.backend),
    node("admin-done", "System state updated", 650, 560, 190, 80, styles.end),
    edge("admin-e1", "admin-login", "admin-dashboard"),
    edge("admin-e2", "admin-dashboard", "admin-orders"),
    edge("admin-e3", "admin-dashboard", "admin-payments"),
    edge("admin-e4", "admin-dashboard", "admin-balances"),
    edge("admin-e5", "admin-dashboard", "admin-retry"),
    edge("admin-e6", "admin-dashboard", "admin-logs"),
    edge("admin-e7", "admin-orders", "admin-actions"),
    edge("admin-e8", "admin-payments", "admin-actions"),
    edge("admin-e9", "admin-balances", "admin-actions"),
    edge("admin-e10", "admin-retry", "admin-actions"),
    edge("admin-e11", "admin-logs", "admin-actions"),
    edge("admin-e12", "admin-actions", "admin-done"),
  ])
);

const xml = `<mxfile host="app.diagrams.net" modified="2026-05-11T00:00:00.000Z" agent="Codex" version="24.8.2" type="device">
${diagrams.join("\n")}
</mxfile>
`;

fs.writeFileSync(outFile, xml);
console.log(outFile);
