import { useCallback, useEffect, useRef, useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import {
  assignBillingFormula,
  cancelUserSubscription,
  createSubscriptionPlan,
  deleteSubscriptionPlan,
  getAdminUsageStats,
  getAdminUsageSummary,
  getBillingConfig,
  grantUserSubscription,
  listAdminLedger,
  listAdminSubscriptions,
  listAdminUsage,
  listSubscriptionPlans,
  rechargeUser,
  syncSubscriptionPlansToProduction,
  updateBillingConfig,
  updateSubscriptionPlan,
} from '../../api/client';
import type { PagedResult } from '../../api/client';
import type {
  AdminSubscription,
  AdminUserRow,
  BillingAdminConfig,
  BillingFormulaKey,
  LedgerEntry,
  PlanDefinition,
  UsageRecord,
  UsageStatsResult,
  UsageSummaryResult,
  UsageTotals,
} from '../../types';
import { Pagination } from '../../components/Pagination';
import {
  dateRangeToUnix,
  DEFAULT_CHART_METRICS,
  METRIC_CONFIG,
  METRIC_OPTIONS,
  presetDateRange,
  toggleChartMetric,
  UsageTrendChart,
  type UsageChartMetric,
  type UsageChartType,
} from '../../components/UsageTrendChart';
import { useAdminUsers } from '../hooks/useAdminUsers';
import { formatTime, formatYuan } from '../utils/format';

function UserCombobox({
  users,
  value,
  onChange,
  placeholder = '搜索用户名 / 显示名称',
}: {
  users: AdminUserRow[];
  value: string;
  onChange: (id: string) => void;
  placeholder?: string;
}) {
  const [query, setQuery] = useState('');
  const [open, setOpen] = useState(false);
  const ref = useRef<HTMLDivElement>(null);

  const selected = users.find((u) => u.id === value);

  const filtered = query.trim()
    ? users.filter((u) => {
        const q = query.toLowerCase();
        return u.username.toLowerCase().includes(q) || u.displayName.toLowerCase().includes(q);
      })
    : users;

  useEffect(() => {
    const handler = (e: MouseEvent) => {
      if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);
    };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, []);

  const select = (u: AdminUserRow) => {
    onChange(u.id);
    setQuery('');
    setOpen(false);
  };

  const clear = () => {
    onChange('');
    setQuery('');
  };

  return (
    <div ref={ref} className="user-combobox">
      <div className="user-combobox-input-wrap" onClick={() => setOpen(true)}>
        {selected && !open ? (
          <span className="user-combobox-selected">
            {selected.displayName} <span className="muted">@{selected.username}</span>
            <span className="user-combobox-balance">¥{formatYuan(selected.balanceCents)}</span>
          </span>
        ) : (
          <input
            className="user-combobox-input"
            placeholder={selected ? `${selected.displayName} @${selected.username}` : placeholder}
            value={query}
            autoFocus={open}
            onChange={(e) => { setQuery(e.target.value); setOpen(true); }}
            onFocus={() => setOpen(true)}
          />
        )}
        {value && (
          <button type="button" className="user-combobox-clear" onClick={(e) => { e.stopPropagation(); clear(); }}>×</button>
        )}
      </div>
      {open && (
        <div className="user-combobox-dropdown">
          {filtered.length === 0 ? (
            <div className="user-combobox-empty">无匹配用户</div>
          ) : (
            filtered.map((u) => (
              <div key={u.id} className="user-combobox-option" onMouseDown={() => select(u)}>
                <span className="user-combobox-name">{u.displayName}</span>
                <span className="user-combobox-meta muted">@{u.username}</span>
                <span className="user-combobox-bal">¥{formatYuan(u.balanceCents)}</span>
              </div>
            ))
          )}
        </div>
      )}
    </div>
  );
}

type TabKey = 'recharge' | 'usage' | 'ledger' | 'subscriptions' | 'formula';

const TABS: { key: TabKey; label: string }[] = [
  { key: 'subscriptions', label: '订阅记录' },
  { key: 'recharge', label: '充值' },
  { key: 'usage', label: '用量记录' },
  { key: 'ledger', label: '资金流水' },
  { key: 'formula', label: '计量公式' },
];

const TAB_PATHS: Record<TabKey, string> = {
  subscriptions: '/billing',
  recharge: '/billing/recharge',
  usage: '/billing/usage',
  ledger: '/billing/ledger',
  formula: '/billing/formula',
};

const SOURCE_LABELS: Record<string, string> = {
  'admin-db': '后台配置',
  env: '环境变量',
  'env-override': '环境变量锁定',
  default: '默认值',
};

function tabFromPath(pathname: string): TabKey {
  const suffix = pathname.replace(/^\/billing\/?/, '');
  if (suffix === 'usage' || suffix.startsWith('usage/')) return 'usage';
  if (suffix === 'recharge') return 'recharge';
  if (suffix === 'ledger') return 'ledger';
  if (suffix === 'formula') return 'formula';
  if (suffix === 'subscriptions') return 'subscriptions';
  return 'subscriptions';
}

const DEFAULT_BILLING_FORMULA: BillingAdminConfig = {
  useBackendCost: true,
  usdCnyRate: 7.2,
  marginMultiplier: 1.2,
  inputCentsPer1k: 2,
  outputCentsPer1k: 6,
  minBillCents: 1,
  costEstimateFromTokens: true,
  costEstimateInputUsdPer1M: 0.27,
  costEstimateOutputUsdPer1M: 1.1,
};

const FORMULA_TABS: BillingFormulaKey[] = ['A', 'B'];

function FormulaConfigForm({
  formulaKey,
  draft,
  source,
  updatedAt,
  envLocked,
  saving,
  onDraftChange,
  onSave,
}: {
  formulaKey: BillingFormulaKey;
  draft: BillingAdminConfig;
  source: string;
  updatedAt: number | null;
  envLocked: boolean;
  saving: boolean;
  onDraftChange: (next: BillingAdminConfig) => void;
  onSave: (event: React.FormEvent) => void;
}) {
  const patchNumber = (key: keyof BillingAdminConfig, value: string) => {
    const num = Number(value);
    onDraftChange({
      ...draft,
      [key]: Number.isFinite(num) ? num : draft[key],
    });
  };

  return (
    <form className="admin-form" onSubmit={onSave}>
      <p className="muted">
        计量公式 {formulaKey} · 来源：{SOURCE_LABELS[source] ?? source}
        {updatedAt
          ? ` · 更新于 ${new Date(updatedAt).toLocaleString('zh-CN', { hour12: false })}`
          : ''}
      </p>

      <label className="inline-check">
        <input
          type="checkbox"
          checked={draft.useBackendCost}
          disabled={envLocked}
          onChange={(event) => onDraftChange({ ...draft, useBackendCost: event.target.checked })}
        />
        <span>
          <strong>启用成本模式</strong>
          <span className="muted"> 按上游真实 USD 成本扣费（推荐）</span>
        </span>
      </label>

      <label>
        <span>汇率（USD→CNY）</span>
        <input
          type="number"
          min="0.01"
          step="0.01"
          disabled={envLocked}
          value={draft.usdCnyRate}
          onChange={(e) => patchNumber('usdCnyRate', e.target.value)}
        />
      </label>
      <label>
        <span>毛利倍数</span>
        <input
          type="number"
          min="0.01"
          step="0.01"
          disabled={envLocked}
          value={draft.marginMultiplier}
          onChange={(e) => patchNumber('marginMultiplier', e.target.value)}
        />
      </label>
      <label>
        <span>最低扣费（分）</span>
        <input
          type="number"
          min="1"
          step="1"
          disabled={envLocked}
          value={draft.minBillCents}
          onChange={(e) => patchNumber('minBillCents', e.target.value)}
        />
      </label>

      <h3>Token 回退单价（成本缺失时）</h3>
      <label>
        <span>输入（分 / 1k tokens）</span>
        <input
          type="number"
          min="0"
          step="0.01"
          disabled={envLocked}
          value={draft.inputCentsPer1k}
          onChange={(e) => patchNumber('inputCentsPer1k', e.target.value)}
        />
      </label>
      <label>
        <span>输出（分 / 1k tokens）</span>
        <input
          type="number"
          min="0"
          step="0.01"
          disabled={envLocked}
          value={draft.outputCentsPer1k}
          onChange={(e) => patchNumber('outputCentsPer1k', e.target.value)}
        />
      </label>

      <h3>上游成本估算（Finish 无 cost 时）</h3>
      <label className="inline-check">
        <input
          type="checkbox"
          checked={draft.costEstimateFromTokens}
          disabled={envLocked || !draft.useBackendCost}
          onChange={(event) => onDraftChange({
            ...draft,
            costEstimateFromTokens: event.target.checked,
          })}
        />
        <span>
          <strong>按 Token 估算上游成本</strong>
          <span className="muted"> 仅成本模式生效</span>
        </span>
      </label>
      <label>
        <span>估算输入（USD / 1M）</span>
        <input
          type="number"
          min="0"
          step="0.01"
          disabled={envLocked || !draft.useBackendCost}
          value={draft.costEstimateInputUsdPer1M}
          onChange={(e) => patchNumber('costEstimateInputUsdPer1M', e.target.value)}
        />
      </label>
      <label>
        <span>估算输出（USD / 1M）</span>
        <input
          type="number"
          min="0"
          step="0.01"
          disabled={envLocked || !draft.useBackendCost}
          value={draft.costEstimateOutputUsdPer1M}
          onChange={(e) => patchNumber('costEstimateOutputUsdPer1M', e.target.value)}
        />
      </label>

      <p className="muted">
        预览：成本模式扣费 ≈ 上游 USD × {draft.usdCnyRate} × {draft.marginMultiplier}
      </p>

      <button type="submit" className="send-btn" disabled={saving || envLocked}>
        {saving ? '保存中…' : `保存计量公式 ${formulaKey}`}
      </button>
    </form>
  );
}

function FormulaAssignmentSection() {
  const { users, reload, error, setError } = useAdminUsers();
  const [selected, setSelected] = useState<string[]>([]);
  const [formulaFilter, setFormulaFilter] = useState<'all' | BillingFormulaKey>('all');
  const [search, setSearch] = useState('');
  const [assigning, setAssigning] = useState(false);
  const [message, setMessage] = useState<string | null>(null);

  const filteredUsers = users.filter((user) => {
    if (user.role !== 'user') return false;
    const formula = user.billingFormula ?? 'A';
    if (formulaFilter !== 'all' && formula !== formulaFilter) return false;
    if (!search.trim()) return true;
    const q = search.toLowerCase();
    return user.username.toLowerCase().includes(q) || user.displayName.toLowerCase().includes(q);
  });

  const toggleUser = (userId: string) => {
    setSelected((prev) => (
      prev.includes(userId) ? prev.filter((id) => id !== userId) : [...prev, userId]
    ));
  };

  const toggleAll = () => {
    const ids = filteredUsers.map((user) => user.id);
    const allSelected = ids.length > 0 && ids.every((id) => selected.includes(id));
    setSelected((prev) => (
      allSelected ? prev.filter((id) => !ids.includes(id)) : [...new Set([...prev, ...ids])]
    ));
  };

  const handleAssign = async (formula: BillingFormulaKey) => {
    if (!selected.length) return;
    setAssigning(true);
    setMessage(null);
    setError(null);
    try {
      const result = await assignBillingFormula(selected, formula);
      setMessage(`已将 ${result.updated} 位用户分配到计量公式 ${formula}`);
      setSelected([]);
      await reload();
    } catch (err) {
      setError(err instanceof Error ? err.message : '批量分配失败');
    } finally {
      setAssigning(false);
    }
  };

  return (
    <section className="admin-card">
      <h2>批量分配计量公式</h2>
      <p className="muted">勾选用户后分配到公式 A 或 B。未分配用户默认使用公式 A。</p>
      {error && <p className="banner banner-error">{error}</p>}
      {message && <p className="banner banner-info">{message}</p>}
      <div className="billing-toolbar">
        <input
          className="users-search-input"
          placeholder="搜索用户名 / 显示名"
          value={search}
          onChange={(event) => setSearch(event.target.value)}
        />
        <select
          className="billing-filter-select"
          value={formulaFilter}
          onChange={(event) => setFormulaFilter(event.target.value as 'all' | BillingFormulaKey)}
        >
          <option value="all">全部公式</option>
          <option value="A">公式 A</option>
          <option value="B">公式 B</option>
        </select>
        <button type="button" className="ghost-btn" onClick={() => void reload()} disabled={assigning}>
          刷新用户
        </button>
        <button type="button" className="send-btn" disabled={!selected.length || assigning} onClick={() => void handleAssign('A')}>
          分配到 A
        </button>
        <button type="button" className="send-btn" disabled={!selected.length || assigning} onClick={() => void handleAssign('B')}>
          分配到 B
        </button>
      </div>
      <div className="admin-table-wrap">
        <table className="admin-table">
          <thead>
            <tr>
              <th>
                <input
                  type="checkbox"
                  checked={filteredUsers.length > 0 && filteredUsers.every((user) => selected.includes(user.id))}
                  onChange={toggleAll}
                />
              </th>
              <th>用户</th>
              <th>当前公式</th>
              <th>余额</th>
            </tr>
          </thead>
          <tbody>
            {filteredUsers.map((user) => (
              <tr key={user.id}>
                <td>
                  <input
                    type="checkbox"
                    checked={selected.includes(user.id)}
                    onChange={() => toggleUser(user.id)}
                  />
                </td>
                <td>
                  <span>{user.displayName}</span>
                  <span className="muted"> @{user.username}</span>
                </td>
                <td><strong>{user.billingFormula ?? 'A'}</strong></td>
                <td className="billing-num">¥{formatYuan(user.balanceCents)}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      {filteredUsers.length === 0 ? <p className="muted billing-empty">没有匹配的用户</p> : null}
    </section>
  );
}

function FormulaTab() {
  const [activeFormula, setActiveFormula] = useState<BillingFormulaKey>('A');
  const [drafts, setDrafts] = useState<Record<BillingFormulaKey, BillingAdminConfig>>({
    A: DEFAULT_BILLING_FORMULA,
    B: DEFAULT_BILLING_FORMULA,
  });
  const [meta, setMeta] = useState<Record<BillingFormulaKey, { source: string; updatedAt: number | null }>>({
    A: { source: 'default', updatedAt: null },
    B: { source: 'default', updatedAt: null },
  });
  const [formulaText, setFormulaText] = useState('');
  const [envLocked, setEnvLocked] = useState(false);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [message, setMessage] = useState<string | null>(null);

  const load = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const result = await getBillingConfig('A');
      setDrafts({
        A: result.formulas?.A ?? result.config,
        B: result.formulas?.B ?? result.config,
      });
      setMeta({
        A: {
          source: result.formulaMeta?.A?.source ?? result.source ?? 'default',
          updatedAt: result.formulaMeta?.A?.updatedAt ?? result.updatedAt ?? null,
        },
        B: {
          source: result.formulaMeta?.B?.source ?? result.source ?? 'default',
          updatedAt: result.formulaMeta?.B?.updatedAt ?? null,
        },
      });
      setFormulaText(result.formula ?? '');
      setEnvLocked(Boolean(result.envOverrideActive));
    } catch (err) {
      setError(err instanceof Error ? err.message : '加载计量公式失败');
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    void load();
  }, [load]);

  const handleSave = async (e: React.FormEvent) => {
    e.preventDefault();
    const draft = drafts[activeFormula];
    if (envLocked) {
      setError('当前环境已锁定为仅读 env（H5_BILLING_CONFIG_SOURCE=env），无法保存。');
      return;
    }
    if (draft.marginMultiplier <= 0 || draft.usdCnyRate <= 0) {
      setError('汇率与毛利倍数必须大于 0。');
      return;
    }
    if (
      draft.useBackendCost
      && !window.confirm(
        `确认保存公式 ${activeFormula} 成本模式扣费？\n最终扣费 = 上游成本(USD) × ${draft.usdCnyRate} × ${draft.marginMultiplier}`,
      )
    ) {
      return;
    }
    setSaving(true);
    setError(null);
    setMessage(null);
    try {
      const result = await updateBillingConfig(draft, activeFormula);
      setDrafts({
        A: result.formulas?.A ?? drafts.A,
        B: result.formulas?.B ?? drafts.B,
      });
      setMeta({
        A: {
          source: result.formulaMeta?.A?.source ?? result.source ?? 'admin-db',
          updatedAt: result.formulaMeta?.A?.updatedAt ?? result.updatedAt ?? null,
        },
        B: {
          source: result.formulaMeta?.B?.source ?? result.source ?? 'admin-db',
          updatedAt: result.formulaMeta?.B?.updatedAt ?? result.updatedAt ?? null,
        },
      });
      setFormulaText(result.formula ?? '');
      setEnvLocked(Boolean(result.envOverrideActive));
      setMessage(`计量公式 ${activeFormula} 已保存。Portal 扣费会在数秒内读取新配置，无需重启。`);
    } catch (err) {
      setError(err instanceof Error ? err.message : '保存失败');
    } finally {
      setSaving(false);
    }
  };

  return (
    <>
      <section className="admin-card">
        <h2>计量公式</h2>
        <p className="muted">
          支持公式 A / B 两套独立配置。用户默认走公式 A，可在下方批量分配到 B。
        </p>
        {formulaText ? <p className="muted">{formulaText}</p> : null}
        <div className="admin-tabs" role="tablist">
          {FORMULA_TABS.map((key) => (
            <button
              key={key}
              type="button"
              role="tab"
              aria-selected={activeFormula === key}
              className={`admin-tab${activeFormula === key ? ' active' : ''}`}
              onClick={() => setActiveFormula(key)}
            >
              公式 {key}
            </button>
          ))}
        </div>
        {loading ? <p className="muted">加载中…</p> : null}
        {error && <p className="banner banner-error">{error}</p>}
        {message && <p className="banner banner-info">{message}</p>}
        {!loading ? (
          <FormulaConfigForm
            formulaKey={activeFormula}
            draft={drafts[activeFormula]}
            source={meta[activeFormula].source}
            updatedAt={meta[activeFormula].updatedAt}
            envLocked={envLocked}
            saving={saving}
            onDraftChange={(next) => setDrafts((prev) => ({ ...prev, [activeFormula]: next }))}
            onSave={handleSave}
          />
        ) : null}
      </section>
      <FormulaAssignmentSection />
    </>
  );
}

const PAGE_SIZE = 20;

function RechargeTab() {
  const { users, reload, error, setError } = useAdminUsers();
  const [message, setMessage] = useState<string | null>(null);
  const [recharge, setRecharge] = useState({ userId: '', amountYuan: '10', note: '' });
  const [submitting, setSubmitting] = useState(false);

  const handleRecharge = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!recharge.userId) return;
    setMessage(null);
    setError(null);
    setSubmitting(true);
    try {
      const amountCents = Math.round(Number(recharge.amountYuan) * 100);
      await rechargeUser(recharge.userId, amountCents, recharge.note || undefined);
      setMessage('充值成功');
      setRecharge((s) => ({ ...s, userId: '', note: '' }));
      await reload();
    } catch (err) {
      setError(err instanceof Error ? err.message : '充值失败');
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <section className="admin-card">
      <h2>充值</h2>
      {error && <p className="banner banner-error">{error}</p>}
      {message && <p className="banner banner-info">{message}</p>}
      <form className="admin-form" onSubmit={handleRecharge}>
        <UserCombobox
          users={users.filter((u) => u.role === 'user')}
          value={recharge.userId}
          onChange={(id) => setRecharge((s) => ({ ...s, userId: id }))}
        />
        <input placeholder="金额（元）" type="number" min="0.01" step="0.01" value={recharge.amountYuan}
          onChange={(e) => setRecharge((s) => ({ ...s, amountYuan: e.target.value }))} />
        <input placeholder="备注（可选）" value={recharge.note}
          onChange={(e) => setRecharge((s) => ({ ...s, note: e.target.value }))} />
        <button type="submit" className="send-btn" disabled={!recharge.userId || submitting}>
          {submitting ? '处理中…' : '充值'}
        </button>
      </form>
    </section>
  );
}

function UsageRecordsTable({
  result,
  onPage,
}: {
  result: PagedResult<UsageRecord>;
  onPage: (page: number) => void;
}) {
  const formatBillingSource = (row: UsageRecord) => {
    if (row.billingSource === 'subscription') return '套餐额度';
    return `¥${formatYuan(row.costCents)}`;
  };

  return (
    <>
      <div className="admin-table-wrap">
        <table className="admin-table">
          <thead>
            <tr>
              <th>时间</th>
              <th>用户</th>
              <th style={{ textAlign: 'right' }}>输入 Token</th>
              <th style={{ textAlign: 'right' }}>输出 Token</th>
              <th style={{ textAlign: 'right' }}>扣费</th>
              <th style={{ textAlign: 'right' }}>余额后</th>
            </tr>
          </thead>
          <tbody>
            {result.items.map((row) => (
              <tr key={row.id}>
                <td className="billing-time">{formatTime(row.createdAt)}</td>
                <td>
                  <span>{row.displayName || row.username}</span>
                  <span className="muted"> @{row.username}</span>
                </td>
                <td className="billing-num">{row.inputTokens.toLocaleString()}</td>
                <td className="billing-num">{row.outputTokens.toLocaleString()}</td>
                <td className="billing-num">{formatBillingSource(row)}</td>
                <td className="billing-num">
                  {row.billingSource === 'subscription' ? '—' : `¥${formatYuan(row.balanceAfterCents)}`}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <Pagination
        page={result.page}
        totalPages={result.totalPages}
        total={result.total}
        pageSize={result.pageSize}
        onChange={onPage}
      />
    </>
  );
}

function UsageTotalsGrid({ totals }: { totals: UsageTotals }) {
  const totalTokens = totals.inputTokens + totals.outputTokens;
  return (
    <div className="admin-stat-grid usage-summary-grid">
      <div className="admin-stat-card">
        <div className="admin-stat-label">请求次数</div>
        <div className="admin-stat-value">{totals.count.toLocaleString()}</div>
      </div>
      <div className="admin-stat-card">
        <div className="admin-stat-label">Token 总量</div>
        <div className="admin-stat-value">{totalTokens.toLocaleString()}</div>
        <div className="muted usage-summary-sub">
          入 {totals.inputTokens.toLocaleString()} / 出 {totals.outputTokens.toLocaleString()}
        </div>
      </div>
      <div className="admin-stat-card">
        <div className="admin-stat-label">消费金额</div>
        <div className="admin-stat-value">¥{formatYuan(totals.costCents)}</div>
      </div>
    </div>
  );
}

function UsageSummaryPanel({
  summary,
  rangeLabel,
  allTimeLabel = '累计（不限区间）',
  loading,
}: {
  summary: UsageSummaryResult | null;
  rangeLabel: string;
  allTimeLabel?: string;
  loading?: boolean;
}) {
  if (loading && !summary) {
    return <p className="muted usage-summary-loading">汇总加载中…</p>;
  }
  if (!summary) return null;

  return (
    <div className="usage-summary-panel">
      {summary.range && (
        <section className="usage-summary-block">
          <h4 className="usage-summary-title">{rangeLabel}</h4>
          <UsageTotalsGrid totals={summary.range} />
        </section>
      )}
      <section className="usage-summary-block">
        <h4 className="usage-summary-title">{allTimeLabel}</h4>
        <UsageTotalsGrid totals={summary.allTime} />
      </section>
    </div>
  );
}

function UsageChartPanel({
  stats,
  chartMetrics,
  chartType,
  onMetricsChange,
  onChartTypeChange,
  title = '用量趋势',
  hint,
}: {
  stats: UsageStatsResult;
  chartMetrics: UsageChartMetric[];
  chartType: UsageChartType;
  onMetricsChange: (metrics: UsageChartMetric[]) => void;
  onChartTypeChange: (type: UsageChartType) => void;
  title?: string;
  hint?: string;
}) {
  return (
    <div className="usage-chart-panel">
      <div className="usage-chart-head">
        <div>
          <h3>{title}</h3>
          {hint && <p className="muted usage-chart-hint">{hint}</p>}
        </div>
        <div className="usage-chart-controls">
          <div className="usage-metric-checks" role="group" aria-label="图表指标">
            {METRIC_OPTIONS.map(({ key, label }) => {
              const checked = chartMetrics.includes(key);
              const color = METRIC_CONFIG[key].color;
              return (
                <label key={key} className={`usage-metric-check${checked ? ' checked' : ''}`}>
                  <input
                    type="checkbox"
                    checked={checked}
                    onChange={() => onMetricsChange(toggleChartMetric(chartMetrics, key))}
                  />
                  <span className="usage-metric-check-dot" style={{ background: color }} />
                  {label}
                </label>
              );
            })}
          </div>
          <div className="usage-chart-type-toggle" role="group" aria-label="图表类型">
            <button
              type="button"
              className={`usage-chart-type-btn${chartType === 'bar' ? ' active' : ''}`}
              onClick={() => onChartTypeChange('bar')}
            >
              柱状图
            </button>
            <button
              type="button"
              className={`usage-chart-type-btn${chartType === 'line' ? ' active' : ''}`}
              onClick={() => onChartTypeChange('line')}
            >
              曲线图
            </button>
          </div>
        </div>
      </div>
      <UsageTrendChart
        buckets={stats.buckets}
        startAt={stats.startAt}
        endAt={stats.endAt}
        metrics={chartMetrics}
        chartType={chartType}
      />
    </div>
  );
}

type UsageView = 'overview' | 'query';

function UsageOverviewPanel() {
  const [result, setResult] = useState<PagedResult<UsageRecord> | null>(null);
  const [stats, setStats] = useState<UsageStatsResult | null>(null);
  const [summary, setSummary] = useState<UsageSummaryResult | null>(null);
  const [loadingTable, setLoadingTable] = useState(false);
  const [loadingChart, setLoadingChart] = useState(false);
  const [loadingSummary, setLoadingSummary] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [startDate, setStartDate] = useState('');
  const [endDate, setEndDate] = useState('');
  const [chartMetrics, setChartMetrics] = useState<UsageChartMetric[]>(DEFAULT_CHART_METRICS);
  const [chartType, setChartType] = useState<UsageChartType>('bar');

  const hasDateFilter = Boolean(startDate && endDate && startDate <= endDate);

  const loadTable = useCallback(async (page: number, start: string, end: string) => {
    if (start && end && start > end) {
      setError('请选择有效的时间范围');
      return;
    }
    setLoadingTable(true);
    setError(null);
    try {
      const params: { page: number; pageSize: number; startAt?: number; endAt?: number } = {
        page,
        pageSize: PAGE_SIZE,
      };
      if (start && end) {
        const range = dateRangeToUnix(start, end);
        params.startAt = range.startAt;
        params.endAt = range.endAt;
      }
      const data = await listAdminUsage(params);
      setResult(data);
    } catch (err) {
      setError(err instanceof Error ? err.message : '加载失败');
    } finally {
      setLoadingTable(false);
    }
  }, []);

  const loadChart = useCallback(async (start: string, end: string) => {
    if (start && end && start > end) return;
    setLoadingChart(true);
    setError(null);
    try {
      const chartRange = start && end
        ? { startDate: start, endDate: end }
        : presetDateRange(30);
      const { startAt, endAt } = dateRangeToUnix(chartRange.startDate, chartRange.endDate);
      const statsData = await getAdminUsageStats({ startAt, endAt });
      setStats(statsData);
    } catch (err) {
      setError(err instanceof Error ? err.message : '图表加载失败');
    } finally {
      setLoadingChart(false);
    }
  }, []);

  const loadSummary = useCallback(async (start: string, end: string) => {
    if (start && end && start > end) return;
    setLoadingSummary(true);
    setError(null);
    try {
      const data = start && end
        ? await getAdminUsageSummary(dateRangeToUnix(start, end))
        : await getAdminUsageSummary();
      setSummary(data);
    } catch (err) {
      setError(err instanceof Error ? err.message : '汇总加载失败');
    } finally {
      setLoadingSummary(false);
    }
  }, []);

  useEffect(() => {
    void loadTable(1, startDate, endDate);
  }, [startDate, endDate, loadTable]);

  useEffect(() => {
    void loadChart(startDate, endDate);
  }, [startDate, endDate, loadChart]);

  useEffect(() => {
    void loadSummary(startDate, endDate);
  }, [startDate, endDate, loadSummary]);

  const applyPreset = (days: number) => {
    const range = presetDateRange(days);
    setStartDate(range.startDate);
    setEndDate(range.endDate);
  };

  const clearDateFilter = () => {
    setStartDate('');
    setEndDate('');
  };

  const handlePage = (page: number) => void loadTable(page, startDate, endDate);

  const chartHint = hasDateFilter
    ? `${startDate} 至 ${endDate} 全平台用量（列表与图表同步筛选）`
    : '近 30 天全平台用量（列表展示全部记录；设置日期后列表与图表同步筛选）';

  const rangeSummaryLabel = hasDateFilter
    ? `区间汇总（${startDate} 至 ${endDate}）`
    : '';

  return (
    <>
      {error && <p className="banner banner-error">{error}</p>}
      <div className="usage-overview-filter">
        <span className="muted usage-overview-chart-label">日期区间</span>
        <div className="usage-date-range">
          <input
            type="date"
            className="billing-filter-select usage-date-input"
            value={startDate}
            onChange={(e) => setStartDate(e.target.value)}
          />
          <span className="muted usage-date-sep">至</span>
          <input
            type="date"
            className="billing-filter-select usage-date-input"
            value={endDate}
            onChange={(e) => setEndDate(e.target.value)}
          />
        </div>
        <div className="usage-preset-btns">
          <button type="button" className="admin-btn-secondary usage-preset-btn" onClick={() => applyPreset(7)}>近7天</button>
          <button type="button" className="admin-btn-secondary usage-preset-btn" onClick={() => applyPreset(30)}>近30天</button>
          <button type="button" className="admin-btn-secondary usage-preset-btn" onClick={() => applyPreset(90)}>近90天</button>
          <button
            type="button"
            className={`admin-btn-secondary usage-preset-btn${!hasDateFilter ? ' active' : ''}`}
            onClick={clearDateFilter}
          >
            全部
          </button>
        </div>
      </div>
      <UsageSummaryPanel
        summary={summary}
        rangeLabel={rangeSummaryLabel}
        allTimeLabel="累计汇总（不限区间 · 全平台）"
        loading={loadingSummary}
      />
      {loadingChart && !stats && <p className="muted">图表加载中…</p>}
      {!loadingChart && stats && (
        <UsageChartPanel
          stats={stats}
          chartMetrics={chartMetrics}
          chartType={chartType}
          onMetricsChange={setChartMetrics}
          onChartTypeChange={setChartType}
          title="用量统计"
          hint={chartHint}
        />
      )}
      {loadingTable && !result && <p className="muted">加载中…</p>}
      {!loadingTable && result && (
        result.items.length === 0 ? (
          <p className="muted billing-empty">暂无记录</p>
        ) : (
          <UsageRecordsTable result={result} onPage={handlePage} />
        )
      )}
    </>
  );
}

function UsageQueryPanel() {
  const { users } = useAdminUsers();
  const defaultRange = presetDateRange(30);
  const [result, setResult] = useState<PagedResult<UsageRecord> | null>(null);
  const [stats, setStats] = useState<UsageStatsResult | null>(null);
  const [summary, setSummary] = useState<UsageSummaryResult | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [userId, setUserId] = useState('');
  const [startDate, setStartDate] = useState(defaultRange.startDate);
  const [endDate, setEndDate] = useState(defaultRange.endDate);
  const [chartMetrics, setChartMetrics] = useState<UsageChartMetric[]>(DEFAULT_CHART_METRICS);
  const [chartType, setChartType] = useState<UsageChartType>('bar');

  const hasDateFilter = Boolean(startDate && endDate && startDate <= endDate);

  const load = useCallback(async (p: number, uid: string, start: string, end: string, withChart: boolean) => {
    if (!uid) return;
    if (start && end && start > end) {
      setError('请选择有效的时间范围');
      return;
    }
    if ((start && !end) || (!start && end)) {
      setError('请完整选择起止日期');
      return;
    }
    const filtered = Boolean(start && end);
    setLoading(true);
    setError(null);
    try {
      const listParams: { userId: string; page: number; pageSize: number; startAt?: number; endAt?: number } = {
        userId: uid,
        page: p,
        pageSize: PAGE_SIZE,
      };
      let statsPromise: Promise<UsageStatsResult | null> = Promise.resolve(null);
      let summaryPromise: Promise<UsageSummaryResult | null> = Promise.resolve(null);

      if (filtered) {
        const { startAt, endAt } = dateRangeToUnix(start, end);
        listParams.startAt = startAt;
        listParams.endAt = endAt;
        if (withChart) {
          statsPromise = getAdminUsageStats({ userId: uid, startAt, endAt });
          summaryPromise = getAdminUsageSummary({ userId: uid, startAt, endAt });
        }
      } else if (withChart) {
        const endAt = Math.floor(Date.now() / 1000);
        statsPromise = getAdminUsageStats({ userId: uid, startAt: 1, endAt });
        summaryPromise = getAdminUsageSummary({ userId: uid });
      }

      const [data, statsData, summaryData] = await Promise.all([
        listAdminUsage(listParams),
        statsPromise,
        summaryPromise,
      ]);
      setResult(data);
      if (statsData) setStats(statsData);
      if (summaryData) setSummary(summaryData);
    } catch (err) {
      setError(err instanceof Error ? err.message : '加载失败');
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    if (!userId) {
      setResult(null);
      setStats(null);
      setSummary(null);
      setError(null);
      return;
    }
    void load(1, userId, startDate, endDate, true);
  }, [userId, startDate, endDate, load]);

  const applyPreset = (days: number) => {
    const range = presetDateRange(days);
    setStartDate(range.startDate);
    setEndDate(range.endDate);
  };

  const clearDateFilter = () => {
    setStartDate('');
    setEndDate('');
  };

  const handlePage = (p: number) => void load(p, userId, startDate, endDate, false);

  const selectedUser = users.find((u) => u.id === userId);
  const chartHint = hasDateFilter
    ? `${startDate} 至 ${endDate}${selectedUser ? ` · ${selectedUser.displayName}` : ''}`
    : `全部日期${selectedUser ? ` · ${selectedUser.displayName}` : ''}`;

  const rangeSummaryLabel = hasDateFilter
    ? `区间汇总（${startDate} 至 ${endDate}${selectedUser ? ` · ${selectedUser.displayName}` : ''}）`
    : '';

  const allTimeSummaryLabel = selectedUser
    ? `累计汇总（${selectedUser.displayName} · 全部日期）`
    : '累计汇总（全部日期）';

  return (
    <>
      <div className="billing-toolbar usage-toolbar usage-query-toolbar">
        <UserCombobox
          users={users}
          value={userId}
          onChange={setUserId}
          placeholder="选择用户"
        />
        <div className="usage-date-range">
          <input
            type="date"
            className="billing-filter-select usage-date-input"
            value={startDate}
            onChange={(e) => setStartDate(e.target.value)}
            disabled={!userId}
          />
          <span className="muted usage-date-sep">至</span>
          <input
            type="date"
            className="billing-filter-select usage-date-input"
            value={endDate}
            onChange={(e) => setEndDate(e.target.value)}
            disabled={!userId}
          />
        </div>
        <div className="usage-preset-btns">
          <button type="button" className="admin-btn-secondary usage-preset-btn" disabled={!userId} onClick={() => applyPreset(7)}>近7天</button>
          <button type="button" className="admin-btn-secondary usage-preset-btn" disabled={!userId} onClick={() => applyPreset(30)}>近30天</button>
          <button type="button" className="admin-btn-secondary usage-preset-btn" disabled={!userId} onClick={() => applyPreset(90)}>近90天</button>
          <button
            type="button"
            className={`admin-btn-secondary usage-preset-btn${userId && !hasDateFilter ? ' active' : ''}`}
            disabled={!userId}
            onClick={clearDateFilter}
          >
            全部
          </button>
        </div>
      </div>
      {error && <p className="banner banner-error">{error}</p>}
      {!userId && !loading && (
        <p className="muted billing-empty">请选择用户，将自动加载用量与趋势图</p>
      )}
      {userId && loading && !result && !stats && <p className="muted">加载中…</p>}
      {userId && selectedUser && (
        <div className="usage-user-balance-bar">
          <span className="usage-user-balance-name">
            {selectedUser.displayName}
            <span className="muted"> @{selectedUser.username}</span>
          </span>
          <span className="usage-user-balance-label muted">当前余额</span>
          <span className="usage-user-balance-value">¥{formatYuan(selectedUser.balanceCents)}</span>
        </div>
      )}
      {userId && (
        <UsageSummaryPanel
          summary={summary}
          rangeLabel={rangeSummaryLabel}
          allTimeLabel={allTimeSummaryLabel}
          loading={loading && !summary}
        />
      )}
      {userId && !loading && stats && (
        <UsageChartPanel
          stats={stats}
          chartMetrics={chartMetrics}
          chartType={chartType}
          onMetricsChange={setChartMetrics}
          onChartTypeChange={setChartType}
          title="用户用量趋势"
          hint={chartHint}
        />
      )}
      {userId && !loading && result && (
        result.items.length === 0 ? (
          <p className="muted billing-empty">{hasDateFilter ? '该时间范围内暂无记录' : '该用户暂无用量记录'}</p>
        ) : (
          <UsageRecordsTable result={result} onPage={handlePage} />
        )
      )}
    </>
  );
}

function UsageTab() {
  const location = useLocation();
  const navigate = useNavigate();
  const view: UsageView = location.pathname.endsWith('/query') ? 'query' : 'overview';

  const setView = (next: UsageView) => {
    navigate(next === 'query' ? '/billing/usage/query' : '/billing/usage');
  };

  return (
    <section className="admin-card">
      <div className="admin-card-head usage-tab-head">
        <h2>用量记录</h2>
        <div className="usage-view-switch" role="tablist" aria-label="用量记录视图">
          <button
            type="button"
            role="tab"
            aria-selected={view === 'overview'}
            className={`usage-view-btn${view === 'overview' ? ' active' : ''}`}
            onClick={() => setView('overview')}
          >
            全部记录
          </button>
          <button
            type="button"
            role="tab"
            aria-selected={view === 'query'}
            className={`usage-view-btn${view === 'query' ? ' active' : ''}`}
            onClick={() => setView('query')}
          >
            用户分析
          </button>
        </div>
      </div>
      <div className="usage-tab-body">
        {view === 'overview' ? <UsageOverviewPanel /> : <UsageQueryPanel />}
      </div>
    </section>
  );
}

function LedgerTab() {
  const { users } = useAdminUsers();
  const [result, setResult] = useState<PagedResult<LedgerEntry> | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [filterUserId, setFilterUserId] = useState('');
  const [pendingUserId, setPendingUserId] = useState('');

  const load = useCallback(async (p: number, userId: string) => {
    setLoading(true);
    setError(null);
    try {
      const data = await listAdminLedger({ userId: userId || undefined, page: p, pageSize: PAGE_SIZE });
      setResult(data);
      setFilterUserId(userId);
    } catch (err) {
      setError(err instanceof Error ? err.message : '加载失败');
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => { void load(1, ''); }, [load]);

  const handleQuery = () => void load(1, pendingUserId);
  const handlePage = (p: number) => void load(p, filterUserId);

  const TYPE_LABEL: Record<string, string> = { recharge: '充值', deduct: '扣费', refund: '退款', adjust: '调整' };

  return (
    <section className="admin-card">
      <div className="admin-card-head">
        <h2>资金流水</h2>
        <div className="billing-toolbar">
          <UserCombobox
            users={users}
            value={pendingUserId}
            onChange={setPendingUserId}
            placeholder="全部用户"
          />
          <button type="button" className="send-btn billing-query-btn" onClick={handleQuery} disabled={loading}>
            查询
          </button>
        </div>
      </div>
      {error && <p className="banner banner-error">{error}</p>}
      {!result && !loading && (
        <p className="muted billing-empty">选择用户后点击查询</p>
      )}
      {loading && <p className="muted">加载中…</p>}
      {!loading && result && (
        result.items.length === 0 ? (
          <p className="muted billing-empty">暂无记录</p>
        ) : (
          <>
            <div className="admin-table-wrap">
              <table className="admin-table">
                <thead>
                  <tr>
                    <th>时间</th>
                    <th>用户</th>
                    <th>类型</th>
                    <th style={{ textAlign: 'right' }}>金额</th>
                    <th>备注</th>
                  </tr>
                </thead>
                <tbody>
                  {result.items.map((row) => (
                    <tr key={row.id}>
                      <td className="billing-time">{formatTime(row.createdAt)}</td>
                      <td>
                        <span>{row.displayName || row.username}</span>
                        <span className="muted"> @{row.username}</span>
                      </td>
                      <td><span className={`ledger-type-tag ledger-type-${row.type}`}>{TYPE_LABEL[row.type] ?? row.type}</span></td>
                      <td className={`billing-num ${row.amountCents < 0 ? 'text-error' : 'text-income'}`}>
                        {row.amountCents >= 0 ? '+' : ''}¥{formatYuan(Math.abs(row.amountCents))}
                      </td>
                      <td className="billing-note">{row.note ?? '—'}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
            <Pagination page={result.page} totalPages={result.totalPages} total={result.total}
              pageSize={result.pageSize} onChange={handlePage} />
          </>
        )
      )}
    </section>
  );
}

const PLAN_TIER_LABEL: Record<string, string> = {
  basic: '基础',
  standard: '标准',
  premium: '旗舰',
};

const EMPTY_PLAN_FORM = {
  planType: '',
  name: '',
  priceCents: '0',
  periodDays: '30',
  periodTokens: '0',
  periodImages: '0',
  modelTier: 'basic',
  overageRate: '1.00',
  sortOrder: '0',
  isActive: true,
  description: '',
};

type PlanForm = typeof EMPTY_PLAN_FORM;

function planToForm(p: PlanDefinition): PlanForm {
  return {
    planType: p.planType,
    name: p.name,
    priceCents: String(p.priceCents),
    periodDays: String(p.periodDays),
    periodTokens: String(p.periodTokens),
    periodImages: String(p.periodImages),
    modelTier: p.modelTier,
    overageRate: String(p.overageRate),
    sortOrder: String(p.sortOrder),
    isActive: p.isActive,
    description: p.description ?? '',
  };
}

function PlanFormModal({
  initial,
  onSave,
  onClose,
}: {
  initial: PlanForm;
  onSave: (form: PlanForm) => Promise<void>;
  onClose: () => void;
}) {
  const [form, setForm] = useState<PlanForm>(initial);
  const [saving, setSaving] = useState(false);
  const [err, setErr] = useState<string | null>(null);
  const isNew = !initial.planType;

  const set = (key: keyof PlanForm, val: string | boolean) =>
    setForm((s) => ({ ...s, [key]: val }));

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setSaving(true);
    setErr(null);
    try {
      await onSave(form);
    } catch (ex) {
      setErr(ex instanceof Error ? ex.message : '保存失败');
    } finally {
      setSaving(false);
    }
  };

  return (
    <div className="modal-backdrop" onClick={(e) => e.target === e.currentTarget && onClose()}>
      <div className="modal-box" style={{ maxWidth: 520 }}>
        <div className="modal-head">
          <h3>{isNew ? '新建套餐' : `编辑套餐 · ${initial.name}`}</h3>
          <button type="button" className="modal-close" onClick={onClose}>×</button>
        </div>
        {err && <p className="banner banner-error">{err}</p>}
        <form className="admin-form plan-form" onSubmit={handleSubmit}>
          {isNew && (
            <label className="plan-form-row">
              <span>套餐标识 <span className="muted">(plan_type)</span></span>
              <input
                placeholder="如 basic / pro_plus"
                value={form.planType}
                onChange={(e) => set('planType', e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, ''))}
                required
              />
            </label>
          )}
          <label className="plan-form-row">
            <span>显示名称</span>
            <input placeholder="如 专业版" value={form.name} onChange={(e) => set('name', e.target.value)} required />
          </label>
          <label className="plan-form-row">
            <span>月价格（分）</span>
            <input type="number" min="0" step="1" value={form.priceCents}
              onChange={(e) => set('priceCents', e.target.value)} />
            <span className="plan-form-hint">¥{(Number(form.priceCents) / 100).toFixed(2)} / 月</span>
          </label>
          <label className="plan-form-row">
            <span>有效天数</span>
            <input type="number" min="1" step="1" value={form.periodDays}
              onChange={(e) => set('periodDays', e.target.value)} />
          </label>
          <label className="plan-form-row">
            <span>Token 配额</span>
            <input type="number" min="0" step="10000" value={form.periodTokens}
              onChange={(e) => set('periodTokens', e.target.value)} />
            <span className="plan-form-hint">
              {Number(form.periodTokens) === 0 ? '不限' : `${(Number(form.periodTokens) / 10000).toFixed(0)} 万 Token`}
            </span>
          </label>
          <label className="plan-form-row">
            <span>图片配额（张）</span>
            <input type="number" min="0" step="1" value={form.periodImages}
              onChange={(e) => set('periodImages', e.target.value)} />
            <span className="plan-form-hint">
              {Number(form.periodImages) === 0 ? '不限' : `${form.periodImages} 张/周期`}
            </span>
          </label>
          <label className="plan-form-row">
            <span>模型层级</span>
            <select className="admin-select" value={form.modelTier}
              onChange={(e) => set('modelTier', e.target.value)}>
              <option value="basic">基础（basic）</option>
              <option value="standard">标准（standard）</option>
              <option value="premium">旗舰（premium）</option>
            </select>
          </label>
          <label className="plan-form-row">
            <span>超量费率</span>
            <input type="number" min="0" max="2" step="0.01" value={form.overageRate}
              onChange={(e) => set('overageRate', e.target.value)} />
            <span className="plan-form-hint">配额耗尽后的费用倍率（1.0 = 正常价格）</span>
          </label>
          <label className="plan-form-row">
            <span>排序权重</span>
            <input type="number" step="1" value={form.sortOrder}
              onChange={(e) => set('sortOrder', e.target.value)} />
          </label>
          <label className="plan-form-row">
            <span>简介（可选）</span>
            <input placeholder="套餐说明文字" value={form.description}
              onChange={(e) => set('description', e.target.value)} />
          </label>
          <label className="plan-form-row plan-form-check">
            <input type="checkbox" checked={form.isActive}
              onChange={(e) => set('isActive', e.target.checked)} />
            <span>对用户可见（上架）</span>
          </label>
          <div className="plan-form-actions">
            <button type="button" className="admin-btn-secondary" onClick={onClose}>取消</button>
            <button type="submit" className="send-btn" disabled={saving}>
              {saving ? '保存中…' : '保存套餐'}
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

function PlanCatalogSection({
  plans,
  onPlansChange,
}: {
  plans: PlanDefinition[];
  onPlansChange: () => void;
}) {
  const [editing, setEditing] = useState<PlanForm | null>(null);
  const [err, setErr] = useState<string | null>(null);
  const [msg, setMsg] = useState<string | null>(null);
  const [deleting, setDeleting] = useState<string | null>(null);
  const [syncingProd, setSyncingProd] = useState(false);

  const openNew = () => setEditing({ ...EMPTY_PLAN_FORM });
  const openEdit = (p: PlanDefinition) => setEditing(planToForm(p));
  const closeModal = () => setEditing(null);

  const handleSave = async (form: PlanForm) => {
    const data = {
      name: form.name,
      priceCents: Number(form.priceCents),
      periodDays: Number(form.periodDays),
      periodTokens: Number(form.periodTokens),
      periodImages: Number(form.periodImages),
      modelTier: form.modelTier,
      overageRate: Number(form.overageRate),
      sortOrder: Number(form.sortOrder),
      isActive: form.isActive,
      description: form.description || null,
    };
    const isNew = !editing?.planType || editing.planType !== form.planType;
    if (isNew) {
      const result = await createSubscriptionPlan(form.planType, data);
      setMsg(
        result.sync?.ok === false
          ? `已创建套餐「${form.name}」，但生产后台同步失败：${result.sync.message}`
          : result.sync?.message
            ? `已创建套餐「${form.name}」，${result.sync.message}`
            : `已创建套餐「${form.name}」`,
      );
    } else {
      const result = await updateSubscriptionPlan(form.planType, data);
      setMsg(
        result.sync?.ok === false
          ? `已更新套餐「${form.name}」，但生产后台同步失败：${result.sync.message}`
          : result.sync?.message
            ? `已更新套餐「${form.name}」，${result.sync.message}`
            : `已更新套餐「${form.name}」`,
      );
    }
    closeModal();
    onPlansChange();
  };

  const handleDelete = async (p: PlanDefinition) => {
    if (!window.confirm(`确认删除套餐「${p.name}」？已购用户不受影响，但新用户无法选择此套餐。`)) return;
    setDeleting(p.planType);
    setErr(null);
    try {
      const result = await deleteSubscriptionPlan(p.planType);
      setMsg(
        result.sync?.ok === false
          ? `已删除套餐「${p.name}」，但生产后台同步失败：${result.sync.message}`
          : result.sync?.message
            ? `已删除套餐「${p.name}」，${result.sync.message}`
            : `已删除套餐「${p.name}」`,
      );
      onPlansChange();
    } catch (ex) {
      setErr(ex instanceof Error ? ex.message : '删除失败');
    } finally {
      setDeleting(null);
    }
  };

  const handleSyncProduction = async () => {
    setSyncingProd(true);
    setErr(null);
    try {
      const result = await syncSubscriptionPlansToProduction();
      if (result.ok) setMsg(result.message);
      else setErr(result.message);
    } catch (ex) {
      setErr(ex instanceof Error ? ex.message : '同步生产后台失败');
    } finally {
      setSyncingProd(false);
    }
  };

  return (
    <section className="admin-card">
      <div className="admin-card-head">
        <h2>套餐目录</h2>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          <button type="button" className="admin-btn-secondary" onClick={handleSyncProduction} disabled={syncingProd}>
            {syncingProd ? '同步中…' : '同步生产后台'}
          </button>
          <button type="button" className="send-btn" onClick={openNew}>+ 新建套餐</button>
        </div>
      </div>
      {err && <p className="banner banner-error">{err}</p>}
      {msg && <p className="banner banner-info">{msg}</p>}
      {plans.length === 0 ? (
        <p className="muted">暂无套餐，点击「新建套餐」添加。</p>
      ) : (
        <div className="admin-table-wrap">
          <table className="admin-table">
            <thead>
              <tr>
                <th>套餐</th>
                <th style={{ textAlign: 'right' }}>价格</th>
                <th style={{ textAlign: 'right' }}>Token 配额</th>
                <th style={{ textAlign: 'right' }}>图片配额</th>
                <th>模型层级</th>
                <th>天数</th>
                <th>超量费率</th>
                <th>状态</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {plans.map((p) => (
                <tr key={p.planType} style={{ opacity: p.isActive ? 1 : 0.5 }}>
                  <td>
                    <strong>{p.name}</strong>
                    <span className="muted"> ({p.planType})</span>
                    {p.description && <div className="plan-desc muted">{p.description}</div>}
                  </td>
                  <td className="billing-num">
                    {p.priceCents === 0 ? '免费' : `¥${formatYuan(p.priceCents)}/月`}
                  </td>
                  <td className="billing-num">
                    {p.periodTokens === 0 ? '不限' : `${(p.periodTokens / 10000).toFixed(0)} 万`}
                  </td>
                  <td className="billing-num">
                    {p.periodImages === 0 ? '不限' : `${p.periodImages} 张`}
                  </td>
                  <td>{PLAN_TIER_LABEL[p.modelTier] ?? p.modelTier}</td>
                  <td>{p.periodDays} 天</td>
                  <td>{p.overageRate === 1 ? '—' : `×${p.overageRate}`}</td>
                  <td>
                    <span className={`ledger-type-tag ledger-type-${p.isActive ? 'active' : 'cancelled'}`}>
                      {p.isActive ? '上架' : '下架'}
                    </span>
                  </td>
                  <td className="plan-actions">
                    <button type="button" className="admin-btn-secondary" onClick={() => openEdit(p)}>编辑</button>
                    {p.planType !== 'free' && (
                      <button type="button" className="admin-btn-danger"
                        disabled={deleting === p.planType}
                        onClick={() => void handleDelete(p)}>
                        {deleting === p.planType ? '删除中…' : '删除'}
                      </button>
                    )}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
      {editing !== null && (
        <PlanFormModal initial={editing} onSave={handleSave} onClose={closeModal} />
      )}
    </section>
  );
}

function SubscriptionsTab() {
  const { users, reload: reloadUsers } = useAdminUsers();
  const [plans, setPlans] = useState<PlanDefinition[]>([]);
  const [result, setResult] = useState<{
    items: AdminSubscription[];
    total: number;
    page: number;
    totalPages: number;
    pageSize: number;
  } | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [message, setMessage] = useState<string | null>(null);
  const [filterUserId, setFilterUserId] = useState('');
  const [pendingUserId, setPendingUserId] = useState('');
  const [filterStatus, setFilterStatus] = useState('active');
  const [grant, setGrant] = useState({ userId: '', planType: '', durationDays: '', note: '' });
  const [submitting, setSubmitting] = useState(false);
  const [cancelling, setCancelling] = useState<string | null>(null);

  const loadPlans = useCallback(async () => {
    try {
      const p = await listSubscriptionPlans();
      setPlans(p);
    } catch { /* ignore */ }
  }, []);

  useEffect(() => { void loadPlans(); }, [loadPlans]);

  const load = useCallback(async (p: number, userId: string, status: string) => {
    setLoading(true);
    setError(null);
    try {
      const data = await listAdminSubscriptions({
        userId: userId || undefined,
        status: status || undefined,
        page: p,
        pageSize: 20,
      });
      setResult(data);
      setFilterUserId(userId);
      setFilterStatus(status);
    } catch (err) {
      setError(err instanceof Error ? err.message : '加载失败');
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => { void load(1, '', 'active'); }, [load]);

  const handleQuery = () => void load(1, pendingUserId, filterStatus);
  const handlePage = (p: number) => void load(p, filterUserId, filterStatus);

  const activePlans = plans.filter((p) => p.isActive && p.priceCents > 0);

  const handleGrant = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!grant.userId || !grant.planType) return;
    setSubmitting(true);
    setError(null);
    setMessage(null);
    try {
      const days = grant.durationDays ? Number(grant.durationDays) : undefined;
      await grantUserSubscription(grant.userId, grant.planType, days, grant.note || undefined);
      const planName = plans.find((p) => p.planType === grant.planType)?.name ?? grant.planType;
      const user = users.find((u) => u.id === grant.userId);
      setMessage(`已为 ${user?.displayName ?? grant.userId} 授予 ${planName} 套餐`);
      setGrant((s) => ({ ...s, userId: '', note: '' }));
      await reloadUsers();
      void load(1, filterUserId, filterStatus);
    } catch (err) {
      setError(err instanceof Error ? err.message : '授予失败');
    } finally {
      setSubmitting(false);
    }
  };

  const handleCancel = async (userId: string, displayName: string) => {
    if (!window.confirm(`确认取消 ${displayName} 的套餐？`)) return;
    setCancelling(userId);
    setError(null);
    setMessage(null);
    try {
      await cancelUserSubscription(userId);
      setMessage(`已取消 ${displayName} 的套餐`);
      void load(1, filterUserId, filterStatus);
    } catch (err) {
      setError(err instanceof Error ? err.message : '取消失败');
    } finally {
      setCancelling(null);
    }
  };

  const STATUS_LABEL: Record<string, string> = { active: '有效', expired: '已到期', cancelled: '已取消' };
  const autoRenewLabel = (row: AdminSubscription) => {
    if (!row.autoRenew) return '未开启';
    if (row.status === 'active') return '已开启';
    if (row.status === 'expired') return '待补扣';
    return '—';
  };

  return (
    <>
      <PlanCatalogSection plans={plans} onPlansChange={loadPlans} />

      {/* Grant subscription */}
      <section className="admin-card">
        <h2>授予套餐</h2>
        {error && <p className="banner banner-error">{error}</p>}
        {message && <p className="banner banner-info">{message}</p>}
        <form className="admin-form" onSubmit={handleGrant}>
          <UserCombobox
            users={users.filter((u) => u.role === 'user')}
            value={grant.userId}
            onChange={(id) => setGrant((s) => ({ ...s, userId: id }))}
          />
          <select
            className="admin-select"
            value={grant.planType}
            onChange={(e) => setGrant((s) => ({ ...s, planType: e.target.value }))}
            required
          >
            <option value="">选择套餐（含所有套餐）</option>
            {plans.map((p) => (
              <option key={p.planType} value={p.planType}>
                {p.name} — {p.priceCents === 0 ? '免费' : `¥${formatYuan(p.priceCents)}/月`}
                {!p.isActive ? ' [下架]' : ''}
              </option>
            ))}
          </select>
          <input
            placeholder="有效天数（留空用套餐默认）"
            type="number"
            min="1"
            value={grant.durationDays}
            onChange={(e) => setGrant((s) => ({ ...s, durationDays: e.target.value }))}
          />
          <input
            placeholder="备注（可选）"
            value={grant.note}
            onChange={(e) => setGrant((s) => ({ ...s, note: e.target.value }))}
          />
          <button type="submit" className="send-btn" disabled={!grant.userId || !grant.planType || submitting}>
            {submitting ? '处理中…' : '授予'}
          </button>
        </form>
      </section>

      {/* Subscription list */}
      <section className="admin-card">
        <div className="admin-card-head">
          <h2>订阅记录</h2>
          <div className="billing-toolbar">
            <UserCombobox
              users={users}
              value={pendingUserId}
              onChange={setPendingUserId}
              placeholder="全部用户"
            />
            <select
              className="admin-select billing-status-select"
              value={filterStatus}
              onChange={(e) => setFilterStatus(e.target.value)}
            >
              <option value="">全部状态</option>
              <option value="active">有效</option>
              <option value="expired">已到期</option>
              <option value="cancelled">已取消</option>
            </select>
            <button
              type="button"
              className="send-btn billing-query-btn"
              onClick={handleQuery}
              disabled={loading}
            >
              查询
            </button>
          </div>
        </div>
        {loading && <p className="muted">加载中…</p>}
        {!loading && result && (
          result.items.length === 0 ? (
            <p className="muted billing-empty">暂无记录</p>
          ) : (
            <>
              <div className="admin-table-wrap">
                <table className="admin-table">
                  <thead>
                    <tr>
                      <th>用户</th>
                      <th>套餐</th>
                      <th>状态</th>
                      <th>自动续费</th>
                      <th style={{ textAlign: 'right' }}>Token 用量</th>
                      <th style={{ textAlign: 'right' }}>图片用量</th>
                      <th>到期时间</th>
                      <th>备注</th>
                      <th></th>
                    </tr>
                  </thead>
                  <tbody>
                    {result.items.map((row) => (
                      <tr key={row.id}>
                        <td>
                          <span>{row.displayName}</span>
                          <span className="muted"> @{row.username}</span>
                        </td>
                        <td><strong>{row.planType}</strong></td>
                        <td>
                          <span className={`ledger-type-tag ledger-type-${row.status}`}>
                            {STATUS_LABEL[row.status] ?? row.status}
                          </span>
                        </td>
                        <td>
                          <span className={row.autoRenew && row.status === 'expired' ? 'text-error' : undefined}>
                            {autoRenewLabel(row)}
                          </span>
                        </td>
                        <td className="billing-num">
                          {row.periodTokensUsed.toLocaleString()}
                          {row.periodTokensLimit > 0 && (
                            <span className="muted"> / {row.periodTokensLimit.toLocaleString()}</span>
                          )}
                        </td>
                        <td className="billing-num">
                          {row.periodImagesUsed}
                          {row.periodImagesLimit > 0 && (
                            <span className="muted"> / {row.periodImagesLimit}</span>
                          )}
                        </td>
                        <td className="billing-time">{formatTime(row.expiresAt)}</td>
                        <td className="billing-note">{row.note ?? '—'}</td>
                        <td>
                          {row.status === 'active' && (
                            <button
                              type="button"
                              className="admin-btn-danger"
                              disabled={cancelling === row.userId}
                              onClick={() => void handleCancel(row.userId, row.displayName)}
                            >
                              {cancelling === row.userId ? '取消中…' : '取消套餐'}
                            </button>
                          )}
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
              <Pagination
                page={result.page}
                totalPages={result.totalPages}
                total={result.total}
                pageSize={result.pageSize}
                onChange={handlePage}
              />
            </>
          )
        )}
      </section>
    </>
  );
}

export function BillingPage() {
  const location = useLocation();
  const navigate = useNavigate();
  const activeTab = tabFromPath(location.pathname);

  return (
    <div className="admin-page">
      <div className="admin-page-head">
        <h2>计费中心</h2>
        <p className="muted">充值、用量、资金流水与计量公式</p>
      </div>
      <div className="admin-tabs" role="tablist">
        {TABS.map((tab) => (
          <button key={tab.key} type="button" role="tab" aria-selected={activeTab === tab.key}
            className={`admin-tab${activeTab === tab.key ? ' active' : ''}`}
            onClick={() => navigate(TAB_PATHS[tab.key])}>
            {tab.label}
          </button>
        ))}
      </div>
      <div className="billing-tab-content">
        {activeTab === 'recharge' && <RechargeTab />}
        {activeTab === 'usage' && <UsageTab />}
        {activeTab === 'ledger' && <LedgerTab />}
        {activeTab === 'subscriptions' && <SubscriptionsTab />}
        {activeTab === 'formula' && <FormulaTab />}
      </div>
    </div>
  );
}
