import { useCallback, useEffect, useState } from 'react'
import {
  apiInjectApply,
  apiInjectDelete,
  apiInjectFetchModels,
  apiInjectList,
  apiInjectReset,
  apiInjectRouterGet,
  apiInjectRouterSave,
  apiInjectSave,
  apiInjectStatus,
  restartApp,
  routerLogs,
  ROUTER_ENDPOINT_ID
} from '../ipc'
import type {
  ApiEndpoint,
  ApiStatus,
  ModelInfo,
  RequestLog,
  RouteRule,
  RouterConfig,
  RouterStatus
} from '../types'
import { ConfirmDialog, Modal } from './Modal'
import { IconEdit, IconPlus, IconTrash } from './Icons'

interface EditState {
  id: string
  name: string
  baseUrl: string
  key: string
  model: string
  models: string[]
  isNew: boolean
}

const emptyEdit = (): EditState => ({
  id: '',
  name: '',
  baseUrl: '',
  key: '',
  model: '',
  models: [],
  isNew: true
})

/** 待注入目标：真实接口或内置虚拟路由接口 */
interface ApplyTarget {
  id: string
  name: string
}

/** CLI 保留别名（前端提示用，后端保存时强校验） */
const RESERVED_ALIASES = ['sonnet', 'opus', 'haiku', 'fable']

