'use client';

// CPS 优惠券分发与对账。平台:美团(actId+sid,完整对账) / 淘宝(淘口令) / 京东(链接)。
// 淘宝/京东无 API → 只统计点击,对账字段显示 "-"。单页 Tabs:对账统计/群管理/活动管理/订单明细。
import { useCallback, useEffect, useState } from 'react';
import Link from 'next/link';
import type { ColumnsType } from 'antd/es/table';
import {
  Button,
  Card,
  Checkbox,
  Form,
  Input,
  InputNumber,
  Modal,
  Popconfirm,
  Select,
  Space,
  Statistic,
  Table,
  Tabs,
  Tag,
  Typography,
  Upload,
  message,
} from 'antd';
import { api, errMsg } from '@/lib/api';
import { canDo } from '@/lib/auth';
import { formatUtcTime, yuan } from '@/lib/format';
import { usePagedList } from '@/lib/usePagedList';
import type {
  CpsActivity,
  CpsGroup,
  CpsGroupStat,
  CpsOrder,
  CpsReconcileResult,
  CpsReferralLinks,
  CpsStats,
} from '@/lib/types';

const MT_STATUS: Record<string, { text: string; color: string }> = {
  '2': { text: '已付款', color: 'blue' },
  '3': { text: '已完成', color: 'cyan' },
  '4': { text: '已取消', color: 'red' },
  '5': { text: '风控', color: 'orange' },
  '6': { text: '已结算', color: 'green' },
};

const PLATFORM_LABEL: Record<string, string> = { meituan: '美团', taobao: '淘宝', jd: '京东' };
const PLATFORM_COLOR: Record<string, string> = { meituan: 'gold', taobao: 'volcano', jd: 'red' };
const PLATFORM_OPTIONS = [
  { label: '美团', value: 'meituan' },
  { label: '淘宝', value: 'taobao' },
  { label: '京东', value: 'jd' },
];

const fmtRate = (r: string | null) => (r ? `${Number(r) / 100}%` : '-');
const DASH = <span style={{ color: '#bbb' }}>-</span>;
const platformTags = (ps: string[] | undefined) =>
  (ps || []).map((p) => (
    <Tag key={p} color={PLATFORM_COLOR[p]} style={{ marginInlineEnd: 4 }}>
      {PLATFORM_LABEL[p] || p}
    </Tag>
  ));

export default function CpsPage() {
  return (
    <div>
      <h2>CPS 优惠券分发与对账</h2>
      <Typography.Paragraph type="secondary" style={{ marginTop: -8 }}>
        美团(actId + sid,可完整对账下单/佣金) / 淘宝(淘口令) / 京东(链接)。淘宝、京东无开放 API,
        <b>只统计点击</b>,对账字段显示「-」。发群链接都是咱的落地页 /c/xxx。
      </Typography.Paragraph>
      <Tabs
        defaultActiveKey="stats"
        destroyInactiveTabPane
        items={[
          { key: 'stats', label: '对账统计', children: <StatsTab /> },
          { key: 'groups', label: '群管理', children: <GroupsTab /> },
          { key: 'activities', label: '活动管理', children: <ActivitiesTab /> },
          { key: 'orders', label: '订单明细', children: <OrdersTab /> },
        ]}
      />
    </div>
  );
}

