import { useCallback, useEffect, useMemo, useState } from 'react'
import type { ReactNode } from 'react'
import { Alert, Card, Descriptions, Table, Tag, Typography } from 'antd'
import { BookOutlined } from '@ant-design/icons'
import EndpointDoc, { CommonResponseDoc } from '../openapi/EndpointDoc'
import {
  commonResponseFields,
  endpoints,
  errorCodes,
  orderStatusTable,
} from '../openapi/endpoints'
import { endpointSections, type EndpointSpec } from '../openapi/types'

const { Paragraph, Text } = Typography

const baseUrl =
  typeof window !== 'undefined'
    ? window.location.origin.replace(':5173', ':8080')
    : 'http://localhost:8080'

const deliveryModes = [
  {
    mode: '发货链接模式',
    scene: '实现最简：下单后拿一个签名链接，直接跳转平台发货页，由买家在页面上绑定账号并提交',
    interfaces: '/api/client/v1/orders/{order_no}/delivery-link',
    steps: '下单 → 获取发货链接 → 链接给买家 → 平台页完成发货',
    recommend: '商户无自建发货页、想最快上线时使用',
  },
  {
    mode: '自建发货页模式',
    scene: '商户自己有前端页面，把发货流程嵌在自己的系统里（可预填下单时透传的账号/区服）',
    interfaces: '/api/client/v1/orders/{order_no}/delivery\n/api/client/v1/orders/{order_no}/delivery/bind\n/api/client/v1/orders/{order_no}/delivery/submit',
    steps: '下单 → 查询发货数据 → 发起绑定 → 提交发货',
    recommend: '商户需要自定义发货交互（展示区服、预填账号）时使用',
  },
]

// ---------- TOC 目录构建 ----------
interface TocLeaf {
  id: string
  label: string
  level: 3 // 接口子小节（接口地址/请求方式/...）
}
interface TocItem {
  id: string
  label: string
  children?: TocLeaf[]
}
interface TocGroup {
  title: string
  items: TocItem[]
}

function buildToc(): TocGroup[] {
  const tocItems = (eps: typeof endpoints) =>
    eps.map((ep) => ({
      id: `ep-${ep.key}`,
      label: ep.title,
      children: endpointSections.map((s) => ({
        id: `ep-${ep.key}-${s.id}`,
        label: s.label,
        level: 3 as const,
      })),
    }))
  return [
    {
      title: '开始',
      items: [
        { id: 'overview', label: '概述' },
        { id: 'auth', label: '鉴权与签名' },
      ],
    },
    {
      title: '基础接口',
      items: tocItems(endpoints.filter((ep) => ep.group === 'basic')),
    },
    {
      title: '发货链接模式',
      items: tocItems(endpoints.filter((ep) => ep.group === 'delivery-link')),
    },
    {
      title: '自建发货页模式',
      items: tocItems(endpoints.filter((ep) => ep.group === 'delivery-self')),
    },
    {
      title: '回调',
      items: [
        { id: 'callback', label: '回调通知' },
        { id: 'callback-sign', label: '签名校验' },
        { id: 'callback-retry', label: '推送与重试' },
      ],
    },
    {
      title: '附录',
      items: [{ id: 'status', label: '状态说明' }],
    },
  ]
}

const toc = buildToc()

const pageItems = toc.flatMap((group) => group.items)
const pageIds = new Set(pageItems.map((item) => item.id))

function findPageId(id: string): string {
  if (pageIds.has(id)) return id
  for (const item of pageItems) {
    if (item.children?.some((child) => child.id === id)) return item.id
  }
  return 'overview'
}