/** API 注入：显示 Claude Code 当前全局模型接口，管理自定义接口并一键注入/恢复官方 */
export function ApiInjectPage() {
  const [status, setStatus] = useState<ApiStatus | null>(null)
  const [endpoints, setEndpoints] = useState<ApiEndpoint[]>([])
  const [editing, setEditing] = useState<EditState | null>(null)
  const [deleting, setDeleting] = useState<ApiEndpoint | null>(null)
  const [applying, setApplying] = useState<ApplyTarget | null>(null)
  const [resetting, setResetting] = useState(false)
  /** 非空 = 弹出"重启后生效"提示 */
  const [restartHint, setRestartHint] = useState('')
  /** 路由配置面板开关 */
  const [routerOpen, setRouterOpen] = useState(false)
  const [error, setError] = useState('')
  const [busy, setBusy] = useState(false)

  const refresh = useCallback(async () => {
    try {
      const [s, list] = await Promise.all([apiInjectStatus(), apiInjectList()])
      setStatus(s)
      setEndpoints(list)
    } catch (e) {
      setError(String(e))
    }
  }, [])

  useEffect(() => {
    void refresh()
  }, [refresh])

  const doApply = async (target: ApplyTarget) => {
    setBusy(true)
    setError('')
    try {
      await apiInjectApply(target.id)
      setApplying(null)
      setRestartHint(
        target.id === ROUTER_ENDPOINT_ID
          ? '已将「多模型路由」注入为 Claude Code 全局模型接口。\n注意：路由模式依赖 CCGUI 内嵌代理，CCGUI 未运行时新会话将无法连通接口。'
          : `已将「${target.name}」注入为 Claude Code 全局模型接口。`
      )
      await refresh()
    } catch (e) {
      setError(String(e))
      setApplying(null)
    } finally {
      setBusy(false)
    }
  }

  const doReset = async () => {
    setBusy(true)
    setError('')
    try {
      await apiInjectReset()
      setResetting(false)
      setRestartHint('已恢复 Claude Code 官方接口。')
      await refresh()
    } catch (e) {
      setError(String(e))
      setResetting(false)
    } finally {
      setBusy(false)
    }
  }

  const doDelete = async (ep: ApiEndpoint) => {
    setError('')
    try {
      setEndpoints(await apiInjectDelete(ep.id))
    } catch (e) {
      setError(String(e))
    } finally {
      setDeleting(null)
    }
  }

  const modeBadge =
    status?.mode === 'router' ? (
      <span className="badge accent" style={{ marginLeft: 8 }}>
        多模型路由
      </span>
    ) : status?.isOfficial ? (
      <span className="badge" style={{ marginLeft: 8 }}>
        官方
      </span>
    ) : (
      <span className="badge" style={{ marginLeft: 8 }}>
        直连
      </span>
    )

  return (
    <div className="page">
      <h2>API 注入</h2>
      <p className="page-desc">
        查看并替换 Claude Code 的全局模型接口（~/.claude/settings.json）。注入对新开的会话生效。
      </p>
      {error && <div style={{ color: 'var(--danger)', marginBottom: 10 }}>{error}</div>}

      {/* 当前全局接口状态 */}
      <div
        style={{
          border: '1px solid var(--border)',
          borderRadius: 'var(--radius)',
          background: 'var(--bg-panel)',
          padding: '10px 14px',
          marginBottom: 22
        }}
      >
        <div style={{ fontWeight: 600, marginBottom: 4 }}>当前全局接口</div>
        {status ? (
          <div style={{ fontSize: 13, lineHeight: 1.9 }}>
            <div>
              接口地址：
              <span style={{ fontFamily: 'var(--font-mono)' }}>
                {status.isOfficial ? '官方默认（https://api.anthropic.com）' : status.baseUrl}
              </span>
              {modeBadge}
            </div>
            <div>
              API Key：
              <span style={{ fontFamily: 'var(--font-mono)' }}>
                {status.keyMasked ?? '未设置（使用官方登录凭据）'}
              </span>
            </div>
            <div>
              模型：
              <span style={{ fontFamily: 'var(--font-mono)' }}>
                {status.model ?? '默认（跟随 Claude Code）'}
              </span>
            </div>
          </div>
        ) : (
          <div className="empty-hint" style={{ padding: 12 }}>
            读取中…
          </div>
        )}
      </div>

      {/* 接口列表：内置路由接口固定首条 */}
      <div className="toolbar" style={{ marginBottom: 8 }}>
        <div>
          <div style={{ fontWeight: 600 }}>接口</div>
          <div style={{ color: 'var(--text-dim)', fontSize: 12 }}>保存后可一键注入为全局接口</div>
        </div>
        <div className="spacer" />
        <button className="btn primary" onClick={() => setEditing(emptyEdit())}>
          <IconPlus />
          新增接口
        </button>
      </div>
      <div className="row-list">
        {/* 内置虚拟接口：多模型路由 */}
        <div className="row">
          <div className="row-main">
            <div className="row-title">
              多模型路由
              <span className="badge" style={{ marginLeft: 6 }}>
                内置
              </span>
              {status?.injectedEndpointId === ROUTER_ENDPOINT_ID && (
                <span className="badge accent" style={{ marginLeft: 6 }}>
                  使用中
                </span>
              )}
            </div>
            <div className="row-sub">
              本地代理按模型名把请求路由到不同接口：主会话与各个 subagent 可使用不同接口、不同模型
            </div>
          </div>
          <div className="row-actions">
            <button
              className="btn small primary"
              disabled={busy}
              onClick={() => setApplying({ id: ROUTER_ENDPOINT_ID, name: '多模型路由' })}
            >
              注入
            </button>
            <button className="btn small" onClick={() => setRouterOpen(true)}>
              配置
            </button>
          </div>
        </div>

        {endpoints.length === 0 && (
          <div className="empty-hint">还没有自定义接口，点击右上角「新增接口」</div>
        )}
        {endpoints.map((ep) => (
          <div key={ep.id} className="row">
            <div className="row-main">
              <div className="row-title">
                {ep.name}
                {status?.injectedEndpointId === ep.id && (
                  <span className="badge accent" style={{ marginLeft: 6 }}>
                    使用中
                  </span>
                )}
              </div>
              <div className="row-sub" style={{ fontFamily: 'var(--font-mono)' }}>
                {ep.baseUrl} · {ep.model || '（未指定模型）'}
                {ep.models.length > 0 && ` · 路由 ×${ep.models.length}`}
              </div>
            </div>
            <div className="row-actions">
              <button
                className="btn small primary"
                disabled={busy}
                onClick={() => setApplying({ id: ep.id, name: ep.name })}
              >
                注入
              </button>
              <button
                className="btn small"
                title="编辑"
                onClick={() => setEditing({ ...ep, isNew: false })}
              >
                <IconEdit />
              </button>
              <button className="btn small danger" title="删除" onClick={() => setDeleting(ep)}>
                <IconTrash />
              </button>
            </div>
          </div>
        ))}
      </div>

      {/* 恢复官方 */}
      <div style={{ marginTop: 22 }}>
        <button
          className="btn danger"
          disabled={busy || !status || status.isOfficial}
          onClick={() => setResetting(true)}
        >
          恢复官方接口
        </button>
        <span style={{ marginLeft: 8, color: 'var(--text-faint)', fontSize: 12 }}>
          移除 settings.json 中注入的接口地址 / Key / 模型，恢复为官方默认
        </span>
      </div>

      {/* 新增/编辑弹窗 */}
      {editing && (
        <EditDialog
          initial={editing}
          onClose={() => setEditing(null)}
          onSaved={(list) => {
            setEndpoints(list)
            setEditing(null)
          }}
        />
      )}

      {/* 路由配置面板（关闭后刷新状态卡：保存可能已重写 settings） */}
      {routerOpen && (
        <RouterPanel
          onClose={() => {
            setRouterOpen(false)
            void refresh()
          }}
        />
      )}

      {/* 删除确认 */}
      {deleting && (
        <ConfirmDialog
          title="删除接口"
          message={`确定删除自定义接口「${deleting.name}」？不会改动已注入的配置。`}
          confirmText="删除"
          danger
          onCancel={() => setDeleting(null)}
          onConfirm={() => void doDelete(deleting)}
        />
      )}

      {/* 注入确认 */}
      {applying && (
        <ConfirmDialog
          title="注入接口"
          message={
            applying.id === ROUTER_ENDPOINT_ID
              ? '确定将「多模型路由」注入为 Claude Code 全局模型接口？\n\nsettings.json 将指向 CCGUI 内嵌代理（127.0.0.1），请先在「配置」里设置好路由表与默认接口。'
              : `确定将「${applying.name}」注入为 Claude Code 全局模型接口？`
          }
          confirmText="注入"
          onCancel={() => setApplying(null)}
          onConfirm={() => void doApply(applying)}
        />
      )}

      {/* 重置确认 */}
      {resetting && (
        <ConfirmDialog
          title="恢复官方接口"
          message="确定恢复 Claude Code 全局模型接口为官方默认？\n将从 settings.json 移除注入的接口地址 / Key / 模型配置。"
          confirmText="恢复"
          danger
          onCancel={() => setResetting(false)}
          onConfirm={() => void doReset()}
        />
      )}

      {/* 重启提示 */}
      {restartHint && (
        <Modal
          title="操作成功"
          onClose={() => setRestartHint('')}
          footer={
            <>
              <button className="btn" onClick={() => setRestartHint('')}>
                稍后重启
              </button>
              <button className="btn primary" onClick={() => void restartApp()}>
                立即重启
              </button>
            </>
          }
        >
          <div style={{ whiteSpace: 'pre-wrap' }}>{`${restartHint}\n\n重启 CCGUI 后生效。`}</div>
        </Modal>
      )}
    </div>
  )
}