// ───────────── 对账统计 ─────────────
function StatsTab() {
  const [days, setDays] = useState(30);
  const [data, setData] = useState<CpsStats | null>(null);
  const [loading, setLoading] = useState(false);
  const [reconciling, setReconciling] = useState(false);
  const canReconcile = canDo(['finance']);

  const load = useCallback(async (d: number) => {
    setLoading(true);
    try {
      const resp = await api.get<CpsStats>('/admin/api/cps/stats', { params: { days: d } });
      setData(resp.data);
    } catch (e) {
      message.error(errMsg(e));
    } finally {
      setLoading(false);
    }
  }, []);

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

  const reconcile = async () => {
    setReconciling(true);
    try {
      const resp = await api.post<CpsReconcileResult>('/admin/api/cps/orders/reconcile', null, {
        params: { days },
      });
      const r = resp.data;
      message.success(`对账完成:拉取 ${r.fetched} 单(新增 ${r.inserted}、更新 ${r.updated})`);
      load(days);
    } catch (e) {
      message.error(errMsg(e));
    } finally {
      setReconciling(false);
    }
  };

  const columns: ColumnsType<CpsGroupStat> = [
    {
      title: '群',
      dataIndex: 'name',
      width: 140,
      ellipsis: true,
      fixed: 'left',
      render: (v: string, r) =>
        r.group_id ? <Link href={`/cps/groups/${r.group_id}`}>{v}</Link> : v,
    },
    { title: '平台', key: 'platforms', width: 130, render: (_, r) => platformTags(r.platforms) },
    { title: '人数', dataIndex: 'member_count', width: 64, render: (v) => v ?? '-' },
    { title: '点击', dataIndex: 'click_pv', width: 64 },
    { title: '独立', dataIndex: 'click_uv', width: 64 },
    {
      title: '复制',
      dataIndex: 'copy_pv',
      width: 64,
      render: (v: number) => (v ? v : DASH),
    },
    {
      title: '有效单',
      dataIndex: 'order_count',
      width: 70,
      render: (v: number | null) => (v == null ? DASH : v),
    },
    {
      title: '取消/风控',
      dataIndex: 'canceled_count',
      width: 80,
      render: (v: number | null) => (v == null ? DASH : v ? <span style={{ color: '#cf1322' }}>{v}</span> : 0),
    },
    {
      title: '点击→下单',
      key: 'rate',
      width: 88,
      render: (_, r) =>
        r.order_count == null ? DASH : r.click_uv ? `${((r.order_count / r.click_uv) * 100).toFixed(0)}%` : '-',
    },
    {
      title: '成交额',
      dataIndex: 'gmv_cents',
      width: 96,
      render: (v: number | null) => (v == null ? DASH : yuan(v)),
    },
    {
      title: '预估佣金',
      dataIndex: 'est_commission_cents',
      width: 100,
      sorter: (a, b) => (a.est_commission_cents || 0) - (b.est_commission_cents || 0),
      render: (v: number | null) => (v == null ? DASH : <b>{yuan(v)}</b>),
    },
    {
      title: '已结算佣金',
      dataIndex: 'settled_commission_cents',
      width: 100,
      render: (v: number | null) => (v == null ? DASH : <span style={{ color: '#3f8600' }}>{yuan(v)}</span>),
    },
  ];

  return (
    <div>
      <Space style={{ marginBottom: 16 }} wrap>
        <span>统计区间</span>
        <Select
          value={days}
          onChange={setDays}
          style={{ width: 120 }}
          options={[
            { value: 7, label: '近 7 天' },
            { value: 30, label: '近 30 天' },
            { value: 90, label: '近 90 天' },
          ]}
        />
        {canReconcile && (
          <Button type="primary" loading={reconciling} onClick={reconcile}>
            刷新对账(拉美团订单)
          </Button>
        )}
        <Typography.Text type="secondary">淘宝/京东无对账,「-」即无法对账;佣金以「已结算」为准</Typography.Text>
      </Space>

      <Space size="large" style={{ marginBottom: 16 }} wrap>
        <Card size="small">
          <Statistic title="有效订单数(美团)" value={data?.total_order_count ?? 0} />
        </Card>
        <Card size="small">
          <Statistic
            title="预估佣金"
            value={(data?.total_est_commission_cents ?? 0) / 100}
            precision={2}
            prefix="¥"
          />
        </Card>
        <Card size="small">
          <Statistic
            title="已结算佣金"
            value={(data?.total_settled_commission_cents ?? 0) / 100}
            precision={2}
            prefix="¥"
            valueStyle={{ color: '#3f8600' }}
          />
        </Card>
      </Space>

      <Table
        rowKey={(r) => r.sid ?? `gid-${r.group_id ?? 'none'}`}
        columns={columns}
        dataSource={data?.groups ?? []}
        loading={loading}
        pagination={false}
        scroll={{ x: 1200 }}
      />
    </div>
  );
}

