import * as React from "react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import {
  BarChart3,
  Bell,
  BriefcaseBusiness,
  CheckCircle,
  ChevronDown,
  ChevronLeft,
  ChevronRight,
  CircleHelp,
  ClipboardList,
  FileText,
  Fullscreen,
  Home,
  KeyRound,
  ListChecks,
  Menu,
  PackageOpen,
  RefreshCw,
  Search,
  Settings,
  ShieldCheck,
  SlidersHorizontal,
  User,
  Volume2,
  WalletCards,
  X
} from "lucide-react";
import "./styles.css";

type RouteKey =
  | "home"
  | "merchant-list"
  | "merchant-channel"
  | "merchant-deposit"
  | "merchant-balance"
  | "qrcode-list"
  | "payment-order"
  | "payout-order"
  | "available-code"
  | "code-merchant-list"
  | "code-merchant-channel"
  | "code-merchant-deposit"
  | "code-merchant-funds"
  | "prediction"
  | "team-volume"
  | "daily-report"
  | "operation-setting"
  | "payment-channel"
  | "operation-log"
  | "merchant-manual"
  | "operation-manual"
  | "telegram-group"
  | "telegram-config"
  | "plugin-market"
  | "plugin-tools"
  | "plugin-guarantee"
  | "account-rules";

type MenuItem = {
  key: RouteKey;
  label: string;
  icon: React.ComponentType<{ size?: number }>;
};

type MenuGroup = {
  key: string;
  label: string;
  icon: React.ComponentType<{ size?: number }>;
  children?: MenuItem[];
};

type PageConfig = {
  group: string;
  title: string;
  filters: [string, string][];
  columns: string[];
  summary: string;
  actions?: string[];
  rows?: string[][];
  notice?: string;
};

type ApiResponse<T> = {
  code: number;
  message: string;
  data: T;
};

type DataRouteKey =
  | "merchant-list"
  | "merchant-channel"
  | "merchant-deposit"
  | "merchant-balance"
  | "qrcode-list"
  | "payment-order"
  | "payout-order"
  | "available-code"
  | "code-merchant-list"
  | "code-merchant-channel"
  | "code-merchant-deposit"
  | "code-merchant-funds"
  | "prediction"
  | "team-volume"
  | "daily-report"
  | "operation-log"
  | "operation-setting"
  | "payment-channel"
  | "telegram-group"
  | "telegram-config"
  | "plugin-market"
  | "plugin-tools"
  | "plugin-guarantee"
  | "account-rules";

type CreateRouteKey = "merchant-list" | "code-merchant-list" | "qrcode-list" | "code-merchant-deposit" | "account-rules";

type FormField = {
  name: string;
  label: string;
  placeholder: string;
  defaultValue?: string;
  type?: "text" | "number" | "checkbox";
};

type CreateConfig = {
  title: string;
  endpoint: string;
  fields: FormField[];
  buildPayload: (values: Record<string, string>) => Record<string, unknown>;
  getEditValues?: (row: string[]) => Record<string, string>;
  getEditEndpoint?: (row: string[]) => string;
};

type DialogState = {
  key: CreateRouteKey;
  mode: "create" | "edit";
  row?: string[];
};

type AdjustState = {
  route: "merchant-list" | "code-merchant-list";
  row: string[];
};

type DetailState = {
  route: "payment-order";
  row: string[];
};

const menu: MenuGroup[] = [
  { key: "home", label: "首页", icon: Home, children: [{ key: "home", label: "首页", icon: Home }] },
  {
    key: "merchant",
    label: "商户管理",
    icon: BriefcaseBusiness,
    children: [
      { key: "merchant-list", label: "商户列表", icon: ClipboardList },
      { key: "merchant-channel", label: "商户通道", icon: ListChecks },
      { key: "merchant-deposit", label: "存取记录", icon: WalletCards },
      { key: "merchant-balance", label: "余额变动", icon: BarChart3 }
    ]
  },
  {
    key: "order",
    label: "订单管理",
    icon: ClipboardList,
    children: [
      { key: "qrcode-list", label: "收款码列表", icon: CircleHelp },
      { key: "payment-order", label: "收款订单列表", icon: BriefcaseBusiness },
      { key: "payout-order", label: "代付订单列表", icon: Bell },
      { key: "available-code", label: "可用收款码", icon: CheckCircle }
    ]
  },
  {
    key: "codeMerchant",
    label: "码商管理",
    icon: User,
    children: [
      { key: "code-merchant-list", label: "码商列表", icon: ClipboardList },
      { key: "code-merchant-channel", label: "码商通道", icon: CircleHelp },
      { key: "code-merchant-deposit", label: "存取款管理", icon: FileText },
      { key: "code-merchant-funds", label: "资金流水", icon: BarChart3 },
      { key: "prediction", label: "接单预测", icon: BarChart3 },
      { key: "team-volume", label: "团队跑量", icon: BarChart3 }
    ]
  },
  {
    key: "report",
    label: "报表中心",
    icon: BarChart3,
    children: [{ key: "daily-report", label: "平台日报表", icon: BarChart3 }]
  },
  {
    key: "operation",
    label: "运营中心",
    icon: Settings,
    children: [
      { key: "operation-setting", label: "系统设置", icon: Settings },
      { key: "payment-channel", label: "支付通道管理", icon: ListChecks },
      { key: "merchant-manual", label: "商户必读手册", icon: FileText },
      { key: "operation-manual", label: "运营必读手册", icon: FileText },
      { key: "telegram-group", label: "Telegram机器人群", icon: Bell },
      { key: "telegram-config", label: "Telegram机器人配置", icon: Bell }
    ]
  },
  {
    key: "plugin",
    label: "[资源]插件市场",
    icon: PackageOpen,
    children: [
      { key: "plugin-market", label: "插件市场", icon: PackageOpen },
      { key: "plugin-tools", label: "工具下载", icon: FileText },
      { key: "plugin-guarantee", label: "担保中心", icon: ShieldCheck }
    ]
  },
  {
    key: "account",
    label: "代理推广中心",
    icon: KeyRound,
    children: [{ key: "account-rules", label: "代理规则", icon: FileText }]
  }
];