interface EditDialogProps {
  initial: EditState
  onClose: () => void
  onSaved: (list: ApiEndpoint[]) => void
}

/** 新增/编辑自定义接口弹窗：地址 + Key + 首选模型 + 参与路由的模型清单 */
function EditDialog({ initial, onClose, onSaved }: EditDialogProps) {
  const [form, setForm] = useState(initial)
  /** 非 null = 已拉取到模型列表，首选模型与路由清单均切换为勾选/下拉 */
  const [fetched, setFetched] = useState<ModelInfo[] | null>(null)
  const [fetching, setFetching] = useState(false)
  const [saving, setSaving] = useState(false)
  const [error, setError] = useState('')
  /** 手输模式下的路由模型清单文本（逗号/空格分隔） */
  const [modelsText, setModelsText] = useState(initial.models.join(', '))

  const set = (patch: Partial<EditState>) => setForm((f) => ({ ...f, ...patch }))
  const canSave = form.name.trim() && form.baseUrl.trim() && form.key.trim()

  const fetchModels = async () => {
    setFetching(true)
    setError('')
    try {
      setFetched(await apiInjectFetchModels(form.baseUrl, form.key))
    } catch (e) {
      setError(String(e))
    } finally {
      setFetching(false)
    }
  }

  const toggleRouteModel = (id: string) => {
    set({
      models: form.models.includes(id)
        ? form.models.filter((m) => m !== id)
        : [...form.models, id]
    })
  }

  const save = async () => {
    setSaving(true)
    setError('')
    try {
      const models = fetched
        ? form.models
        : modelsText
            .split(/[,，\s]+/)
            .map((s) => s.trim())
            .filter(Boolean)
      onSaved(
        await apiInjectSave({
          id: form.id,
          name: form.name,
          baseUrl: form.baseUrl,
          key: form.key,
          model: form.model,
          models
        })
      )
    } catch (e) {
      setError(String(e))
      setSaving(false)
    }
  }

  return (
    <Modal
      title={initial.isNew ? '新增接口' : `编辑：${initial.name}`}
      width={520}
      onClose={onClose}
      footer={
        <>
          <button className="btn" onClick={onClose}>
            取消
          </button>
          <button className="btn primary" disabled={!canSave || saving} onClick={() => void save()}>
            {saving ? '保存中…' : '保存'}
          </button>
        </>
      }
    >
      {error && <div style={{ color: 'var(--danger)', marginBottom: 8 }}>{error}</div>}
      <label className="label">名称</label>
      <input
        className="input"
        style={{ width: '100%' }}
        placeholder="例如：某某中转"
        value={form.name}
        autoFocus={initial.isNew}
        onChange={(e) => set({ name: e.target.value })}
      />
      <label className="label">接口地址（Base URL）</label>
      <input
        className="input"
        style={{ width: '100%', fontFamily: 'var(--font-mono)' }}
        placeholder="https://api.example.com"
        value={form.baseUrl}
        onChange={(e) => set({ baseUrl: e.target.value })}
      />
      <label className="label">API Key</label>
      <input
        className="input"
        style={{ width: '100%', fontFamily: 'var(--font-mono)' }}
        type="password"
        placeholder="sk-..."
        value={form.key}
        onChange={(e) => set({ key: e.target.value })}
      />
      <label className="label">首选模型（直连注入时使用）</label>
      <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
        {fetched ? (
          <select
            className="select"
            style={{ flex: 1 }}
            value={form.model}
            onChange={(e) => set({ model: e.target.value })}
          >
            <option value="">（不指定模型）</option>
            {fetched.map((m) => (
              <option key={m.id} value={m.id}>
                {m.displayName !== m.id ? `${m.displayName}（${m.id}）` : m.id}
              </option>
            ))}
            {/* 手动填过且不在列表中的模型保留为可选项 */}
            {form.model && !fetched.some((m) => m.id === form.model) && (
              <option value={form.model}>{form.model}（手动填写）</option>
            )}
          </select>
        ) : (
          <input
            className="input"
            style={{ flex: 1, fontFamily: 'var(--font-mono)' }}
            placeholder="模型 ID，如 claude-sonnet-4-6；留空则不指定"
            value={form.model}
            onChange={(e) => set({ model: e.target.value })}
          />
        )}
        <button
          className="btn"
          disabled={fetching || !form.baseUrl.trim() || !form.key.trim()}
          onClick={() => void fetchModels()}
        >
          {fetching ? '获取中…' : '获取模型'}
        </button>
      </div>

      <label className="label" style={{ marginTop: 10 }}>
        参与路由的模型（多模型路由模式下对外提供）
      </label>
      {fetched ? (
        <div
          style={{
            maxHeight: 160,
            overflowY: 'auto',
            border: '1px solid var(--border)',
            borderRadius: 'var(--radius)',
            padding: '6px 10px'
          }}
        >
          {fetched.map((m) => (
            <label
              key={m.id}
              style={{ display: 'flex', gap: 8, alignItems: 'center', padding: '3px 0', fontSize: 13 }}
            >
              <input
                type="checkbox"
                checked={form.models.includes(m.id)}
                onChange={() => toggleRouteModel(m.id)}
              />
              <span style={{ fontFamily: 'var(--font-mono)' }}>{m.id}</span>
            </label>
          ))}
        </div>
      ) : (
        <input
          className="input"
          style={{ width: '100%', fontFamily: 'var(--font-mono)' }}
          placeholder="多个模型用逗号分隔，可留空"
          value={modelsText}
          onChange={(e) => setModelsText(e.target.value)}
        />
      )}
      {fetched && (
        <div style={{ marginTop: 6 }}>
          <button
            className="btn ghost small"
            onClick={() => {
              // 切手动输入时带上当前勾选结果，避免丢失
              setModelsText(form.models.join(', '))
              setFetched(null)
            }}
          >
            改为手动输入
          </button>
        </div>
      )}
    </Modal>
  )
}