// ───────────── 群管理 ─────────────
function GroupsTab() {
  const [keyword, setKeyword] = useState('');
  const [applied, setApplied] = useState<Record<string, unknown>>({});
  const { items, total, page, pageSize, loading, onChange, reload } = usePagedList<CpsGroup>(
    '/admin/api/cps/groups',
    applied,
  );
  const canManage = canDo(['operator']);

  const [editing, setEditing] = useState<CpsGroup | null>(null);
  const [createOpen, setCreateOpen] = useState(false);
  const [linkGroup, setLinkGroup] = useState<CpsGroup | null>(null);

  const delGroup = async (g: CpsGroup) => {
    try {
      await api.delete(`/admin/api/cps/groups/${g.id}`);
      message.success('已删除群');
      reload();
    } catch (e) {
      message.error(errMsg(e));
    }
  };

  const columns: ColumnsType<CpsGroup> = [
    { title: 'ID', dataIndex: 'id', width: 60 },
    { title: '群名', dataIndex: 'name', width: 160, ellipsis: true },
    { title: '平台', key: 'platforms', width: 140, render: (_, g) => platformTags(g.platforms) },
    {
      title: 'sid',
      dataIndex: 'sid',
      width: 130,
      render: (v: string | null) => (v ? <Typography.Text copyable>{v}</Typography.Text> : DASH),
    },
    { title: '人数', dataIndex: 'member_count', width: 70, render: (v) => v ?? '-' },
    {
      title: '状态',
      dataIndex: 'status',
      width: 80,
      render: (s: string) => <Tag color={s === 'active' ? 'green' : 'default'}>{s}</Tag>,
    },
    { title: '创建时间', dataIndex: 'created_at', width: 150, render: (v: string) => formatUtcTime(v) },
    {
      title: '操作',
      key: 'op',
      fixed: 'right',
      width: 200,
      render: (_, g) => (
        <Space onClick={(e) => e.stopPropagation()}>
          {canManage && <a onClick={() => setLinkGroup(g)}>生成链接</a>}
          {canManage && <a onClick={() => setEditing(g)}>编辑</a>}
          {canManage && (
            <Popconfirm
              title="删除这个群?"
              description="已发出的链接仍可用,但该群不再计入统计。"
              okText="删除"
              okButtonProps={{ danger: true }}
              onConfirm={() => delGroup(g)}
            >
              <a style={{ color: '#cf1322' }}>删除</a>
            </Popconfirm>
          )}
        </Space>
      ),
    },
  ];

  return (
    <div>
      <Space style={{ marginBottom: 16 }} wrap>
        <Input
          placeholder="群名/sid"
          value={keyword}
          onChange={(e) => setKeyword(e.target.value)}
          onPressEnter={() => setApplied({ keyword: keyword || undefined })}
          allowClear
          style={{ width: 180 }}
        />
        <Button type="primary" onClick={() => setApplied({ keyword: keyword || undefined })}>
          查询
        </Button>
        {canManage && <Button onClick={() => setCreateOpen(true)}>新建群</Button>}
      </Space>

      <Table
        rowKey="id"
        columns={columns}
        dataSource={items}
        loading={loading}
        pagination={{
          current: page,
          pageSize,
          total,
          showSizeChanger: true,
          showTotal: (t) => `共 ${t} 个群`,
          onChange,
        }}
        scroll={{ x: 1090 }}
      />

      <GroupFormModal open={createOpen} group={null} onClose={() => setCreateOpen(false)} onDone={reload} />
      <GroupFormModal open={!!editing} group={editing} onClose={() => setEditing(null)} onDone={reload} />
      <ReferralLinkModal group={linkGroup} onClose={() => setLinkGroup(null)} />
    </div>
  );
}