const pageConfigs: Record<RouteKey, PageConfig> = {
  home: {
    group: "首页",
    title: "首页",
    filters: [["统计日期", "请选择统计日期"], ["商户", "请输入商户名称"], ["码商", "请输入码商名称"]],
    summary: "今日收款:0.00，今日代付:0.00，成功订单:0，待处理订单:0，商户余额:0.00，码商余额:0.00",
    columns: ["指标", "今日", "昨日", "本月", "操作"],
    rows: [
      ["收款金额", "0.00", "0.00", "0.00", "查看"],
      ["代付金额", "0.00", "0.00", "0.00", "查看"],
      ["订单成功率", "0%", "0%", "0%", "查看"]
    ]
  },
  "merchant-list": {
    group: "商户管理",
    title: "商户列表",
    filters: [["登录名", "请输入登录名"], ["商户号", "请输入商户号"], ["备注", "请输入备注"]],
    summary: "总商户数量:2，商户总余额:339210.25",
    actions: ["新建商户"],
    columns: ["ID", "用户名", "谷歌绑定", "电话/邮箱", "支付方式", "IP白名单", "备注", "状态", "Accesskey(商户号)", "创建/最晚", "余额", "操作"],
    rows: [
      ["1001", "demo_merchant", "已绑定", "138****0001", "支付宝/银行卡", "127.0.0.1", "演示商户", "启用", "M202606240001", "2026-06-24", "286530.25", "编辑/通道/账变"],
      ["1002", "night_shop", "未绑定", "未设置", "微信/代付", "未设置", "待审核", "待审核", "M202606240002", "2026-06-24", "52680.00", "编辑/审核"]
    ]
  },
  "merchant-channel": {
    group: "商户管理",
    title: "商户通道",
    filters: [["商户", "请输入商户名称"], ["渠道", "请输入渠道名称"], ["状态", "请选择状态"], ["备注", "请输入备注"]],
    summary: "通道总数:2，通道类型:2，已启用:1",
    actions: ["批量更新所有商户通道"],
    columns: ["ID", "商户名", "通道编号", "通道名称", "状态", "收款类型", "限额", "费率", "备注", "创建时间", "操作"],
    rows: [
      ["1", "demo_merchant", "ALIPAY_QR", "支付宝扫码", "启用", "收款", "100-50000", "3.8‰", "默认路由", "2026-06-24", "编辑/停用"],
      ["2", "night_shop", "BANK_PAYOUT", "银行卡代付", "停用", "代付", "100-200000", "5.0‰", "待补资料", "2026-06-24", "编辑/启用"]
    ]
  },
  "merchant-deposit": {
    group: "商户管理",
    title: "存取记录",
    filters: [["商户名称", "请输入商户名称"], ["操作人", "请输入操作人"], ["创建时间", "请选择时间范围"]],
    summary: "总金额:0.00，总笔数:0",
    columns: ["ID", "平台订单号", "商户名称", "金额", "类型", "状态", "备注消息", "操作人", "创建时间"],
    rows: []
  },
  "merchant-balance": {
    group: "商户管理",
    title: "余额变动",
    filters: [["关联订单号", "请输入订单号"], ["商户", "请输入商户名称"], ["类型", "请选择类型"], ["创建时间", "请选择时间范围"]],
    summary: "总笔数:2",
    columns: ["ID", "关联订单号", "商户名称", "类型", "订单金额", "订单手续费", "订单净值", "金额变化前", "金额变化后", "操作人", "备注", "创建时间"],
    rows: [
      ["1", "P20260624190001001", "demo_merchant", "收款入账", "1000.13", "3.80", "996.33", "285533.92", "286530.25", "system", "订单成功", "2026-06-24 18:58:03"],
      ["2", "D20260624191001001", "demo_merchant", "代付冻结", "2000.00", "8.00", "-2008.00", "286530.25", "284522.25", "system", "代付锁单", "2026-06-24 19:10:03"]
    ]
  },
  "qrcode-list": {
    group: "订单管理",
    title: "收款码列表",
    filters: [["供应码商", "请输入码商名称"], ["支付类型", "请选择支付类型"], ["码名字", "请输入码名字"], ["码状态", "请选择码状态"], ["可接单码", "请选择可接单码"]],
    summary: "总码数量:2，正常:1，停用:1",
    actions: ["添加收款方式"],
    notice: "注意：码接单需满足 接单状态正常/通道状态正常/码状态正常/余额充足/拉单金额匹配/未到收款限制。",
    columns: ["ID", "收款码名字", "支付类型", "供应码商/余额/冻结/押金/可用", "接单状态", "拉单限额", "今日收款/笔数/成功率", "创建时间/码状态", "操作"],
    rows: [
      ["8001", "张三-支付宝-01", "支付宝", "code_001 / 68920.80 / 1200 / 5000 / 62720.80", "可接单", "50-3000", "18520 / 23 / 97.2%", "2026-06-24 / 正常", "编辑/测试/下架"],
      ["8002", "李四-银行卡-尾号8821", "银行卡", "code_002 / 12800 / 0 / 3000 / 9800", "不可接单", "500-10000", "0 / 0 / -", "2026-06-24 / 停用", "编辑/删除"]
    ]
  },
  "payment-order": {
    group: "订单管理",
    title: "收款订单列表",
    filters: [["商户订单", "请输入商户订单号"], ["平台订单", "请输入平台订单号"], ["支付类型", "请输入支付类型"], ["码商", "请输入码商名称"], ["商户", "请输入商户名称"], ["订单金额", "请输入订单金额"], ["收款信息", "请输入收款码名称"]],
    summary: "总订单数量:2，总订单金额:1560.00，总收款:1000.13，成功率:50%，码商总成本:996.33，码商总利润:3.80",
    columns: ["ID", "平台订单", "商户/订单", "用户提交/IP", "会员设备", "提交/浮动/应收/确认", "收款码信息", "下单时间/完成时间", "备注", "⏰/状态", "订单状态", "详情/聊天"],
    rows: [
      ["90001", "P20260624190001001", "demo_merchant / MO-240624-001", "1000.00 / 218.33.111.9", "iPhone / Safari", "1000 / +0.13 / 1000.13 / 1000.13", "张三-支付宝-01", "18:56:11 / 18:58:02", "已回调", "完成", "支付成功", "详情/聊天"],
      ["90002", "P20260624190002001", "night_shop / MO-240624-002", "560.00 / 218.33.111.9", "Android / Chrome", "560 / +0.27 / 560.27 / 0", "张三-支付宝-01", "19:03:42 / -", "未回调", "计时中", "待确认", "详情/聊天"]
    ]
  },
  "payout-order": {
    group: "订单管理",
    title: "代付订单列表",
    filters: [["商户订单", "请输入商户订单号"], ["平台订单", "请输入平台订单号"], ["代付类型", "请输入代付类型"], ["码商", "请输入码商"], ["商户", "请输入商户名称"], ["代付金额", "请输入金额"], ["代付名字", "请输入姓名"], ["创建时间", "请选择时间范围"], ["订单状态", "拉单失败/已撤单/等待抢单/打款中/冻结中/支付成功"]],
    summary: "总代付数量:2，总代付金额:2880.00，交易成功金额:0.00，成功率:0%",
    columns: ["ID", "平台订单", "商户/订单", "来源/IP", "收款信息", "金额", "通道提示", "关联码商", "下单时间/最后时间", "转账附件", "回调状态", "备注", "订单状态", "详情"],
    rows: [
      ["91001", "D20260624191001001", "demo_merchant / DO-240624-001", "银行卡 / 218.33.111.9", "王五 / 6222 **** 3108", "2000.00 / 8.00", "请核对姓名后打款", "code_001", "19:10:01 / 19:12:18", "未上传", "待回调", "等待上传凭证", "打款中", "详情"],
      ["91002", "D20260624191002001", "night_shop / DO-240624-002", "银行卡 / 218.33.111.10", "赵六 / 6217 **** 7721", "880.00 / 3.50", "等待码商抢单", "-", "19:12:33 / 19:12:33", "未上传", "未回调", "等待抢单", "等待抢单", "详情"]
    ]
  },
  "available-code": {
    group: "订单管理",
    title: "可用收款码",
    filters: [["通道名称", "请输入通道名称"]],
    summary: "通道总数:2，码商总数:2，在线码商:1，总码数:2，可用码数:1",
    columns: ["通道名称", "码商数量", "在线码商", "码商余额", "码商押金", "可接单余额", "冻结余额", "码数量", "可用码数"],
    rows: [["支付宝", "1", "1", "68920.80", "5000.00", "62720.80", "1200.00", "1", "1"]]
  },
  "code-merchant-list": {
    group: "码商管理",
    title: "码商列表",
    filters: [["登录名", "请输入登录名"], ["备注", "请输入备注"], ["账号状态", "请选择账号状态"], ["接单状态", "请选择接单状态"], ["可用余额低于", "请输入金额"], ["只看顶级码商", "是/否"]],
    summary: "下面小弟数量：0，可用余额:72520.80，冻结余额:1200.00",
    actions: ["添加码商"],
    columns: ["ID", "登录名", "绑定谷歌", "延迟到账", "订单退压", "上级路径", "冻结金额", "押金", "账号状态", "接单状态", "备注", "创建时间/最晚", "可用余额", "操作"],
    rows: [
      ["501", "code_001", "已绑定", "关闭", "开启", "顶级码商", "1200.00", "5000.00", "在线", "接单中", "默认顶级码商", "2026-06-24 10:30:00 / 2026-06-24 18:48:12", "62720.80", "编辑/重置密码/账变/冻结"],
      ["502", "code_002", "未绑定", "开启", "关闭", "code_001 / code_002", "0.00", "3000.00", "离线", "冻结中", "银行卡码商", "2026-06-24 11:20:00 / 2026-06-24 15:17:33", "9800.00", "编辑/重置密码/账变/恢复"]
    ]
  },
  "code-merchant-channel": {
    group: "码商管理",
    title: "码商通道",
    filters: [["通道名称", "请输入通道名称"], ["码商名字", "请输入码商名字"], ["接单状态", "请选择状态"]],
    summary: "码总数量:2，码总种类:2",
    columns: ["ID", "码商名字", "通道名称", "支付类型", "拉单金额限制", "费率", "状态", "今日跑量", "操作"],
    rows: [
      ["1", "code_001", "支付宝", "正常", "接单中", "50", "3000", "3.5‰", "18520.00", "编辑/冻结"],
      ["2", "code_002", "银行卡", "正常", "冻结中", "500", "10000", "4.2‰", "0.00", "编辑/解冻"]
    ]
  },
  "code-merchant-deposit": {
    group: "码商管理",
    title: "存取款管理",
    filters: [["平台订单号", "请输入订单号"], ["发起账号", "请输入发起账号"], ["接收账号", "请输入接收账号"], ["状态", "请选择状态"]],
    summary: "转账笔数:1，总转出金额:500.00，手续费:0.00，净到账:500.00",
    actions: ["发起转账"],
    columns: ["ID", "平台订单号", "发起账号", "接收账号", "金额", "手续费", "净值", "转出所有余额", "状态", "备注", "操作人", "创建时间"],
    rows: [["1", "CT202606240001", "code_001", "code_002", "500.00", "0.00", "500.00", "否", "成功", "团队内部调拨", "admin", "2026-06-24 16:20:00"]]
  },
  "code-merchant-funds": {
    group: "码商管理",
    title: "资金流水",
    filters: [["关联订单号", "请输入订单号"], ["码商", "请输入码商"], ["类型", "请选择类型"], ["创建时间", "请选择时间范围"]],
    summary: "总笔数:2，佣金总额:1040.70",
    columns: ["ID", "关联订单号", "码商", "类型", "金额", "可用变化前", "可用变化后", "冻结", "押金", "备注", "创建时间"],
    rows: [
      ["1", "P20260624190001001", "code_001", "收款成本入账", "996.33", "61724.47", "62720.80", "1200.00", "5000.00", "订单成功", "2026-06-24 18:58:03"],
      ["2", "TEAM-20260624", "code_001", "团队佣金", "12.80", "62708.00", "62720.80", "1200.00", "5000.00", "下级跑量", "2026-06-24 19:00:00"]
    ]
  },
  prediction: {
    group: "码商管理",
    title: "接单预测",
    filters: [["通道列表", "请输入通道名称"], ["码商", "请输入码商"], ["金额", "请输入金额"]],
    summary: "预计可接订单:21，预计可接金额:62720.80，冻结中:1",
    columns: ["通道名字", "码商名字", "排名", "等待单数", "码商余额", "可接单余额", "最后接单时间", "建议"],
    rows: [["code_001", "支付宝", "62720.80", "50-3000", "0", "96.4%", "18:48:12", "可优先派单"], ["code_002", "银行卡", "9800.00", "500-10000", "0", "91.8%", "15:17:33", "冻结中"]]
  },
  "team-volume": {
    group: "码商管理",
    title: "团队跑量",
    filters: [["支付类型", "请输入支付类型"], ["时间范围", "请选择时间范围"]],
    summary: "团队总订单金额:18520.00，总成功金额:18520.00，佣金:1040.70",
    columns: ["团队名字", "余额", "余额占比", "支付中的金额", "在线接单/账号数", "总下级数量", "总订单金额", "总成功金额", "总订单数量", "总成功数量", "支付成功率", "订单数占比"],
    rows: [["默认团队", "code_001", "在线", "86.5%", "18520.00", "18520.00", "97.2%", "23", "22", "100%"]]
  },
  "daily-report": {
    group: "报表中心",
    title: "平台日报表",
    filters: [["日期范围", "请选择日期范围"]],
    summary: "总充值:0.00，总下发:0.00，总支付金额:1560.00，总代付金额:2880.00，总利润:3.80",
    columns: ["时间", "充值/笔数/手续费", "下发金额/笔数", "支付金额/笔数", "支付率", "代付金额/笔数", "代付率", "总成功金额", "当日利润"],
    rows: [["2026-06-24", "2", "1560.00", "50%", "2", "2880.00", "3.80", "996.33", "导出"]]
  },
  "operation-setting": {
    group: "运营中心",
    title: "系统设置",
    filters: [["配置项", "请输入配置项"], ["状态", "请选择状态"]],
    summary: "订单超时:5分钟，回调重试:8次，风控状态:启用",
    columns: ["配置项", "配置值", "说明", "状态", "操作"],
    rows: [["订单超时", "5分钟", "码商未确认自动释放", "启用", "编辑"], ["回调重试", "8次", "商户通知失败自动重试", "启用", "编辑"], ["高风险二验", "安全码/Google", "确认收款和代付需二验", "启用", "编辑"]]
  },
  "payment-channel": {
    group: "运营中心",
    title: "支付通道管理",
    filters: [["通道名称", "请输入通道名称"], ["支付类型", "请选择支付类型"], ["状态", "请选择状态"]],
    summary: "通道类型:3，启用:2，停用:1",
    actions: ["新增通道"],
    columns: ["ID", "通道编号", "通道名称", "支付类型", "状态", "限额", "默认费率", "排序", "操作"],
    rows: [["1", "ALIPAY_QR", "支付宝扫码", "收款", "启用", "50-50000", "3.8‰", "10", "编辑/停用"], ["2", "BANK_PAYOUT", "银行卡代付", "代付", "启用", "100-200000", "5‰", "20", "编辑/停用"]]
  },
  "merchant-manual": {
    group: "运营中心",
    title: "商户必读手册",
    filters: [["关键词", "请输入关键词"]],
    summary: "文档:签名规则、收款下单、代付下单、余额查询、回调说明",
    columns: ["章节", "内容摘要", "最后更新", "操作"],
    rows: [["签名规则", "按商户号、订单号、金额、时间戳生成签名", "2026-06-24", "编辑"], ["回调说明", "回调需验签并幂等处理", "2026-06-24", "编辑"]]
  },
  "operation-log": {
    group: "运营中心",
    title: "操作日志",
    filters: [["模块", "请输入模块"], ["操作", "请输入操作"], ["对象", "请输入对象"], ["操作人", "请输入操作人"]],
    summary: "记录高风险动作、新增、状态切换和确认收款。",
    columns: ["ID", "模块", "操作", "对象", "操作人", "详情", "创建时间"],
    rows: []
  },
  "operation-manual": {
    group: "运营中心",
    title: "运营必读手册",
    filters: [["关键词", "请输入关键词"]],
    summary: "文档:补单流程、代付异常、码商冻结、账变审核",
    columns: ["章节", "适用场景", "负责人", "操作"],
    rows: [["补单流程", "用户已付款但订单未完成", "运营", "查看"], ["代付异常", "收款账户错误或打款失败", "财务", "查看"]]
  },
  "telegram-config": {
    group: "运营中心",
    title: "Telegram机器人配置",
    filters: [["机器人", "请输入机器人名称"], ["群组", "请输入群组"]],
    summary: "通知群组:0，机器人:0，告警:未启用",
    actions: ["新增机器人"],
    columns: ["ID", "机器人名称", "群组", "通知类型", "状态", "操作"],
    rows: []
  },
  "telegram-group": {
    group: "运营中心",
    title: "Telegram机器人群",
    filters: [["群组名称", "请输入群组名称"], ["机器人", "请输入机器人名称"], ["状态", "请选择状态"]],
    summary: "群组数量:0，已绑定:0，启用:0",
    actions: ["新增群组"],
    columns: ["ID", "群组名称", "群组ID", "绑定机器人", "通知类型", "状态", "创建时间", "操作"],
    rows: []
  },
  "plugin-market": {
    group: "[资源]插件市场",
    title: "插件市场",
    filters: [["插件名称", "请输入插件名称"], ["分类", "请选择分类"], ["状态", "请选择状态"]],
    summary: "插件数量:0，已启用:0，待安装:0",
    columns: ["插件名称", "分类", "版本", "状态", "更新时间", "说明", "操作"],
    rows: []
  },
  "plugin-tools": {
    group: "[资源]插件市场",
    title: "工具下载",
    filters: [["工具名称", "请输入工具名称"], ["类型", "请选择类型"]],
    summary: "工具数量:0，可下载:0",
    columns: ["工具名称", "类型", "版本", "文件大小", "更新时间", "说明", "操作"],
    rows: []
  },
  "plugin-guarantee": {
    group: "[资源]插件市场",
    title: "担保中心",
    filters: [["订单号", "请输入订单号"], ["商户", "请输入商户"], ["状态", "请选择状态"]],
    summary: "担保订单:0，处理中:0，已完成:0",
    columns: ["ID", "担保订单", "商户", "码商", "金额", "状态", "创建时间", "操作"],
    rows: []
  },
  "account-rules": {
    group: "代理推广中心",
    title: "代理规则",
    filters: [["平台名字", "请输入平台名字"], ["账号", "请输入账号"], ["状态", "请选择状态"]],
    summary: "当前余额:1200.00，日租金:30.00，成功订单手续费:0.03，已注册下级平台:1",
    actions: ["立即注册"],
    columns: ["ID", "平台名字", "域名前缀", "账号", "当前余额", "日租金", "成功订单手续费", "状态", "备注", "注册时间", "操作"],
    rows: [["1", "奈计一号下级平台", "agent001", "agent001", "1200.00", "30.00", "0.03", "启用", "演示下级平台", "2026-06-24 13:30:00", "充值/刷新"]]
  }
};