function getInitialHash() {
  if (typeof window === 'undefined') return 'overview'
  return decodeURIComponent(window.location.hash.replace(/^#/, '')) || 'overview'
}

// ---------- 锚点跳转 ----------
function scrollToId(id: string) {
  const el = document.getElementById(id)
  if (!el) return
  const root = document.getElementById('docScroll')
  if (!root) return
  const top = root.scrollTop + el.getBoundingClientRect().top - root.getBoundingClientRect().top - 22
  root.scrollTo({ top, behavior: 'smooth' })
}

export default function OpenApiDocs() {
  const initialHash = useMemo(() => getInitialHash(), [])
  const [activePageId, setActivePageId] = useState(() => findPageId(initialHash))
  const [activeAnchorId, setActiveAnchorId] = useState(initialHash)
  const activeEndpoint = useMemo(
    () => endpoints.find((spec) => `ep-${spec.key}` === activePageId),
    [activePageId],
  )

  useEffect(() => {
    const syncHash = () => {
      const nextHash = getInitialHash()
      setActivePageId(findPageId(nextHash))
      setActiveAnchorId(nextHash)
    }
    window.addEventListener('hashchange', syncHash)
    return () => window.removeEventListener('hashchange', syncHash)
  }, [])

  useEffect(() => {
    const root = document.getElementById('docScroll')
    if (!root) return

    if (activeAnchorId !== activePageId) {
      requestAnimationFrame(() => scrollToId(activeAnchorId))
      return
    }
    root.scrollTo({ top: 0 })
  }, [activeAnchorId, activePageId])

  const activeIndex = useMemo(
    () => pageItems.findIndex((item) => item.id === activePageId),
    [activePageId],
  )

  const handleNav = useCallback((id: string) => {
    const pageId = findPageId(id)
    setActivePageId(pageId)
    setActiveAnchorId(id)
    if (typeof window !== 'undefined') {
      window.history.replaceState(null, '', `${window.location.pathname}${window.location.search}#${id}`)
    }
  }, [])

  const handleStep = useCallback(
    (direction: -1 | 1) => {
      const next = pageItems[activeIndex + direction]
      if (next) handleNav(next.id)
    },
    [activeIndex, handleNav],
  )

  return (
    <div className="api-docs">
      {/* 左侧目录 */}
      <aside className="api-docs__toc">
        <div className="api-docs__toc-header">
          <BookOutlined style={{ color: '#2563eb', fontSize: 16 }} />
          <span>文档章节目录</span>
        </div>
        <nav className="api-docs__nav">
          {toc.map((group) => (
            <div className="api-docs__nav-group" key={group.title}>
              <div className="api-docs__nav-heading">{group.title}</div>
              {group.items.map((item) => {
                const isActive = activePageId === item.id
                return (
                  <div className="api-docs__nav-row" key={item.id}>
                    <a
                      className={`api-docs__nav-item${isActive ? ' api-docs__nav-item--active' : ''}`}
                      onClick={() => handleNav(item.id)}
                    >
                      {item.label}
                    </a>
                    {item.children?.length && isActive ? (
                      <div className="api-docs__nav-sub">
                        {item.children.map((c) => (
                          <a
                            key={c.id}
                            className={`api-docs__nav-sub-item${activeAnchorId === c.id ? ' api-docs__nav-sub-item--active' : ''}`}
                            onClick={() => handleNav(c.id)}
                          >
                            {c.label}
                          </a>
                        ))}
                      </div>
                    ) : null}
                  </div>
                )
              })}
            </div>
          ))}
        </nav>
      </aside>

      {/* 右侧文档 */}
      <div id="docScroll" className="api-docs__content">
        <div className="api-docs__inner">
          {activePageId === 'overview' ? <OverviewSection /> : null}
          {activePageId === 'auth' ? <AuthSection /> : null}
          {activePageId === 'callback' ? <CallbackSection /> : null}
          {activePageId === 'callback-sign' ? <CallbackSignSection /> : null}
          {activePageId === 'callback-retry' ? <CallbackRetrySection /> : null}
          {activeEndpoint ? <EndpointSection spec={activeEndpoint} /> : null}
          {activePageId === 'status' ? <StatusSection /> : null}
          <PageStepper
            currentIndex={activeIndex}
            items={pageItems}
            onStep={handleStep}
          />
        </div>
      </div>
    </div>
  )
}

function PageStepper({
  currentIndex,
  items,
  onStep,
}: {
  currentIndex: number
  items: TocItem[]
  onStep: (direction: -1 | 1) => void
}) {
  const prev = items[currentIndex - 1]
  const next = items[currentIndex + 1]

  return (
    <div className="api-docs__pager">
      <button
        className="api-docs__pager-btn"
        type="button"
        disabled={!prev}
        onClick={() => onStep(-1)}
      >
        <span>上一篇</span>
        <strong>{prev?.label ?? '无'}</strong>
      </button>
      <button
        className="api-docs__pager-btn api-docs__pager-btn--next"
        type="button"
        disabled={!next}
        onClick={() => onStep(1)}
      >
        <span>下一篇</span>
        <strong>{next?.label ?? '无'}</strong>
      </button>
    </div>
  )
}

// ---------- 各文档小节 ----------
function SectionWrap({
  id,
  title,
  desc,
  children,
}: {
  id: string
  title: string
  desc?: ReactNode
  children?: ReactNode
}) {
  return (
    <div className="api-docs__section">
      <h2 id={id} className="api-docs__h2">
        {title}
      </h2>
      {desc ? <Paragraph className="api-docs__summary" type="secondary">{desc}</Paragraph> : null}
      {children}
    </div>
  )
}

function OverviewSection() {
  return (
    <SectionWrap
      id="overview"
      title="概述"
      desc={
        <>
          面向商户系统调用的开放 API。凭证在「开放 API / API 密钥」创建，
          采用 <Text code>X-App-Key</Text> + HMAC-SHA256 签名鉴权。
          发货链路同时支持「返回签名链接」和「返回结构化数据」两种模式。
        </>
      }
    >
      <Alert
        className="api-docs__alert"
        type="info"
        showIcon
        message="一句话上手"
        description={
          <ol style={{ margin: 0, paddingLeft: 20 }}>
            <li>在「开放 API / API 密钥」创建凭证，获得 <Text code>AppKey</Text> 与 <Text code>AppSecret</Text>。</li>
            <li>每次请求携带 <Text code>X-App-Key / X-Timestamp / X-Nonce / X-Sign</Text> 四个鉴权头。</li>
            <li>调用「商品列表」拿到可售 <Text code>sku</Text>，调用「下单」创建订单并扣款。</li>
            <li>拿到 <Text code>order_no</Text> 后，按「发货对接方式」二选一：发货链接模式（返回链接即可）或自建发货页模式（结构化接口）。</li>
            <li>在「回调」页配置回调地址并订阅事件，订单状态变化会实时推送，见「回调通知」。</li>
          </ol>
        }
      />
      <Card className="api-docs__card" size="small" title="发货对接方式（二选一，先选好再看对应接口）">
        <Table
          className="api-docs__table"
          size="small"
          pagination={false}
          rowKey="mode"
          dataSource={deliveryModes}
          scroll={{ x: 1080 }}
          columns={[
            {
              title: '方式',
              dataIndex: 'mode',
              width: 140,
              render: (v: string) => <span style={{ fontWeight: 700, whiteSpace: 'nowrap', color: '#0f172a' }}>{v}</span>,
            },
            {
              title: '适用场景',
              dataIndex: 'scene',
              width: 280,
              render: (v: string) => <span style={{ fontSize: 13, lineHeight: 1.6, display: 'block', color: '#334155' }}>{v}</span>,
            },
            {
              title: '接口顺序',
              dataIndex: 'steps',
              width: 240,
              render: (v: string) => <pre className="api-docs__pre" style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>{v}</pre>,
            },
            {
              title: '相关接口',
              dataIndex: 'interfaces',
              width: 260,
              render: (v: string) => <pre className="api-docs__pre" style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>{v}</pre>,
            },
            {
              title: '建议',
              dataIndex: 'recommend',
              width: 180,
              render: (v: string) => <span style={{ fontSize: 13, lineHeight: 1.5, display: 'block', color: '#475569' }}>{v}</span>,
            },
          ]}
        />
      </Card>
      <Card className="api-docs__card" size="small" title="环境信息">
        <Descriptions size="small" column={1} bordered>
          <Descriptions.Item label="Base URL">
            <Text code>{baseUrl}</Text>
          </Descriptions.Item>
          <Descriptions.Item label="鉴权头">
            <Text code>X-App-Key</Text>、<Text code>X-Timestamp</Text>、<Text code>X-Nonce</Text>、<Text code>X-Sign</Text>
          </Descriptions.Item>
          <Descriptions.Item label="时间偏差">允许 ±300 秒</Descriptions.Item>
          <Descriptions.Item label="时间格式">
            所有时间字段统一返回 RFC3339 秒级北京时间，例如 <Text code>2026-07-30T17:53:58+08:00</Text>
          </Descriptions.Item>
          <Descriptions.Item label="请求体">POST 请求使用 <Text code>application/json</Text></Descriptions.Item>
        </Descriptions>
      </Card>
      <div className="api-docs__common">
        <CommonResponseDoc fields={commonResponseFields} errors={errorCodes} />
      </div>
    </SectionWrap>
  )
}

function AuthSection() {
  return (
    <SectionWrap id="auth" title="鉴权与签名">
      <Card className="api-docs__card" size="small" title="鉴权头（每次请求必带）">
        <Table
          className="api-docs__table"
          size="small"
          pagination={false}
          rowKey="header"
          dataSource={[
            { header: 'X-App-Key', required: true, desc: '商户分配的 AppKey' },
            { header: 'X-Timestamp', required: true, desc: '当前 Unix 秒时间戳' },
            { header: 'X-Nonce', required: true, desc: '随机串，8~96 字符，同一客户端有效期内不可重复' },
            { header: 'X-Sign', required: true, desc: 'HMAC-SHA256 签名，见下方算法' },
          ]}
          columns={[
            { title: 'Header', dataIndex: 'header', width: 160, render: (v) => <Text code>{v}</Text> },
            {
              title: '必填',
              dataIndex: 'required',
              width: 80,
              render: (v) => v ? <span className="api-docs__required">是</span> : <Text type="secondary">否</Text>,
            },
            { title: '说明', dataIndex: 'desc' },
          ]}
        />
      </Card>

      <Card className="api-docs__card" size="small" title="签名算法">
        <Descriptions size="small" column={1} bordered>
          <Descriptions.Item label="参与参数">
            <Text code>app_key</Text>、<Text code>body_sha256</Text>、<Text code>method</Text>、<Text code>nonce</Text>、<Text code>path</Text>、<Text code>timestamp</Text>
          </Descriptions.Item>
          <Descriptions.Item label="拼接方式">参数按 ASCII 字典序，用 <Text code>&</Text> 拼成 <Text code>k1=v1&k2=v2&...</Text></Descriptions.Item>
          <Descriptions.Item label="排序后顺序">
            <Text code>app_key, body_sha256, method, nonce, path, timestamp</Text>
          </Descriptions.Item>
          <Descriptions.Item label="method">大写，如 GET / POST</Descriptions.Item>
          <Descriptions.Item label="path">仅 URL.Path，不含域名和 query</Descriptions.Item>
          <Descriptions.Item label="body_sha256">
            <Text code>SHA256(原始 body 字节)</Text> 的十六进制小写；GET 用空 body 的摘要
          </Descriptions.Item>
          <Descriptions.Item label="value">原样拼接，不做 URL encode</Descriptions.Item>
          <Descriptions.Item label="X-Sign">
            <Text code>hex( HMAC-SHA256( app_secret, 签名串 ) )</Text>，小写十六进制
          </Descriptions.Item>
        </Descriptions>
      </Card>

      <Card className="api-docs__card" size="small" title="签名示例（GET，body 为空）">
        <pre className="api-docs__pre">{`app_key=ak_xxx&body_sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855&method=GET&nonce=a1b2c3d4e5f67890&path=/api/client/v1/products&timestamp=1721450000`}</pre>
      </Card>

      <Card className="api-docs__card" size="small" title="签名示例（POST，body 非空）">
        <pre className="api-docs__pre">{`# body = {"client_order_no":"shop-10001","sku":"suit_pink_sheep"}
app_key=ak_xxx&body_sha256=<实际请求 body 字节的 SHA256 十六进制>&method=POST&nonce=a1b2c3d4e5f67890&path=/api/client/v1/orders&timestamp=1721450000`}</pre>
      </Card>

      <Alert
        className="api-docs__alert"
        type="warning"
        showIcon
        message="签名注意事项"
        style={{ marginTop: 16 }}
        description={
          <ul style={{ margin: 0, paddingLeft: 20 }}>
            <li>POST 签名用的 <Text code>body</Text> 必须与实际发送的 body <b>字节级一致</b>，不要签名后再改空格或字段顺序。</li>
            <li>value <b>不要</b> URL encode，原样参与拼接。</li>
            <li>签名失败常见原因：secret 错、path 多了 query、body 与签名不一致、时间戳过期、nonce 重复、参数未按字典序拼接。</li>
            <li>下单幂等直接使用 <Text code>client_order_no</Text>，无需额外 Header。</li>
          </ul>
        }
      />
    </SectionWrap>
  )
}

function EndpointSection({ spec }: { spec: EndpointSpec }) {
  return (
    <div className="api-docs__section">
      <div className="api-docs__endpoint-head">
        <h2 id={`ep-${spec.key}`} className="api-docs__h2">
          {spec.title}
        </h2>
        <div className="api-docs__endpoint-meta">
          <Tag color={spec.method === 'GET' ? 'blue' : 'geekblue'}>{spec.method}</Tag>
          <Text code>{spec.scope}</Text>
        </div>
      </div>
      <EndpointDoc spec={spec} />
    </div>
  )
}

// ---------- 回调通知文档 ----------

const callbackEvents = [
  {
    event: 'order.created',
    desc: '订单创建成功（已扣款，order_status=paid）',
    trigger: '创建订单',
  },
  {
    event: 'order.shipping.updated',
    desc: '发货状态变化：提交发货（delivering）、发货成功（delivered）、发货失败（ship_failed）',
    trigger: '提交发货 / 发货结果回传',
  },
  {
    event: 'order.cancelled',
    desc: '订单取消并退款（order_status=cancelled）',
    trigger: '取消订单',
  },
]

const callbackPayloadExample = `{
  "event_id": "4751626d-d608-42c1-a453-60ffcafc01fc",
  "event": "order.shipping.updated",
  "occurred_at": "2026-08-03T10:11:20+08:00",
  "data": {
    "order_no": "FO20260803000123",
    "client_order_no": "shop-10001",
    "order_status": "delivered",
    "can_ship": false,
    "product_sku": "suit_pink_sheep",
    "quantity": 1,
    "amount": 105,
    "currency": "POINT",
    "provider_order_no": "PROV-xxxx",
    "failure_reason": "",
    "created_at": "2026-08-03T10:00:00+08:00",
    "delivered_at": "2026-08-03T10:11:20+08:00",
    "data": { "game_account": "4808146277", "game_channel": "ios-wechat", "role_name": "玩家名" }
  }
}`

const retrySchedule = [
  { attempt: 2, after: '15 秒' },
  { attempt: 3, after: '15 秒' },
  { attempt: 4, after: '30 秒' },
  { attempt: 5, after: '3 分钟' },
  { attempt: 6, after: '10 分钟' },
  { attempt: 7, after: '20 分钟' },
  { attempt: 8, after: '30 分钟' },
  { attempt: 9, after: '30 分钟' },
  { attempt: 10, after: '30 分钟' },
  { attempt: 11, after: '1 小时' },
  { attempt: 12, after: '3 小时' },
  { attempt: 13, after: '3 小时' },
  { attempt: 14, after: '3 小时' },
  { attempt: 15, after: '6 小时' },
  { attempt: 16, after: '6 小时' },
]

function CallbackSection() {
  return (
    <SectionWrap
      id="callback"
      title="回调通知"
      desc={
        <>
          平台通过 <Text code>POST</Text> 方式把订单事件推送到商户配置的回调地址。
          商户在后台「回调」页配置一个 URL 并订阅事件，配置保存在 outbox 表中，
          订单事务提交后才写入待推送记录，进程重启不会丢失。
        </>
      }
    >
      <Alert
        className="api-docs__alert"
        type="info"
        showIcon
        message="快速接入"
        description={
          <ol style={{ margin: 0, paddingLeft: 20 }}>
            <li>在商户后台「回调」页填写回调 URL 并订阅事件，保存后获得 <Text code>CallbackSecret</Text>（仅展示一次，可在后台重置）。</li>
            <li>接收平台推送：请求头带 <Text code>X-Event-ID / X-Timestamp / X-Sign</Text>，按「签名校验」验证后处理。</li>
            <li>返回 HTTP 2xx 即视为投递成功；非 2xx 或超时按「推送与重试」策略重试。</li>
          </ol>
        }
      />
      <Card className="api-docs__card" size="small" title="回调事件">
        <Table
          className="api-docs__table"
          size="small"
          pagination={false}
          rowKey="event"
          dataSource={callbackEvents}
          columns={[
            { title: '事件', dataIndex: 'event', width: 220, render: (v) => <Text code>{v}</Text> },
            { title: '触发时机', dataIndex: 'trigger', width: 220 },
            { title: '说明', dataIndex: 'desc' },
          ]}
        />
      </Card>
      <Card className="api-docs__card" size="small" title="推送请求示例">
        <Descriptions size="small" column={1} bordered style={{ marginBottom: 12 }}>
          <Descriptions.Item label="URL">
            <Text code>POST https://你的服务器/callback</Text>
          </Descriptions.Item>
          <Descriptions.Item label="Content-Type">
            <Text code>application/json</Text>
          </Descriptions.Item>
        </Descriptions>
        <pre className="api-docs__pre">{`POST /callback HTTP/1.1
Content-Type: application/json
X-Event-ID: 4751626d-d608-42c1-a453-60ffcafc01fc
X-Timestamp: 1785723081
X-Sign: 191892922db64bf41159f58e...`}</pre>
        <pre className="api-docs__pre">{callbackPayloadExample}</pre>
      </Card>
      <Card className="api-docs__card" size="small" title="接收方要求">
        <ul style={{ margin: 0, paddingLeft: 20 }}>
          <li>返回 <Text code>2xx</Text>（任意状态码）即视为投递成功；返回其他状态码或超时视为失败并进入重试。</li>
          <li>同一事件的 <Text code>X-Event-ID</Text> 全局唯一，请按它做幂等处理，避免重复入账。</li>
          <li>事件里的 <Text code>occurred_at</Text> 是事件发生时间，与请求头 <Text code>X-Timestamp</Text> 不同。</li>
        </ul>
      </Card>
    </SectionWrap>
  )
}

function CallbackSignSection() {
  return (
    <SectionWrap id="callback-sign" title="签名校验">
      <Card className="api-docs__card" size="small" title="请求头">
        <Table
          className="api-docs__table"
          size="small"
          pagination={false}
          rowKey="header"
          dataSource={[
            { header: 'X-Event-ID', desc: '事件唯一 ID，接收方用于幂等' },
            { header: 'X-Timestamp', desc: '推送时的 Unix 秒时间戳' },
            { header: 'X-Sign', desc: 'HMAC-SHA256 签名，见下方算法' },
          ]}
          columns={[
            { title: 'Header', dataIndex: 'header', width: 160, render: (v) => <Text code>{v}</Text> },
            { title: '说明', dataIndex: 'desc' },
          ]}
        />
      </Card>
      <Card className="api-docs__card" size="small" title="签名算法">
        <Descriptions size="small" column={1} bordered>
          <Descriptions.Item label="密钥">
            <Text code>CallbackSecret</Text>（保存回调配置时展示一次，可在后台「重置密钥」）
          </Descriptions.Item>
          <Descriptions.Item label="body_hash">
            <Text code>sha256hex(body)</Text> —— 原始请求体字节的 SHA256 十六进制（小写）
          </Descriptions.Item>
          <Descriptions.Item label="签名串">
            <Text code>body_sha256=&lt;hash&gt;&amp;timestamp=&lt;unix秒&gt;</Text>，按 ASCII 字典序 <Text code>&amp;</Text> 拼接（与开放 API 鉴权同一风格）
          </Descriptions.Item>
          <Descriptions.Item label="X-Sign">
            <Text code>hex( HMAC-SHA256( secret, 签名串 ) )</Text>，小写十六进制
          </Descriptions.Item>
        </Descriptions>
      </Card>
      <Card className="api-docs__card" size="small" title="校验伪代码">
        <pre className="api-docs__pre">{`bodyHash = sha256Hex(rawBody)
content = "body_sha256=" + bodyHash + "&timestamp=" + timestamp
expected = hmacSHA256Hex(secret, content)
ok = (X-Sign == expected)`}</pre>
      </Card>
      <Alert
        className="api-docs__alert"
        type="warning"
        showIcon
        message="注意"
        description={
          <ul style={{ margin: 0, paddingLeft: 20 }}>
            <li>校验用 <Text code>原始 body 字节</Text>，不要重新序列化后再算摘要。</li>
            <li>建议校验 <Text code>X-Timestamp</Text> 与当前时间偏差（如 ±5 分钟）后验签。</li>
            <li>若在后台重置密钥，旧密钥立即失效，新密钥签名推送。</li>
          </ul>
        }
      />
    </SectionWrap>
  )
}

function CallbackRetrySection() {
  return (
    <SectionWrap
      id="callback-retry"
      title="推送与重试"
      desc={
        <>
          回调基于数据库 outbox 持久化推送（每 3 秒轮询一批），失败后按固定间隔退避重试，
          参考微信/支付宝通知机制。重试次数与间隔可通过环境变量调整：
          <Text code>CALLBACK_MAX_ATTEMPTS</Text>（默认 16）、
          <Text code>CALLBACK_RETRY_SCHEDULE</Text>（逗号分隔秒数）。
        </>
      }
    >
      <Card className="api-docs__card" size="small" title="重试策略（默认）">
        <Table
          className="api-docs__table"
          size="small"
          pagination={false}
          rowKey="attempt"
          dataSource={retrySchedule}
          columns={[
            { title: '第 N 次推送', dataIndex: 'attempt', width: 140, render: (v) => <Text code>{v}</Text> },
            { title: '距上次失败间隔', dataIndex: 'after' },
          ]}
        />
      </Card>
      <Alert
        className="api-docs__alert"
        type="info"
        showIcon
        message="规则"
        description={
          <ul style={{ margin: 0, paddingLeft: 20 }}>
            <li>共尝试 <Text code>16</Text> 次（首次 + 15 次重试），全部失败后标记 <Text code>failed</Text>，不再推送。</li>
            <li>单次推送超时 <Text code>15 秒</Text>（可配 <Text code>CALLBACK_PUSH_TIMEOUT_SECONDS</Text>）按失败处理。</li>
            <li>接收方返回任意 <Text code>2xx</Text> 即停止重试。</li>
            <li>未配置回调地址或订阅未匹配事件时不会产生推送。</li>
          </ul>
        }
      />
    </SectionWrap>
  )
}

function StatusSection() {  return (
    <SectionWrap id="status" title="状态说明">
      <Card className="api-docs__card" size="small" title="订单状态 order_status 与 can_ship">
        <Table
          className="api-docs__table"
          size="small"
          pagination={false}
          rowKey="name"
          dataSource={orderStatusTable}
          columns={[
            { title: '状态', dataIndex: 'name', width: 140, render: (v) => <Text code>{v}</Text> },
            {
              title: 'can_ship',
              dataIndex: 'example',
              width: 160,
              render: (v: string) =>
                v === 'can_ship=true' ? <Tag color="green">true</Tag> : <Tag>false</Tag>,
            },
            { title: '说明', dataIndex: 'desc' },
          ]}
        />
      </Card>
      <Alert
        className="api-docs__alert"
        type="info"
        showIcon
        message="推荐调用流程"
        style={{ marginTop: 16 }}
        description={
          <pre className="api-docs__pre api-docs__pre--plain">{`拿到 sku（商品列表）
    ↓
POST /orders 下单（client_order_no 幂等）
    ↓
拿响应里的 order_no 进入发货链接
    ↓
买家在发货页绑定账号并提交发货
    ↓
平台完成发货处理并更新 order_status
    ↓
GET /orders/{order_no} 轮询，或接收 order.shipping.updated 回调`}</pre>
        }
      />
    </SectionWrap>
  )
}