function GroupFormModal({
  open,
  group,
  onClose,
  onDone,
}: {
  open: boolean;
  group: CpsGroup | null;
  onClose: () => void;
  onDone: () => void;
}) {
  const [form] = Form.useForm();
  const isEdit = !!group;
  const watchPlatforms = (Form.useWatch('platforms', form) as string[] | undefined) || [];
  const hasMeituan = watchPlatforms.includes('meituan');

  useEffect(() => {
    if (open) {
      if (group) {
        form.setFieldsValue({
          name: group.name,
          platforms: group.platforms,
          member_count: group.member_count,
          remark: group.remark,
          status: group.status,
        });
      } else {
        form.resetFields();
        form.setFieldsValue({ platforms: ['meituan'] });
      }
    }
  }, [open, group, form]);

  const submit = async () => {
    const v = await form.validateFields();
    try {
      if (isEdit && group) {
        await api.patch(`/admin/api/cps/groups/${group.id}`, v);
        message.success('已更新群');
      } else {
        await api.post('/admin/api/cps/groups', v);
        message.success('已新建群');
      }
      onClose();
      onDone();
    } catch (e) {
      message.error(errMsg(e));
    }
  };

  return (
    <Modal title={isEdit ? '编辑群' : '新建群'} open={open} onOk={submit} onCancel={onClose} destroyOnHidden>
      <Form form={form} layout="vertical">
        <Form.Item name="name" label="群名" rules={[{ required: true, message: '请输入群名' }]}>
          <Input placeholder="如:宝妈优惠群1" />
        </Form.Item>
        <Form.Item
          name="platforms"
          label="这个群发哪些平台的券(可多选)"
          rules={[{ required: true, message: '至少选一个平台' }]}
        >
          <Checkbox.Group options={PLATFORM_OPTIONS} />
        </Form.Item>
        {hasMeituan && !isEdit && (
          <Form.Item
            name="sid"
            label="美团 sid(渠道标识,留空自动生成 g+ID)"
            rules={[{ pattern: /^[A-Za-z0-9]+$/, message: '仅字母和数字' }]}
          >
            <Input placeholder="留空自动生成;或自定义如 baoma1" maxLength={64} />
          </Form.Item>
        )}
        {hasMeituan && isEdit && (
          <Typography.Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 12 }}>
            当前 sid:{group?.sid || '(无,保存后如缺会在生成美团链接时报错)'}
          </Typography.Text>
        )}
        <Form.Item name="member_count" label="群人数(用于估算转化率)">
          <InputNumber style={{ width: '100%' }} min={0} placeholder="如 200" />
        </Form.Item>
        {isEdit && (
          <Form.Item name="status" label="状态">
            <Select
              options={[
                { value: 'active', label: 'active(启用)' },
                { value: 'archived', label: 'archived(归档)' },
              ]}
            />
          </Form.Item>
        )}
        <Form.Item name="remark" label="备注">
          <Input.TextArea rows={2} maxLength={256} />
        </Form.Item>
      </Form>
    </Modal>
  );
}