const money = (value: unknown) => Number(value || 0).toFixed(2);

const routeApiMap: Partial<Record<DataRouteKey, string>> = {
  "merchant-list": "/api/merchants",
  "merchant-channel": "/api/merchant-channels",
  "merchant-deposit": "/api/merchant-deposit-records",
  "merchant-balance": "/api/ledger",
  "qrcode-list": "/api/qrcodes",
  "payment-order": "/api/payment-orders",
  "payout-order": "/api/payout-orders",
  "available-code": "/api/available-qrcode-groups",
  "code-merchant-list": "/api/code-merchants",
  "code-merchant-channel": "/api/code-merchant-channels",
  "code-merchant-deposit": "/api/code-merchant-transfers",
  "code-merchant-funds": "/api/ledger",
  prediction: "/api/predictions",
  "team-volume": "/api/team-volumes",
  "daily-report": "/api/daily-reports",
  "operation-log": "/api/operation-logs",
  "operation-setting": "/api/system-settings",
  "payment-channel": "/api/payment-channels",
  "telegram-group": "/api/telegram-groups",
  "telegram-config": "/api/telegram-configs",
  "plugin-market": "/api/plugins",
  "plugin-tools": "/api/tool-downloads",
  "plugin-guarantee": "/api/guarantee-orders",
  "account-rules": "/api/sub-platforms"
};