/** 路由配置面板：路由表 CRUD + 默认接口 + 主模型 + subagent 兜底 + 代理状态与日志 */
function RouterPanel({ onClose }: { onClose: () => void }) {
  const [config, setConfig] = useState<RouterConfig | null>(null)
  const [routes, setRoutes] = useState<RouteRule[]>([])
  const [endpoints, setEndpoints] = useState<ApiEndpoint[]>([])
  const [proxy, setProxy] = useState<RouterStatus | null>(null)
  const [logs, setLogs] = useState<RequestLog[] | null>(null)
  const [showLogs, setShowLogs] = useState(false)
  const [saving, setSaving] = useState(false)
  const [error, setError] = useState('')

  useEffect(() => {
    void (async () => {
      try {
        const view = await apiInjectRouterGet()
        setConfig(view.config)
        setRoutes(view.routes)
        setEndpoints(view.endpoints)
        setProxy(view.proxy)
      } catch (e) {
        setError(String(e))
      }
    })()
  }, [])

  const loadLogs = async () => {
    try {
      setLogs(await routerLogs())
    } catch (e) {
      setError(String(e))
    }
  }

  const setCfg = (patch: Partial<RouterConfig>) => setConfig((c) => (c ? { ...c, ...patch } : c))

  const setRoute = (idx: number, patch: Partial<RouteRule>) =>
    setRoutes((rs) => rs.map((r, i) => (i === idx ? { ...r, ...patch } : r)))

  const addRoute = () =>
    setRoutes((rs) => [
      ...rs,
      {
        id: `r${Date.now().toString(36)}${rs.length}`,
        alias: '',
        endpointId: endpoints[0]?.id ?? '',
        model: ''
      }
    ])

  const save = async () => {
    if (!config) return
    setSaving(true)
    setError('')
    try {
      await apiInjectRouterSave(config, routes)
      onClose()
    } catch (e) {
      setError(String(e))
      setSaving(false)
    }
  }

  /** 路由条目可选的真实模型候选（所选接口的 models 清单） */
  const modelCandidates = (endpointId: string) =>
    endpoints.find((e) => e.id === endpointId)?.models ?? []

  const epName = (id: string) => endpoints.find((e) => e.id === id)?.name ?? '（已删除）'

  return (
    <Modal
      title="多模型路由 · 配置"
      width={760}
      onClose={onClose}
      footer={
        <>
          <button className="btn" onClick={onClose}>
            取消
          </button>
          <button
            className="btn primary"
            disabled={!config || saving}
            onClick={() => void save()}
          >
            {saving ? '保存中…' : '保存配置'}
          </button>
        </>
      }
    >
      {error && <div style={{ color: 'var(--danger)', marginBottom: 8 }}>{error}</div>}
      {!config ? (
        <div className="empty-hint">读取中…</div>
      ) : (
        <>
          {/* 代理状态行 */}
          <div style={{ fontSize: 12, color: 'var(--text-dim)', marginBottom: 12 }}>
            代理状态：
            {proxy?.running ? (
              <span style={{ color: 'var(--accent)' }}>运行中 · 127.0.0.1:{proxy.port}</span>
            ) : (
              '未运行（首次注入路由时自动启动）'
            )}
            <span style={{ marginLeft: 12 }}>
              端口 {config.port}（冲突自动更换） · 占位 token 系统生成
            </span>
          </div>

          {/* 路由表 */}
          <div style={{ fontWeight: 600, marginBottom: 6 }}>路由表（对外模型名 → 接口 · 真实模型）</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginBottom: 8 }}>
            {routes.length === 0 && (
              <div className="empty-hint">还没有路由条目，点击下方「添加路由」</div>
            )}
            {routes.map((r, idx) => {
              const reserved = RESERVED_ALIASES.includes(r.alias.trim().toLowerCase())
              return (
                <div key={r.id} style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
                  <input
                    className="input"
                    style={{
                      width: 180,
                      fontFamily: 'var(--font-mono)',
                      borderColor: reserved ? 'var(--danger)' : undefined
                    }}
                    placeholder="对外模型名"
                    value={r.alias}
                    onChange={(e) => setRoute(idx, { alias: e.target.value })}
                  />
                  <select
                    className="select"
                    style={{ width: 150 }}
                    value={r.endpointId}
                    onChange={(e) => setRoute(idx, { endpointId: e.target.value, model: '' })}
                  >
                    {endpoints.map((ep) => (
                      <option key={ep.id} value={ep.id}>
                        {ep.name}
                      </option>
                    ))}
                    {!endpoints.some((e) => e.id === r.endpointId) && (
                      <option value={r.endpointId}>（已删除）</option>
                    )}
                  </select>
                  <input
                    className="input"
                    style={{ flex: 1, fontFamily: 'var(--font-mono)' }}
                    placeholder="真实模型名"
                    value={r.model}
                    list={`route-models-${r.id}`}
                    onChange={(e) => setRoute(idx, { model: e.target.value })}
                  />
                  <datalist id={`route-models-${r.id}`}>
                    {modelCandidates(r.endpointId).map((m) => (
                      <option key={m} value={m} />
                    ))}
                  </datalist>
                  <button
                    className="btn small danger"
                    title="删除"
                    onClick={() => {
                      const removed = routes[idx]
                      setRoutes((rs) => rs.filter((_, i) => i !== idx))
                      // 主模型/兜底模型指向被删条目时一并清空，避免悬空引用
                      if (config.mainAlias === removed.alias) setCfg({ mainAlias: '' })
                      if (config.subagentModel === removed.alias) setCfg({ subagentModel: '' })
                    }}
                  >
                    <IconTrash />
                  </button>
                </div>
              )
            })}
            {reservedHint(routes)}
          </div>
          <div style={{ marginBottom: 14 }}>
            <button className="btn" onClick={addRoute} disabled={endpoints.length === 0}>
              <IconPlus />
              添加路由
            </button>
            {endpoints.length === 0 && (
              <span style={{ marginLeft: 8, fontSize: 12, color: 'var(--text-faint)' }}>
                请先新增至少一个自定义接口
              </span>
            )}
          </div>

          {/* 全局项 */}
          <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
            <div style={{ flex: '1 1 200px' }}>
              <label className="label">默认接口（未命中路由时透传）</label>
              <select
                className="select"
                style={{ width: '100%' }}
                value={config.defaultEndpointId}
                onChange={(e) => setCfg({ defaultEndpointId: e.target.value })}
              >
                <option value="">（未选择）</option>
                {endpoints.map((ep) => (
                  <option key={ep.id} value={ep.id}>
                    {ep.name}
                  </option>
                ))}
              </select>
            </div>
            <div style={{ flex: '1 1 200px' }}>
              <label className="label">主模型（注入后新会话默认使用）</label>
              <select
                className="select"
                style={{ width: '100%' }}
                value={config.mainAlias}
                onChange={(e) => setCfg({ mainAlias: e.target.value })}
              >
                <option value="">（未选择）</option>
                {routes
                  .filter((r) => r.alias.trim())
                  .map((r) => (
                    <option key={r.id} value={r.alias}>
                      {r.alias}（{epName(r.endpointId)}）
                    </option>
                  ))}
              </select>
            </div>
            <div style={{ flex: '1 1 200px' }}>
              <label className="label">subagent 兜底模型（可留空）</label>
              <input
                className="input"
                style={{ width: '100%', fontFamily: 'var(--font-mono)' }}
                placeholder="所有 subagent 默认模型"
                value={config.subagentModel}
                list="subagent-model-candidates"
                onChange={(e) => setCfg({ subagentModel: e.target.value })}
              />
              <datalist id="subagent-model-candidates">
                {routes
                  .filter((r) => r.alias.trim())
                  .map((r) => (
                    <option key={r.id} value={r.alias} />
                  ))}
              </datalist>
            </div>
          </div>
          <div style={{ fontSize: 12, color: 'var(--text-faint)', margin: '8px 0 14px' }}>
            优先级：subagent 兜底 &gt; agent 定义的 model 字段 &gt; 主模型。对外模型名不要用
            sonnet / opus / haiku / fable（CLI 会抢先解析为官方模型）。
          </div>

          {/* 请求日志 */}
          <div style={{ borderTop: '1px solid var(--border)', paddingTop: 10 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <button
                className="btn ghost small"
                onClick={() => {
                  const next = !showLogs
                  setShowLogs(next)
                  if (next) void loadLogs()
                }}
              >
                {showLogs ? '收起请求日志' : `请求日志（${proxy?.logCount ?? 0}）`}
              </button>
              {showLogs && (
                <button className="btn ghost small" onClick={() => void loadLogs()}>
                  刷新
                </button>
              )}
            </div>
            {showLogs && (
              <div style={{ maxHeight: 220, overflowY: 'auto', marginTop: 8 }}>
                {!logs?.length ? (
                  <div className="empty-hint">暂无请求</div>
                ) : (
                  <table style={{ width: '100%', fontSize: 12, borderCollapse: 'collapse' }}>
                    <thead>
                      <tr style={{ textAlign: 'left', color: 'var(--text-faint)' }}>
                        <th style={{ padding: '4px 6px' }}>时间</th>
                        <th style={{ padding: '4px 6px' }}>请求模型</th>
                        <th style={{ padding: '4px 6px' }}>路由到</th>
                        <th style={{ padding: '4px 6px' }}>实际模型</th>
                        <th style={{ padding: '4px 6px' }}>状态</th>
                        <th style={{ padding: '4px 6px' }}>耗时</th>
                      </tr>
                    </thead>
                    <tbody>
                      {logs.map((l, i) => (
                        <tr key={i} style={{ borderTop: '1px solid var(--border)' }}>
                          <td style={{ padding: '4px 6px', fontFamily: 'var(--font-mono)' }}>
                            {l.ts.slice(11, 19)}
                          </td>
                          <td style={{ padding: '4px 6px', fontFamily: 'var(--font-mono)' }}>
                            {l.modelIn || '-'}
                          </td>
                          <td style={{ padding: '4px 6px' }}>{l.routedTo}</td>
                          <td style={{ padding: '4px 6px', fontFamily: 'var(--font-mono)' }}>
                            {l.modelOut || '-'}
                          </td>
                          <td
                            style={{
                              padding: '4px 6px',
                              color:
                                l.status === 0 || l.status >= 400 ? 'var(--danger)' : undefined
                            }}
                            title={l.error || undefined}
                          >
                            {l.status || 'ERR'}
                          </td>
                          <td style={{ padding: '4px 6px' }}>{l.elapsedMs}ms</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                )}
              </div>
            )}
          </div>
        </>
      )}
    </Modal>
  )
}

/** 路由表里有保留别名时的提示行 */
function reservedHint(routes: RouteRule[]) {
  const hit = routes.find((r) => RESERVED_ALIASES.includes(r.alias.trim().toLowerCase()))
  if (!hit) return null
  return (
    <div style={{ fontSize: 12, color: 'var(--danger)' }}>
      「{hit.alias}」是保留别名，Claude Code 会抢先解析为官方模型，路由不会生效，请换一个名称
    </div>
  )
}