function ReferralLinkModal({ group, onClose }: { group: CpsGroup | null; onClose: () => void }) {
  const [activities, setActivities] = useState<CpsActivity[]>([]);
  const [activityIds, setActivityIds] = useState<number[]>([]);
  const [result, setResult] = useState<CpsReferralLinks | null>(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (!group) {
      setActivityIds([]);
      setResult(null);
      return;
    }
    api
      .get('/admin/api/cps/activities', { params: { status: 'active', limit: 100 } })
      .then((r) => setActivities(r.data.items as CpsActivity[]))
      .catch((e) => message.error(errMsg(e)));
  }, [group]);

  // 只列群平台范围内的活动
  const groupActivities = activities.filter((a) => (group?.platforms || []).includes(a.platform));

  const generate = async () => {
    if (!group || !activityIds.length) {
      message.warning('请勾选要生成的活动');
      return;
    }
    setLoading(true);
    try {
      const resp = await api.post<CpsReferralLinks>('/admin/api/cps/referral-links', {
        group_id: group.id,
        activity_ids: activityIds,
      });
      setResult(resp.data);
    } catch (e) {
      message.error(errMsg(e));
    } finally {
      setLoading(false);
    }
  };

  return (
    <Modal
      title={`生成发群链接 - ${group?.name ?? ''}`}
      open={!!group}
      onCancel={onClose}
      onOk={generate}
      okText="生成"
      confirmLoading={loading}
      destroyOnHidden
      width={660}
    >
      <Typography.Paragraph type="secondary" style={{ fontSize: 12 }}>
        勾选要发的活动,每个生成一条咱的落地页链接;复制后发到群里。
      </Typography.Paragraph>
      {groupActivities.length === 0 ? (
        <Typography.Text type="warning">
          该群平台({(group?.platforms || []).map((p) => PLATFORM_LABEL[p]).join('/')})下没有活动,请先到「活动管理」新建。
        </Typography.Text>
      ) : (
        <Checkbox.Group
          value={activityIds}
          onChange={(v) => setActivityIds(v as number[])}
          style={{ width: '100%' }}
        >
          <Space direction="vertical" style={{ width: '100%' }}>
            {groupActivities.map((a) => (
              <Checkbox key={a.id} value={a.id}>
                <Tag color={PLATFORM_COLOR[a.platform]}>{PLATFORM_LABEL[a.platform]}</Tag>
                {a.name}
                {a.act_id ? <span style={{ color: '#999' }}> (actId={a.act_id})</span> : null}
              </Checkbox>
            ))}
          </Space>
        </Checkbox.Group>
      )}

      {result && (
        <div style={{ marginTop: 16 }}>
          <Typography.Text strong>👇 生成结果(逐条复制发群):</Typography.Text>
          {result.results.map((item) => (
            <div
              key={item.code}
              style={{
                marginTop: 8,
                padding: 10,
                background: '#f6ffed',
                border: '1px solid #b7eb8f',
                borderRadius: 6,
              }}
            >
              <div style={{ marginBottom: 4 }}>
                <Tag color={PLATFORM_COLOR[item.platform]}>{PLATFORM_LABEL[item.platform]}</Tag>
                <span style={{ fontSize: 13 }}>{item.activity_name}</span>
              </div>
              <Typography.Text copyable={{ text: item.redirect_url }} style={{ fontSize: 14, wordBreak: 'break-all' }}>
                {item.redirect_url}
              </Typography.Text>
            </div>
          ))}
          {result.results.some((i) => !i.redirect_url.startsWith('http')) && (
            <Typography.Text type="warning" style={{ fontSize: 12 }}>
              ⚠️ 部分为相对路径:后端未配 CPS_REDIRECT_BASE,请配跳转域名后重启。
            </Typography.Text>
          )}
        </div>
      )}
    </Modal>
  );
}