const routeRowMappers: Partial<Record<DataRouteKey, (rows: any[]) => string[][]>> = {
  "merchant-list": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.username,
      item.googleBound ? "已绑定" : "未绑定",
      [item.phone, item.email].filter(Boolean).join(" / ") || "未设置",
      Array.isArray(item.paymentMethods) ? item.paymentMethods.join("/") : "-",
      item.ipWhitelist,
      item.remark,
      item.status,
      item.merchantNo,
      item.createdAt,
      money(item.balance),
      item.status === "启用" ? "编辑/通道/账变/停用" : "编辑/通道/账变/启用"
    ]),
  "merchant-channel": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.merchant,
      item.channelNo,
      item.channelName,
      item.status,
      item.paymentType,
      item.limit,
      item.rate,
      item.remark,
      "2026-06-24",
      item.status === "启用" ? "编辑/停用" : "编辑/启用"
    ]),
  "merchant-deposit": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.orderNo,
      item.merchant,
      money(item.amount),
      item.type,
      item.status,
      item.remark,
      item.operator,
      item.createdAt
    ]),
  "merchant-balance": (rows) =>
    rows
      .filter((item) => item.subjectType === "merchant")
      .map((item) => [
        String(item.id),
        item.orderNo,
        item.subjectName,
        item.type,
        money(item.amount),
        money(item.fee),
        money(Number(item.amount || 0) - Number(item.fee || 0)),
        money(item.before),
        money(item.after),
        item.operator,
        "账本流水",
        item.createdAt
      ]),
  "qrcode-list": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.name,
      item.paymentType,
      `${item.owner} / - / - / - / -`,
      item.accepting,
      item.limit,
      `${money(item.todayAmount)} / ${item.todayCount} / ${item.successRate}`,
      `2026-06-24 / ${item.status}`,
      item.status === "正常" ? "编辑/测试/下架" : "编辑/删除"
    ]),
  "payment-order": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.platformOrderNo,
      `${item.merchant} / ${item.merchantOrderNo}`,
      `${money(item.amount)} / ${item.submittedIp || "-"}`,
      item.device || "H5 / Browser",
      `${money(item.amount)} / +${money(item.floatAmount)} / ${money(item.receivableAmount)} / ${money(item.confirmedAmount)}`,
      `${item.qrcodeName || "-"} / ${item.codeMerchant}`,
      `${item.createdAt} / ${item.finishedAt}`,
      item.remark || item.callbackStatus,
      item.status === "支付成功" ? "完成" : "计时中",
      item.status,
      item.status === "待确认"
        ? "详情/确认/聊天"
        : item.status === "支付成功" && item.callbackStatus !== "已回调"
          ? "详情/重试回调/聊天"
          : "详情/聊天"
    ]),
  "payout-order": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.platformOrderNo,
      `${item.merchant} / ${item.merchantOrderNo}`,
      `${item.payoutType || "银行卡"} / ${item.sourceIp || "-"}`,
      `${item.accountName} / ${item.accountNo}`,
      `${money(item.amount)} / ${money(item.fee)}`,
      item.channelTip || "-",
      item.codeMerchant || item.lockedBy || "-",
      `${item.createdAt || "-"} / ${item.lastAt || "-"}`,
      item.transferAttachment || "未上传",
      item.callbackStatus || "未回调",
      item.remark || item.reason || "-",
      item.status,
      item.status === "等待抢单"
        ? "详情/锁单/撤单"
        : item.status === "打款中"
          ? "详情/确认打款/冻结"
          : item.status === "冻结中"
            ? "详情/解冻"
            : item.status === "支付成功" && item.callbackStatus !== "已回调"
              ? "详情/重试回调"
              : "详情"
    ]),
  "available-code": (rows) =>
    rows.map((item) => [
      item.channelName,
      String(item.codeMerchantCount),
      String(item.onlineCodeMerchantCount),
      money(item.codeMerchantBalance),
      money(item.deposit),
      money(item.availableBalance),
      money(item.frozenBalance),
      String(item.qrcodeCount),
      String(item.availableQrcodeCount)
    ]),
  "code-merchant-list": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.username,
      item.googleBound ? "已绑定" : "未绑定",
      item.delaySettlement || "关闭",
      item.orderReserve || "关闭",
      item.parentPath || "顶级码商",
      money(item.frozen),
      money(item.deposit),
      item.status,
      item.accepting,
      item.remark || "-",
      `${item.createdAt || "-"} / ${item.lastOrderAt || "-"}`,
      money(Number(item.balance || 0) - Number(item.frozen || 0) - Number(item.deposit || 0)),
      item.accepting === "接单中" ? "编辑/重置密码/账变/冻结" : "编辑/重置密码/账变/恢复"
    ]),
  "code-merchant-channel": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.codeMerchant,
      item.channelName,
      item.paymentType,
      item.limit,
      item.rate,
      item.status,
      money(item.todayAmount),
      item.status === "接单中" ? "编辑/冻结" : "编辑/恢复"
    ]),
  "code-merchant-funds": (rows) =>
    rows
      .filter((item) => item.subjectType === "code_merchant")
      .map((item) => [
        String(item.id),
        item.orderNo,
        item.subjectName,
        item.type,
        money(item.amount),
        money(item.before),
        money(item.after),
        "-",
        "-",
        "账本流水",
        item.createdAt
      ]),
  "code-merchant-deposit": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.orderNo,
      item.fromAccount,
      item.toAccount,
      money(item.amount),
      money(item.fee),
      money(item.netAmount),
      item.transferAll ? "是" : "否",
      item.status,
      item.remark || "-",
      item.operator,
      item.createdAt
    ]),
  prediction: (rows) =>
    rows.map((item) => [
      item.channelName,
      item.codeMerchant,
      String(item.rank),
      String(item.waitingOrders),
      money(item.balance),
      money(item.availableBalance),
      item.lastOrderAt,
      item.availableBalance > 0 ? "可优先派单" : "余额不足"
    ]),
  "team-volume": (rows) =>
    rows.map((item) => [
      item.teamName,
      money(item.balance),
      item.balanceRate,
      money(item.payingAmount),
      item.onlineAccounts,
      String(item.lowerCount),
      money(item.totalOrderAmount),
      money(item.successOrderAmount),
      String(item.totalOrderCount),
      String(item.successOrderCount),
      item.successRate,
      item.orderCountRate
    ]),
  "daily-report": (rows) =>
    rows.map((item) => [
      item.date,
      `${money(item.rechargeAmount)} / ${item.rechargeCount} / ${money(item.rechargeFee)}`,
      `${money(item.withdrawAmount)} / ${item.withdrawCount}`,
      `${money(item.paymentAmount)} / ${item.paymentCount}`,
      item.paymentRate,
      `${money(item.payoutAmount)} / ${item.payoutCount}`,
      item.payoutRate,
      money(item.successAmount),
      money(item.profit)
    ]),
  "operation-log": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.module,
      item.action,
      item.target,
      item.operator,
      item.detail,
      item.createdAt
      ]),
  "operation-setting": (rows) =>
    rows.map((item) => [item.key, item.value, item.description, item.status, "编辑"]),
  "payment-channel": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.channelNo,
      item.channelName,
      item.paymentType,
      item.status,
      item.limit,
      item.defaultRate,
      String(item.sort),
      item.status === "启用" ? "编辑/停用" : "编辑/启用"
    ]),
  "telegram-group": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.groupName,
      item.groupId,
      item.botName,
      item.noticeTypes,
      item.status,
      item.createdAt,
      "编辑"
    ]),
  "telegram-config": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.botName,
      item.groupName,
      item.noticeTypes,
      item.status,
      "编辑"
    ]),
  "plugin-market": (rows) =>
    rows.map((item) => [
      item.name,
      item.category,
      item.version,
      item.status,
      item.updatedAt,
      item.description,
      item.status === "已启用" ? "配置/停用" : "安装"
    ]),
  "plugin-tools": (rows) =>
    rows.map((item) => [
      item.name,
      item.type,
      item.version,
      item.size,
      item.updatedAt,
      item.description,
      item.status
    ]),
  "plugin-guarantee": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.orderNo,
      item.merchant,
      item.codeMerchant,
      money(item.amount),
      item.status,
      item.createdAt,
      "查看"
    ]),
  "account-rules": (rows) =>
    rows.map((item) => [
      String(item.id),
      item.platformName,
      item.domainPrefix,
      item.username,
      money(item.balance),
      money(item.dailyRent),
      money(item.successOrderFee),
      item.status,
      item.remark || "-",
      item.createdAt,
      "充值/刷新"
    ])
};