// ───────────── 活动管理 ─────────────
function ActivitiesTab() {
  const { items, total, page, pageSize, loading, onChange, reload } = usePagedList<CpsActivity>(
    '/admin/api/cps/activities',
    {},
  );
  const canManage = canDo(['operator']);
  const [createOpen, setCreateOpen] = useState(false);
  const [editing, setEditing] = useState<CpsActivity | null>(null);

  const delActivity = async (a: CpsActivity) => {
    try {
      await api.delete(`/admin/api/cps/activities/${a.id}`);
      message.success('已删除活动');
      reload();
    } catch (e) {
      message.error(errMsg(e));
    }
  };

  const columns: ColumnsType<CpsActivity> = [
    { title: 'ID', dataIndex: 'id', width: 60 },
    {
      title: '平台',
      dataIndex: 'platform',
      width: 80,
      render: (v: string) => <Tag color={PLATFORM_COLOR[v]}>{PLATFORM_LABEL[v] || v}</Tag>,
    },
    { title: '活动名', dataIndex: 'name', width: 180, ellipsis: true },
    {
      title: 'actId(美团)',
      dataIndex: 'act_id',
      width: 110,
      render: (v: string | null) => v || '-',
    },
    {
      title: '淘口令/链接',
      dataIndex: 'payload',
      width: 240,
      ellipsis: true,
      render: (v: string | null) => v || '-',
    },
    {
      title: '落地页图',
      dataIndex: 'image_url',
      width: 80,
      render: (v: string | null) =>
        v ? (
          <img src={v} alt="" style={{ width: 36, height: 46, objectFit: 'cover', borderRadius: 4 }} />
        ) : (
          '-'
        ),
    },
    {
      title: '状态',
      dataIndex: 'status',
      width: 80,
      render: (s: string) => <Tag color={s === 'active' ? 'green' : 'default'}>{s}</Tag>,
    },
    { title: '创建时间', dataIndex: 'created_at', width: 150, render: (v: string) => formatUtcTime(v) },
    ...(canManage
      ? ([
          {
            title: '操作',
            key: 'op',
            fixed: 'right' as const,
            width: 120,
            render: (_: unknown, a: CpsActivity) => (
              <Space>
                <a onClick={() => setEditing(a)}>编辑</a>
                <Popconfirm
                  title="删除这个活动?"
                  description="已生成的链接仍可用;淘宝活动删除后其落地页改用默认图。"
                  okText="删除"
                  okButtonProps={{ danger: true }}
                  onConfirm={() => delActivity(a)}
                >
                  <a style={{ color: '#cf1322' }}>删除</a>
                </Popconfirm>
              </Space>
            ),
          },
        ] as ColumnsType<CpsActivity>)
      : []),
  ];

  return (
    <div>
      {canManage && (
        <Space style={{ marginBottom: 16 }}>
          <Button type="primary" onClick={() => setCreateOpen(true)}>
            新建活动
          </Button>
        </Space>
      )}
      <Table
        rowKey="id"
        columns={columns}
        dataSource={items}
        loading={loading}
        pagination={{
          current: page,
          pageSize,
          total,
          showSizeChanger: true,
          showTotal: (t) => `共 ${t} 个活动`,
          onChange,
        }}
        scroll={{ x: 1200 }}
      />
      <ActivityFormModal open={createOpen} activity={null} onClose={() => setCreateOpen(false)} onDone={reload} />
      <ActivityFormModal open={!!editing} activity={editing} onClose={() => setEditing(null)} onDone={reload} />
    </div>
  );
}