const routeSummaryMappers: Partial<Record<DataRouteKey, (rows: any[]) => string>> = {
  "merchant-list": (rows) => `总商户数量:${rows.length}，商户总余额:${money(rows.reduce((sum, item) => sum + Number(item.balance || 0), 0))}`,
  "merchant-deposit": (rows) => `总金额:${money(rows.reduce((sum, item) => sum + Math.abs(Number(item.amount || 0)), 0))}，总笔数:${rows.length}`,
  "merchant-channel": (rows) => `通道总数:${rows.length}，通道类型:${new Set(rows.map((item) => item.channelName)).size}，已启用:${rows.filter((item) => item.status === "启用").length}`,
  "qrcode-list": (rows) => `总码数量:${rows.length}，正常:${rows.filter((item) => item.status === "正常").length}，停用:${rows.filter((item) => item.status !== "正常").length}`,
  "payment-order": (rows) => {
    const total = rows.reduce((sum, item) => sum + Number(item.amount || 0), 0);
    const success = rows.filter((item) => item.status === "支付成功");
    const received = success.reduce((sum, item) => sum + Number(item.confirmedAmount || 0), 0);
    const rate = rows.length ? `${Math.round((success.length / rows.length) * 100)}%` : "0%";
    return `总订单数量:${rows.length}，总订单金额:${money(total)}，总收款:${money(received)}，成功率:${rate}，码商总成本:${money(received)}，码商总利润:${money(total - received)}`;
  },
  "payout-order": (rows) => {
    const total = rows.reduce((sum, item) => sum + Number(item.amount || 0), 0);
    const success = rows.filter((item) => item.status === "支付成功");
    const successAmount = success.reduce((sum, item) => sum + Number(item.amount || 0), 0);
    const rate = rows.length ? `${Math.round((success.length / rows.length) * 100)}%` : "0%";
    return `总代付数量:${rows.length}，总代付金额:${money(total)}，交易成功金额:${money(successAmount)}，成功率:${rate}`;
  },
  "available-code": (rows) => {
    const channelCount = rows.length;
    const codeMerchantCount = rows.reduce((sum, item) => sum + Number(item.codeMerchantCount || 0), 0);
    const onlineCount = rows.reduce((sum, item) => sum + Number(item.onlineCodeMerchantCount || 0), 0);
    const qrcodeCount = rows.reduce((sum, item) => sum + Number(item.qrcodeCount || 0), 0);
    const availableCount = rows.reduce((sum, item) => sum + Number(item.availableQrcodeCount || 0), 0);
    return `通道总数:${channelCount}，码商总数:${codeMerchantCount}，在线码商:${onlineCount}，总码数:${qrcodeCount}，可用码数:${availableCount}`;
  },
  "code-merchant-list": (rows) =>
    `下面小弟数量：${rows.filter((item) => item.parentPath && item.parentPath !== "顶级码商").length}，可用余额:${money(rows.reduce((sum, item) => sum + Number(item.balance || 0) - Number(item.frozen || 0) - Number(item.deposit || 0), 0))}，冻结余额:${money(rows.reduce((sum, item) => sum + Number(item.frozen || 0), 0))}`,
  "code-merchant-channel": (rows) =>
    `码总数量:${rows.length}，码总种类:${new Set(rows.map((item) => item.channelName)).size}，接单中:${rows.filter((item) => item.status === "接单中").length}`,
  "code-merchant-deposit": (rows) =>
    `转账笔数:${rows.length}，总转出金额:${money(rows.reduce((sum, item) => sum + Number(item.amount || 0), 0))}，手续费:${money(rows.reduce((sum, item) => sum + Number(item.fee || 0), 0))}，净到账:${money(rows.reduce((sum, item) => sum + Number(item.netAmount || 0), 0))}`,
  prediction: (rows) =>
    `预计可接订单:${rows.reduce((sum, item) => sum + Number(item.waitingOrders || 0), 0)}，预计可接金额:${money(rows.reduce((sum, item) => sum + Number(item.availableBalance || 0), 0))}，可接码商:${rows.filter((item) => Number(item.availableBalance || 0) > 0).length}`,
  "team-volume": (rows) =>
    `团队总订单金额:${money(rows.reduce((sum, item) => sum + Number(item.totalOrderAmount || 0), 0))}，总成功金额:${money(rows.reduce((sum, item) => sum + Number(item.successOrderAmount || 0), 0))}，团队数:${rows.length}`,
  "daily-report": (rows) =>
    `总充值:${money(rows.reduce((sum, item) => sum + Number(item.rechargeAmount || 0), 0))}，总下发:${money(rows.reduce((sum, item) => sum + Number(item.withdrawAmount || 0), 0))}，总支付金额:${money(rows.reduce((sum, item) => sum + Number(item.paymentAmount || 0), 0))}，总代付金额:${money(rows.reduce((sum, item) => sum + Number(item.payoutAmount || 0), 0))}，总利润:${money(rows.reduce((sum, item) => sum + Number(item.profit || 0), 0))}`,
  "operation-setting": (rows) => `配置项:${rows.length}，启用:${rows.filter((item) => item.status === "启用").length}`,
  "payment-channel": (rows) => `通道类型:${rows.length}，启用:${rows.filter((item) => item.status === "启用").length}，停用:${rows.filter((item) => item.status !== "启用").length}`,
  "telegram-group": (rows) => `群组数量:${rows.length}，已绑定:${rows.filter((item) => item.botName).length}，启用:${rows.filter((item) => item.status === "启用").length}`,
  "telegram-config": (rows) => `机器人:${rows.length}，启用:${rows.filter((item) => item.status === "启用").length}`,
  "plugin-market": (rows) => `插件数量:${rows.length}，已启用:${rows.filter((item) => item.status === "已启用").length}，待安装:${rows.filter((item) => item.status === "待安装").length}`,
  "plugin-tools": (rows) => `工具数量:${rows.length}，可下载:${rows.filter((item) => item.status === "可下载").length}`,
  "plugin-guarantee": (rows) => `担保订单:${rows.length}，处理中:${rows.filter((item) => item.status === "处理中").length}，已完成:${rows.filter((item) => item.status === "已完成").length}`,
  "account-rules": (rows) => {
    const balance = rows.reduce((sum, item) => sum + Number(item.balance || 0), 0);
    const dailyRent = rows[0]?.dailyRent ?? 30;
    const successOrderFee = rows[0]?.successOrderFee ?? 0.03;
    return `当前余额:${money(balance)}，日租金:${money(dailyRent)}，成功订单手续费:${money(successOrderFee)}，已注册下级平台:${rows.length}`;
  }
};

const createConfigs: Record<CreateRouteKey, CreateConfig> = {
  "merchant-list": {
    title: "新建商户",
    endpoint: "/api/merchants",
    fields: [
      { name: "username", label: "登录名", placeholder: "例如 merchant_001" },
      { name: "phone", label: "电话", placeholder: "请输入电话" },
      { name: "email", label: "邮箱", placeholder: "请输入邮箱" },
      { name: "remark", label: "备注", placeholder: "请输入备注" }
    ],
    buildPayload: (values) => ({
      username: values.username,
      phone: values.phone,
      email: values.email,
      remark: values.remark,
      status: "启用"
    }),
    getEditEndpoint: (row) => `/api/merchants/${row[0]}`,
    getEditValues: (row) => ({
      username: row[1],
      phone: row[3].split(" / ")[0] || "",
      email: row[3].split(" / ")[1] || "",
      remark: row[6]
    })
  },
  "code-merchant-list": {
    title: "添加码商",
    endpoint: "/api/code-merchants",
    fields: [
      { name: "username", label: "登录名", placeholder: "例如 code_001" },
      { name: "phone", label: "电话", placeholder: "请输入电话" },
      { name: "email", label: "邮箱", placeholder: "请输入邮箱" },
      { name: "remark", label: "备注", placeholder: "请输入备注" }
    ],
    buildPayload: (values) => ({
      username: values.username,
      displayName: values.username,
      phone: values.phone,
      email: values.email,
      remark: values.remark,
      status: "离线",
      accepting: "暂停"
    }),
    getEditEndpoint: (row) => `/api/code-merchants/${row[0]}`,
    getEditValues: (row) => ({
      username: row[1],
      phone: "",
      email: "",
      remark: row[10]
    })
  },
  "qrcode-list": {
    title: "添加收款方式",
    endpoint: "/api/qrcodes",
    fields: [
      { name: "name", label: "码名称", placeholder: "例如 张三-支付宝-02" },
      { name: "paymentType", label: "支付类型", placeholder: "支付宝", defaultValue: "支付宝" },
      { name: "owner", label: "供应码商", placeholder: "code_001", defaultValue: "code_001" },
      { name: "limit", label: "拉单限额", placeholder: "50 - 3000", defaultValue: "50 - 3000" }
    ],
    buildPayload: (values) => ({
      name: values.name,
      paymentType: values.paymentType || "支付宝",
      owner: values.owner || "code_001",
      limit: values.limit || "50 - 3000",
      status: "正常",
      accepting: "可接单"
    }),
    getEditEndpoint: (row) => `/api/qrcodes/${row[0]}`,
    getEditValues: (row) => ({
      name: row[1],
      paymentType: row[2],
      owner: row[3].split(" / ")[0],
      limit: row[5]
    })
  },
  "code-merchant-deposit": {
    title: "发起转账",
    endpoint: "/api/code-merchant-transfers",
    fields: [
      { name: "fromAccount", label: "发起账号", placeholder: "例如 code_001", defaultValue: "code_001" },
      { name: "toAccount", label: "接收账号", placeholder: "例如 code_002", defaultValue: "code_002" },
      { name: "amount", label: "金额", placeholder: "0.00", defaultValue: "0", type: "number" },
      { name: "transferAll", label: "转出所有余额", placeholder: "", type: "checkbox" },
      { name: "remark", label: "备注", placeholder: "请输入备注" }
    ],
    buildPayload: (values) => ({
      fromAccount: values.fromAccount,
      toAccount: values.toAccount,
      amount: Number(values.amount || 0),
      transferAll: values.transferAll === "true",
      remark: values.remark,
      operator: "admin"
    })
  },
  "account-rules": {
    title: "注册下级平台",
    endpoint: "/api/sub-platforms",
    fields: [
      { name: "platformName", label: "平台名字", placeholder: "请输入平台名字" },
      { name: "domainPrefix", label: "域名前缀", placeholder: "例如 agent002" },
      { name: "username", label: "账号", placeholder: "请输入账号" },
      { name: "remark", label: "备注", placeholder: "请输入备注" }
    ],
    buildPayload: (values) => ({
      platformName: values.platformName,
      domainPrefix: values.domainPrefix,
      username: values.username,
      remark: values.remark,
      dailyRent: 30,
      successOrderFee: 0.03,
      status: "启用"
    })
  }
};

const queryParamMap: Partial<Record<RouteKey, string[]>> = {
  "merchant-list": ["username", "merchantNo", "remark"],
  "merchant-channel": ["merchant", "channelName", "status", "remark"],
  "merchant-balance": ["orderNo", "subjectName", "type", "createdAt"],
  "qrcode-list": ["owner", "paymentType", "name", "status", "accepting"],
  "payment-order": ["merchantOrderNo", "platformOrderNo", "paymentType", "codeMerchant", "merchant", "amount", "qrcodeName"],
  "payout-order": ["merchantOrderNo", "platformOrderNo", "payoutType", "codeMerchant", "merchant", "amount", "accountName", "createdAt", "status"],
  "available-code": ["channelName"],
  "code-merchant-list": ["username", "remark", "status", "accepting", "availableBelow", "topOnly"],
  "code-merchant-deposit": ["orderNo", "fromAccount", "toAccount", "status"],
  "code-merchant-channel": ["channelName", "codeMerchant", "status"],
  "code-merchant-funds": ["orderNo", "subjectName", "type", "createdAt"],
  prediction: ["channelName", "codeMerchant", "amount"],
  "team-volume": ["paymentType", "dateRange"],
  "daily-report": ["date"],
  "operation-log": ["module", "action", "target", "operator"],
  "operation-setting": ["key", "status"],
  "payment-channel": ["channelName", "paymentType", "status"],
  "telegram-group": ["groupName", "botName", "status"],
  "telegram-config": ["botName", "groupName"],
  "plugin-market": ["name", "category", "status"],
  "plugin-tools": ["name", "type"],
  "plugin-guarantee": ["orderNo", "merchant", "status"],
  "account-rules": ["platformName", "username", "status"]
};

const getMenuPath = (key: RouteKey) => {
  for (const group of menu) {
    if (group.children?.some((item) => item.key === key)) return group.label;
  }
  return "首页";
};

function Login({ onDone }: { onDone: () => void }) {
  const [username, setUsername] = React.useState("admin");
  const [password, setPassword] = React.useState("123123");
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState("");

  return (
    <main className="login-page">
      <form
        className="login-box"
        onSubmit={async (event) => {
          event.preventDefault();
          setLoading(true);
          setError("");
          try {
            const response = await fetch("/api/system/auth/login", {
              method: "POST",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify({ username, password })
            });
            const result = (await response.json()) as ApiResponse<{ access_token: string }>;
            if (!response.ok || result.code !== 0) throw new Error(result.message || "登录失败");
            localStorage.setItem("zhifu_token", result.data.access_token);
            onDone();
          } catch (err) {
            setError(err instanceof Error ? err.message : "登录失败");
          } finally {
            setLoading(false);
          }
        }}
      >
        <div className="login-logo">奈</div>
        <h1>奈计支付系统</h1>
        <label>
          登录名
          <input value={username} onChange={(event) => setUsername(event.target.value)} autoComplete="username" />
        </label>
        <label>
          密码
          <input type="password" value={password} onChange={(event) => setPassword(event.target.value)} autoComplete="current-password" />
        </label>
        {error ? <div className="login-error">{error}</div> : null}
        <button type="submit" disabled={loading}>{loading ? "登录中..." : "登录"}</button>
      </form>
    </main>
  );
}

function Sidebar({ active, onChange }: { active: RouteKey; onChange: (key: RouteKey) => void }) {
  return (
    <aside className="admin-sidebar">
      <div className="brand">
        <div className="brand-logo">奈</div>
        <strong>奈计支付系统</strong>
      </div>
      <nav className="menu-list">
        {menu.map((group) => {
          const Icon = group.icon;
          const expanded = Boolean(group.children?.length);
          const groupActive = group.children?.some((item) => item.key === active);
          return (
            <div className="menu-group" key={group.key}>
              <button
                className={`menu-row ${groupActive ? "group-active" : ""}`}
                onClick={() => {
                  if (group.children?.length) onChange(group.children[0].key);
                }}
              >
                <Icon size={18} />
                <span>{group.label}</span>
                {expanded ? <ChevronDown size={15} className="menu-arrow" /> : null}
              </button>
              {expanded ? (
                <div className="submenu">
                  {group.children?.map((item) => {
                    const ChildIcon = item.icon;
                    return (
                      <button className={`submenu-row ${item.key === active ? "active" : ""}`} key={item.key} onClick={() => onChange(item.key)}>
                        <ChildIcon size={17} />
                        <span>{item.label}</span>
                      </button>
                    );
                  })}
                </div>
              ) : null}
            </div>
          );
        })}
      </nav>
    </aside>
  );
}

function Header({ page }: { page: PageConfig }) {
  return (
    <>
      <header className="admin-header">
        <div className="breadcrumb">
          <Menu size={18} />
          <span>首页</span>
          <span>/</span>
          <span>{page.group}</span>
          <span>/</span>
          <span className="muted">{page.title}</span>
        </div>
        <div className="header-actions">
          <Fullscreen size={18} />
          <Volume2 size={19} />
          <div className="avatar">奈</div>
          <span>huhu</span>
        </div>
      </header>
      <div className="tabs-row">
        <button className="tab-scroll"><ChevronLeft size={18} /></button>
        <button className="tab">首页</button>
        <button className="tab active">
          <span className="dot" />
          {page.title}
          <X size={14} />
        </button>
        <div className="tab-fill" />
        <button className="tab-scroll"><ChevronRight size={18} /></button>
        <button className="tab-scroll"><RefreshCw size={17} /></button>
        <button className="tab-scroll"><Settings size={17} /></button>
      </div>
    </>
  );
}

function FilterPanel({
  page,
  active,
  values,
  onValueChange,
  onSearch,
  onReset,
  onCreate
}: {
  page: PageConfig;
  active: RouteKey;
  values: Record<string, string>;
  onValueChange: (name: string, value: string) => void;
  onSearch: () => void;
  onReset: () => void;
  onCreate: (key: CreateRouteKey) => void;
}) {
  const queryNames = queryParamMap[active] ?? [];

  return (
    <section className="filter-panel">
      <div className="filter-grid">
        {page.filters.map(([label, placeholder], index) => {
          const name = queryNames[index] ?? `field${index}`;
          return (
          <label className="field" key={label}>
            <span>{label}:</span>
            <input placeholder={placeholder} value={values[name] ?? ""} onChange={(event) => onValueChange(name, event.target.value)} />
          </label>
          );
        })}
        <div className="filter-actions">
          <button className="btn primary" type="button" onClick={onSearch}><Search size={16} />查询</button>
          {page.actions?.map((action) => {
            const canCreate = active === "merchant-list" || active === "code-merchant-list" || active === "qrcode-list" || active === "code-merchant-deposit" || active === "account-rules";
            return (
              <button
                className="btn primary soft"
                key={action}
                type="button"
                onClick={() => {
                  if (canCreate) onCreate(active);
                }}
              >
                {action}
              </button>
            );
          })}
          <button className="btn" type="button" onClick={onReset}><RefreshCw size={15} />重置</button>
          <button className="link-btn">展开<ChevronDown size={15} /></button>
        </div>
      </div>
    </section>
  );
}

function CreateDialog({
  config,
  mode,
  row,
  onClose,
  onCreated
}: {
  config: CreateConfig;
  mode: "create" | "edit";
  row?: string[];
  onClose: () => void;
  onCreated: () => void;
}) {
  const [values, setValues] = React.useState<Record<string, string>>(() =>
    mode === "edit" && row && config.getEditValues
      ? config.getEditValues(row)
      : Object.fromEntries(config.fields.map((field) => [field.name, field.defaultValue ?? ""]))
  );
  const [saving, setSaving] = React.useState(false);
  const [error, setError] = React.useState("");

  const submit = async (event: React.FormEvent) => {
    event.preventDefault();
    setSaving(true);
    setError("");
    try {
      const endpoint = mode === "edit" && row && config.getEditEndpoint ? config.getEditEndpoint(row) : config.endpoint;
      const response = await fetch(endpoint, {
        method: mode === "edit" ? "PUT" : "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(config.buildPayload(values))
      });
      const result = (await response.json()) as ApiResponse<unknown>;
      if (!response.ok || result.code !== 0) throw new Error(result.message || "保存失败");
      onCreated();
      onClose();
    } catch (err) {
      setError(err instanceof Error ? err.message : "保存失败");
    } finally {
      setSaving(false);
    }
  };

  return (
    <div className="modal-mask">
      <form className="modal-panel" onSubmit={submit}>
        <div className="modal-head">
          <strong>{mode === "edit" ? config.title.replace(/^新建|^创建|^添加/, "编辑") : config.title}</strong>
          <button type="button" onClick={onClose}><X size={18} /></button>
        </div>
        <div className="modal-body">
          {config.fields.map((field) => (
            <label className="modal-field" key={field.name}>
              <span>{field.label}</span>
              {field.type === "checkbox" ? (
                <select
                  value={values[field.name] || "false"}
                  onChange={(event) => setValues((current) => ({ ...current, [field.name]: event.target.value }))}
                >
                  <option value="false">否</option>
                  <option value="true">是</option>
                </select>
              ) : (
                <input
                  type={field.type || "text"}
                  placeholder={field.placeholder}
                  value={values[field.name] ?? ""}
                  onChange={(event) => setValues((current) => ({ ...current, [field.name]: event.target.value }))}
                />
              )}
            </label>
          ))}
          {error ? <div className="modal-error">{error}</div> : null}
        </div>
        <div className="modal-foot">
          <button type="button" className="btn" onClick={onClose}>取消</button>
          <button type="submit" className="btn primary" disabled={saving}>{saving ? "保存中..." : "确定"}</button>
        </div>
      </form>
    </div>
  );
}