// 淘宝活动落地页图选择器:上传新图 或 点选已有图。受控组件(value = image_url 绝对 URL)。
function ImagePicker({ value, onChange }: { value?: string | null; onChange?: (v: string) => void }) {
  const [existing, setExisting] = useState<string[]>([]);
  const [uploading, setUploading] = useState(false);

  useEffect(() => {
    api
      .get<{ images: string[] }>('/admin/api/cps/activity-images')
      .then((r) => setExisting(r.data.images || []))
      .catch(() => {});
  }, []);

  const upload = async (file: File) => {
    setUploading(true);
    try {
      const fd = new FormData();
      fd.append('file', file);
      const r = await api.post<{ url: string }>('/admin/api/cps/upload-image', fd);
      onChange?.(r.data.url);
      setExisting((prev) => (prev.includes(r.data.url) ? prev : [r.data.url, ...prev]));
      message.success('图片已上传');
    } catch (e) {
      message.error(errMsg(e, '上传失败'));
    } finally {
      setUploading(false);
    }
  };

  const thumb = (u: string, w: number, selected: boolean) => (
    <img
      key={u}
      src={u}
      alt="落地页图"
      onClick={() => onChange?.(u)}
      style={{
        width: w,
        height: Math.round(w * 1.27),
        objectFit: 'cover',
        borderRadius: 6,
        cursor: 'pointer',
        border: selected ? '2px solid #ff4d4f' : '2px solid #f0f0f0',
      }}
    />
  );

  return (
    <div>
      <Upload
        accept="image/*"
        showUploadList={false}
        beforeUpload={(file) => {
          upload(file);
          return false; // 阻止 antd 默认上传,走我们自己的端点
        }}
      >
        <Button loading={uploading}>上传新图</Button>
      </Upload>
      {value && (
        <div style={{ marginTop: 8, display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{ fontSize: 12, color: '#999' }}>当前:</span>
          {thumb(value, 90, true)}
        </div>
      )}
      {existing.length > 0 && (
        <div style={{ marginTop: 10 }}>
          <div style={{ fontSize: 12, color: '#999', marginBottom: 6 }}>或选择已有图:</div>
          <Space wrap>{existing.map((u) => thumb(u, 56, u === value))}</Space>
        </div>
      )}
    </div>
  );
}

function ActivityFormModal({
  open,
  activity,
  onClose,
  onDone,
}: {
  open: boolean;
  activity: CpsActivity | null;
  onClose: () => void;
  onDone: () => void;
}) {
  const [form] = Form.useForm();
  const isEdit = !!activity;
  const platform = (Form.useWatch('platform', form) as string | undefined) || 'meituan';

  useEffect(() => {
    if (open) {
      if (activity) {
        form.setFieldsValue({
          name: activity.name,
          platform: activity.platform,
          act_id: activity.act_id,
          product_view_sign: activity.product_view_sign,
          payload: activity.payload,
          image_url: activity.image_url,
          remark: activity.remark,
          status: activity.status,
        });
      } else {
        form.resetFields();
        form.setFieldsValue({ platform: 'meituan' });
      }
    }
  }, [open, activity, form]);

  const submit = async () => {
    const v = await form.validateFields();
    if (v.platform === 'meituan') {
      if (!v.act_id && !v.product_view_sign) {
        message.warning('美团活动:actId 与 productViewSign 至少填一个');
        return;
      }
    } else if (!v.payload) {
      message.warning(v.platform === 'taobao' ? '请填淘口令' : '请填京东链接');
      return;
    }
    try {
      if (isEdit && activity) {
        await api.patch(`/admin/api/cps/activities/${activity.id}`, v);
        message.success('已更新活动');
      } else {
        await api.post('/admin/api/cps/activities', v);
        message.success('已新建活动');
      }
      onClose();
      onDone();
    } catch (e) {
      message.error(errMsg(e));
    }
  };

  return (
    <Modal title={isEdit ? '编辑活动' : '新建活动'} open={open} onOk={submit} onCancel={onClose} destroyOnHidden>
      <Form form={form} layout="vertical" initialValues={{ platform: 'meituan' }}>
        <Form.Item name="name" label="活动名" rules={[{ required: true }]}>
          <Input placeholder="如:点我领取大额红包" />
        </Form.Item>
        <Form.Item name="platform" label="平台" rules={[{ required: true }]}>
          <Select options={PLATFORM_OPTIONS} />
        </Form.Item>

        {platform === 'meituan' && (
          <>
            <Form.Item name="act_id" label="actId(美团活动物料 ID,推荐)">
              <Input placeholder="美团联盟「我要推广-活动推广」第一列 ID,如 792" maxLength={64} />
            </Form.Item>
            <Form.Item name="product_view_sign" label="productViewSign(商品券,与 actId 二选一)">
              <Input maxLength={128} />
            </Form.Item>
          </>
        )}
        {platform === 'taobao' && (
          <>
            <Form.Item
              name="payload"
              label="淘口令(整段,运营从淘宝联盟复制,落地页原样复制给用户)"
              rules={[{ required: true, message: '请填淘口令' }]}
            >
              <Input.TextArea rows={4} placeholder="如:8￥abcXYZ￥ https://m.tb.cn/h.xxx 长按复制本条..." maxLength={4096} />
            </Form.Item>
            <Form.Item
              name="image_url"
              label="落地页图(用户点链接后看到的页面主图,上传新图或选已有)"
              rules={[{ required: true, message: '请上传或选择落地页图' }]}
            >
              <ImagePicker />
            </Form.Item>
          </>
        )}
        {platform === 'jd' && (
          <Form.Item
            name="payload"
            label="京东推广链接(落地页 302 跳到它)"
            rules={[{ required: true, message: '请填京东链接' }]}
          >
            <Input placeholder="如:https://u.jd.com/xxxxxx" maxLength={1024} />
          </Form.Item>
        )}

        <Form.Item name="remark" label="备注">
          <Input.TextArea rows={2} maxLength={256} />
        </Form.Item>
        {isEdit && (
          <Form.Item name="status" label="状态">
            <Select
              options={[
                { value: 'active', label: '启用(active)' },
                { value: 'archived', label: '归档(archived)' },
              ]}
            />
          </Form.Item>
        )}
      </Form>
    </Modal>
  );
}

// ───────────── 订单明细 ─────────────
function OrdersTab() {
  const [sid, setSid] = useState('');
  const [status, setStatus] = useState<string | undefined>();
  const [applied, setApplied] = useState<Record<string, unknown>>({});
  const { items, total, page, pageSize, loading, onChange } = usePagedList<CpsOrder>(
    '/admin/api/cps/orders',
    applied,
  );

  const columns: ColumnsType<CpsOrder> = [
    {
      title: '订单号',
      dataIndex: 'order_id',
      width: 200,
      ellipsis: true,
      render: (v: string) => <Typography.Text copyable>{v}</Typography.Text>,
    },
    { title: 'sid', dataIndex: 'sid', width: 120, render: (v) => v || '-' },
    { title: '商品', dataIndex: 'product_name', width: 200, ellipsis: true, render: (v) => v || '-' },
    {
      title: '成交额',
      dataIndex: 'pay_price_cents',
      width: 100,
      render: (v: number | null) => (v != null ? yuan(v) : '-'),
    },
    {
      title: '佣金',
      dataIndex: 'commission_cents',
      width: 90,
      render: (v: number | null) => (v != null ? yuan(v) : '-'),
    },
    { title: '佣金率', dataIndex: 'commission_rate', width: 80, render: fmtRate },
    {
      title: '状态',
      dataIndex: 'mt_status',
      width: 90,
      render: (s: string | null) => {
        const m = s ? MT_STATUS[s] : null;
        return m ? <Tag color={m.color}>{m.text}</Tag> : s || '-';
      },
    },
    { title: '支付时间', dataIndex: 'pay_time', width: 150, render: (v) => formatUtcTime(v) },
  ];

  const search = () => setApplied({ sid: sid || undefined, mt_status: status });

  return (
    <div>
      <Space style={{ marginBottom: 16 }} wrap>
        <Input
          placeholder="sid"
          value={sid}
          onChange={(e) => setSid(e.target.value)}
          onPressEnter={search}
          allowClear
          style={{ width: 150 }}
        />
        <Select
          placeholder="状态"
          value={status}
          onChange={setStatus}
          allowClear
          style={{ width: 120 }}
          options={Object.entries(MT_STATUS).map(([v, m]) => ({ value: v, label: m.text }))}
        />
        <Button type="primary" onClick={search}>
          查询
        </Button>
      </Space>
      <Table
        rowKey="id"
        columns={columns}
        dataSource={items}
        loading={loading}
        pagination={{
          current: page,
          pageSize,
          total,
          showSizeChanger: true,
          showTotal: (t) => `共 ${t} 单`,
          onChange,
        }}
        scroll={{ x: 1030 }}
      />
    </div>
  );
}