function AdjustDialog({
  state,
  onClose,
  onDone
}: {
  state: AdjustState;
  onClose: () => void;
  onDone: () => void;
}) {
  const isCodeMerchant = state.route === "code-merchant-list";
  const [amount, setAmount] = React.useState("");
  const [direction, setDirection] = React.useState("充值");
  const [account, setAccount] = React.useState("余额");
  const [remark, setRemark] = React.useState("");
  const [saving, setSaving] = React.useState(false);
  const [error, setError] = React.useState("");

  const submit = async (event: React.FormEvent) => {
    event.preventDefault();
    setSaving(true);
    setError("");
    try {
      const endpoint = isCodeMerchant
        ? `/api/code-merchants/${state.row[0]}/adjust-funds`
        : `/api/merchants/${state.row[0]}/adjust-balance`;
      const response = await fetch(endpoint, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ amount: Number(amount), direction, account, remark, operator: "admin" })
      });
      const result = (await response.json()) as ApiResponse<unknown>;
      if (!response.ok || result.code !== 0) throw new Error(result.message || "账变失败");
      onDone();
      onClose();
    } catch (err) {
      setError(err instanceof Error ? err.message : "账变失败");
    } finally {
      setSaving(false);
    }
  };

  return (
    <div className="modal-mask">
      <form className="modal-panel" onSubmit={submit}>
        <div className="modal-head">
          <strong>{isCodeMerchant ? "码商账变" : "商户账变"}</strong>
          <button type="button" onClick={onClose}><X size={18} /></button>
        </div>
        <div className="modal-body">
          <label className="modal-field">
            <span>对象</span>
            <input value={state.row[1]} readOnly />
          </label>
          {isCodeMerchant ? (
            <label className="modal-field">
              <span>账户</span>
              <select value={account} onChange={(event) => setAccount(event.target.value)}>
                <option>余额</option>
                <option>押金</option>
                <option>佣金</option>
              </select>
            </label>
          ) : null}
          <label className="modal-field">
            <span>类型</span>
            <select value={direction} onChange={(event) => setDirection(event.target.value)}>
              <option>充值</option>
              <option>扣款</option>
            </select>
          </label>
          <label className="modal-field">
            <span>金额</span>
            <input type="number" placeholder="0.00" value={amount} onChange={(event) => setAmount(event.target.value)} />
          </label>
          <label className="modal-field">
            <span>备注</span>
            <input placeholder="请输入操作原因" value={remark} onChange={(event) => setRemark(event.target.value)} />
          </label>
          {error ? <div className="modal-error">{error}</div> : null}
        </div>
        <div className="modal-foot">
          <button type="button" className="btn" onClick={onClose}>取消</button>
          <button type="submit" className="btn primary" disabled={saving}>{saving ? "提交中..." : "确定"}</button>
        </div>
      </form>
    </div>
  );
}

function DetailDialog({
  state,
  onClose
}: {
  state: DetailState;
  onClose: () => void;
}) {
  const [detail, setDetail] = React.useState<any | null>(null);
  const [error, setError] = React.useState("");

  React.useEffect(() => {
    let alive = true;
    fetch(`/api/payment-orders/${state.row[0]}`)
      .then((response) => response.json() as Promise<ApiResponse<any>>)
      .then((result) => {
        if (!alive) return;
        if (result.code !== 0) throw new Error(result.message);
        setDetail(result.data);
      })
      .catch((err) => {
        if (alive) setError(err instanceof Error ? err.message : "加载失败");
      });
    return () => {
      alive = false;
    };
  }, [state.row]);

  const fields = detail
    ? [
        ["平台订单", detail.platformOrderNo],
        ["商户订单", detail.merchantOrderNo],
        ["商户", detail.merchant],
        ["码商", detail.codeMerchant],
        ["订单金额", money(detail.amount)],
        ["浮动金额", money(detail.floatAmount)],
        ["应收金额", money(detail.receivableAmount)],
        ["确认金额", money(detail.confirmedAmount)],
        ["订单状态", detail.status],
        ["回调状态", detail.callbackStatus],
        ["下单时间", detail.createdAt],
        ["完成时间", detail.finishedAt]
      ]
    : [];

  return (
    <div className="modal-mask">
      <section className="modal-panel detail-panel">
        <div className="modal-head">
          <strong>收款订单详情</strong>
          <button type="button" onClick={onClose}><X size={18} /></button>
        </div>
        <div className="modal-body">
          {error ? <div className="modal-error">{error}</div> : null}
          {!detail && !error ? <div className="detail-loading">加载中...</div> : null}
          {detail ? (
            <>
              <div className="detail-grid">
                {fields.map(([label, value]) => (
                  <div className="detail-item" key={label}>
                    <span>{label}</span>
                    <strong>{value || "-"}</strong>
                  </div>
                ))}
              </div>
              <div className="detail-section">
                <strong>关联账本</strong>
                {detail.ledger?.length ? (
                  detail.ledger.map((item: any) => (
                    <div className="detail-ledger" key={item.id}>
                      <span>{item.type}</span>
                      <span>{money(item.amount)}</span>
                      <span>{item.operator}</span>
                      <span>{item.createdAt}</span>
                    </div>
                  ))
                ) : (
                  <p>暂无账本流水</p>
                )}
              </div>
            </>
          ) : null}
        </div>
        <div className="modal-foot">
          <button type="button" className="btn primary" onClick={onClose}>关闭</button>
        </div>
      </section>
    </div>
  );
}

function DataPanel({
  page,
  active,
  onReload,
  onEdit,
  onAdjust,
  onDetail
}: {
  page: PageConfig;
  active: RouteKey;
  onReload: () => void;
  onEdit: (key: CreateRouteKey, row: string[]) => void;
  onAdjust: (state: AdjustState) => void;
  onDetail: (state: DetailState) => void;
}) {
  const handleAction = async (row: string[]) => {
    const actionText = row[row.length - 1] ?? "";
    if (active === "payout-order") {
      const action = getPayoutAction(actionText);
      if (!action) return;
      const body = action === "mark-paid" ? { operator: "admin", reason: "运营确认已打款", attachmentUrl: "manual-confirm" } : { operator: "admin", reason: "运营手动处理" };
      await postTableAction(`/api/payout-orders/${row[0]}/${action}`, `确认执行代付订单 ${row[1]} 的 ${getPayoutActionLabel(action)}？`, onReload, body);
      return;
    }
    if (active === "payment-order" && actionText.includes("重试回调")) {
      await postTableAction(`/api/payment-orders/${row[0]}/retry-callback`, `确认重试回调订单 ${row[1]}？`, onReload);
      return;
    }
    if (active === "merchant-list" && actionText.includes("停用")) {
      await postTableAction(`/api/merchants/${row[0]}/toggle`, `确认切换商户 ${row[1]} 的状态？`, onReload);
      return;
    }
    if (active === "code-merchant-list" && (actionText.includes("冻结") || actionText.includes("解冻") || actionText.includes("接单"))) {
      await postTableAction(`/api/code-merchants/${row[0]}/toggle`, `确认切换码商 ${row[1]} 的接单状态？`, onReload);
      return;
    }
    if (active === "qrcode-list" && (actionText.includes("下架") || actionText.includes("上架") || actionText.includes("删除"))) {
      await postTableAction(`/api/qrcodes/${row[0]}/toggle`, `确认切换收款码 ${row[1]} 的状态？`, onReload);
      return;
    }
    if (active !== "payment-order" || !actionText.includes("确认")) return;
    const orderId = row[0];
    await postTableAction(`/api/payment-orders/${orderId}/confirm`, `确认收款订单 ${row[1]} 已到账？`, onReload);
  };

  return (
    <section className="table-panel">
      <div className="summary-bar">
        <span>{page.summary}</span>
        <div className="table-tools">
          <button className="select-btn">不刷新<ChevronDown size={15} /></button>
          <button className="round gray"><Search size={18} /></button>
          <button className="round blue"><RefreshCw size={18} /></button>
          <button className="round red"><SlidersHorizontal size={18} /></button>
        </div>
      </div>
      {page.notice ? <div className="notice-line">{page.notice}</div> : null}
      <div className="data-table">
        <table>
          <thead>
            <tr>
              {page.columns.map((column) => <th key={column}>{column}</th>)}
            </tr>
          </thead>
          <tbody>
            {page.rows?.length ? (
              page.rows.map((row, index) => (
                <tr key={`${page.title}-${index}`}>
                  {page.columns.map((column, columnIndex) => (
                    <td key={column}>
                      {columnIndex === page.columns.length - 1 && isActionButton(active, row[columnIndex]) ? (
                        <div className="row-actions">
                          {isEditableRoute(active) ? (
                            <button className="table-action gray" onClick={() => onEdit(active, row)}>编辑</button>
                          ) : null}
                          {active === "merchant-list" || active === "code-merchant-list" ? (
                            <button className="table-action amber" onClick={() => onAdjust({ route: active, row })}>账变</button>
                          ) : null}
                          {active === "payment-order" ? (
                            <button className="table-action gray" onClick={() => onDetail({ route: "payment-order", row })}>详情</button>
                          ) : null}
                          {shouldShowPrimaryAction(active, row[columnIndex]) ? (
                            <button className="table-action" onClick={() => handleAction(row)}>{getActionLabel(active, row[columnIndex])}</button>
                          ) : null}
                        </div>
                      ) : (
                        row[columnIndex] ?? "-"
                      )}
                    </td>
                  ))}
                </tr>
              ))
            ) : (
              <tr>
                <td colSpan={page.columns.length}>
                  <div className="empty-state">
                    <PackageOpen size={84} strokeWidth={1.1} />
                    <span>暂无数据</span>
                  </div>
                </td>
              </tr>
            )}
          </tbody>
        </table>
      </div>
      <div className="pagination">
        <span>共 {page.rows?.length ?? 0} 条</span>
        <button className="page-size">10条/页<ChevronDown size={15} /></button>
        <button className="page-btn disabled"><ChevronLeft size={16} /></button>
        <button className="page-btn active">1</button>
        <button className="page-btn disabled"><ChevronRight size={16} /></button>
        <span>前往</span>
        <input value="1" readOnly />
        <span>页</span>
      </div>
    </section>
  );
}

const postTableAction = async (endpoint: string, message: string, onReload: () => void, body: Record<string, unknown> = { operator: "admin" }) => {
  if (!window.confirm(message)) return;
  const response = await fetch(endpoint, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body)
  });
  const result = (await response.json()) as ApiResponse<unknown>;
  if (result.code !== 0) {
    window.alert(result.message || "操作失败");
    return;
  }
  onReload();
};

const isActionButton = (active: RouteKey, text = "") => {
  if (active === "payment-order") return text.includes("确认") || text.includes("详情") || text.includes("重试回调");
  if (active === "payout-order") return text.includes("锁单") || text.includes("撤单") || text.includes("确认打款") || text.includes("冻结") || text.includes("解冻") || text.includes("重试回调");
  if (active === "merchant-list") return text.includes("停用") || text.includes("启用");
  if (active === "code-merchant-list") return text.includes("冻结") || text.includes("解冻") || text.includes("接单");
  if (active === "qrcode-list") return text.includes("下架") || text.includes("上架") || text.includes("删除");
  return false;
};

const getActionLabel = (active: RouteKey, text = "") => {
  if (active === "payment-order") return text.includes("重试回调") ? "重试回调" : text.includes("确认") ? "确认收款" : "查看";
  if (active === "merchant-list") return text.includes("停用") ? "停用" : "启用";
  if (active === "code-merchant-list") return text.includes("冻结") ? "冻结接单" : "恢复接单";
  if (active === "qrcode-list") return text.includes("下架") || text.includes("删除") ? "下架" : "上架";
  if (active === "payout-order") return getPayoutActionLabel(getPayoutAction(text) || "");
  return "操作";
};

const shouldShowPrimaryAction = (active: RouteKey, text = "") => {
  if (active === "payment-order") return text.includes("确认") || text.includes("重试回调");
  if (active === "payout-order") return Boolean(getPayoutAction(text));
  return true;
};

const getPayoutAction = (text = "") => {
  if (text.includes("确认打款")) return "mark-paid";
  if (text.includes("重试回调")) return "retry-callback";
  if (text.includes("解冻")) return "unfreeze";
  if (text.includes("冻结")) return "freeze";
  if (text.includes("撤单")) return "cancel";
  if (text.includes("锁单")) return "lock";
  return "";
};

const getPayoutActionLabel = (action = "") => {
  const labels: Record<string, string> = {
    lock: "锁单",
    cancel: "撤单",
    freeze: "冻结",
    unfreeze: "解冻",
    "mark-paid": "确认打款",
    "retry-callback": "重试回调"
  };
  return labels[action] || "操作";
};

const isEditableRoute = (active: RouteKey): active is CreateRouteKey =>
  active === "merchant-list" || active === "code-merchant-list" || active === "qrcode-list" || active === "code-merchant-deposit" || active === "account-rules";

function AdminApp() {
  const [authed, setAuthed] = React.useState(() => Boolean(localStorage.getItem("zhifu_token")));
  const [active, setActive] = React.useState<RouteKey>("payment-order");
  const [remoteRows, setRemoteRows] = React.useState<string[][] | null>(null);
  const [remoteSummary, setRemoteSummary] = React.useState<string | null>(null);
  const [loading, setLoading] = React.useState(false);
  const [reloadKey, setReloadKey] = React.useState(0);
  const [dialogState, setDialogState] = React.useState<DialogState | null>(null);
  const [adjustState, setAdjustState] = React.useState<AdjustState | null>(null);
  const [detailState, setDetailState] = React.useState<DetailState | null>(null);
  const [filterValues, setFilterValues] = React.useState<Record<string, string>>({});
  const [queryValues, setQueryValues] = React.useState<Record<string, string>>({});
  const page = pageConfigs[active];

  React.useEffect(() => {
    setFilterValues({});
    setQueryValues({});
  }, [active]);

  React.useEffect(() => {
    if (!authed) return;
    const endpoint = routeApiMap[active as DataRouteKey];
    const mapper = routeRowMappers[active as DataRouteKey];
    if (!endpoint || !mapper) {
      setRemoteRows(null);
      setRemoteSummary(null);
      return;
    }

    let alive = true;
    setLoading(true);
    const search = new URLSearchParams();
    Object.entries(queryValues).forEach(([key, value]) => {
      if (value) search.set(key, value);
    });
    const url = search.toString() ? `${endpoint}?${search.toString()}` : endpoint;

    fetch(url)
      .then((response) => response.json() as Promise<ApiResponse<any[]>>)
      .then((result) => {
        if (!alive) return;
        if (result.code !== 0) throw new Error(result.message);
        setRemoteRows(mapper(result.data));
        setRemoteSummary(routeSummaryMappers[active as DataRouteKey]?.(result.data) ?? null);
      })
      .catch(() => {
        if (!alive) return;
        setRemoteRows(null);
        setRemoteSummary(null);
      })
      .finally(() => {
        if (alive) setLoading(false);
      });

    return () => {
      alive = false;
    };
  }, [active, authed, reloadKey, queryValues]);

  const runtimePage = {
    ...page,
    rows: remoteRows ?? page.rows,
    summary: loading ? `${page.summary}，正在刷新...` : remoteSummary ?? page.summary
  };

  if (!authed) return <Login onDone={() => setAuthed(true)} />;

  return (
    <div className="admin-app">
      <Sidebar active={active} onChange={setActive} />
      <main className="admin-main">
        <Header page={runtimePage} />
        <div className="page-body">
          <FilterPanel
            page={runtimePage}
            active={active}
            values={filterValues}
            onValueChange={(name, value) => setFilterValues((current) => ({ ...current, [name]: value }))}
            onSearch={() => setQueryValues(filterValues)}
            onReset={() => {
              setFilterValues({});
              setQueryValues({});
            }}
            onCreate={(key) => setDialogState({ key, mode: "create" })}
          />
          <DataPanel
            page={runtimePage}
            active={active}
            onReload={() => setReloadKey((value) => value + 1)}
            onEdit={(key, row) => setDialogState({ key, mode: "edit", row })}
            onAdjust={setAdjustState}
            onDetail={setDetailState}
          />
        </div>
      </main>
      {dialogState ? (
        <CreateDialog
          config={createConfigs[dialogState.key]}
          mode={dialogState.mode}
          row={dialogState.row}
          onClose={() => setDialogState(null)}
          onCreated={() => setReloadKey((value) => value + 1)}
        />
      ) : null}
      {adjustState ? (
        <AdjustDialog
          state={adjustState}
          onClose={() => setAdjustState(null)}
          onDone={() => setReloadKey((value) => value + 1)}
        />
      ) : null}
      {detailState ? (
        <DetailDialog state={detailState} onClose={() => setDetailState(null)} />
      ) : null}
    </div>
  );
}

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <AdminApp />
  </StrictMode>
);
