import type React from 'react'

/**
 * H5 主题契约（P2 可定制化）。
 *
 * 设计目标：让对接 APP 能注入品牌色覆盖 H5 对话页的默认深色主题。
 *
 * 契约层次（优先级从高到低）：
 *   1. 注入的 H5Theme（通过 forge_h5_theme cookie，由入口路由从 app_secrets[iss].theme 读取）
 *   2. DEFAULT_H5_THEME（本文件常量，与 src/app/h5/layout.tsx 的 --h5-* 默认值一致）
 *   3. 永不回退到宿主 Forge token
 *
 * 可覆盖字段仅限颜色 + 字体——这些是"品牌"维度。
 * 圆角/字号/间距不放进来：它们是"布局一致性"维度，应由 DESIGN.md 固定，
 * 不允许对接 APP 改（否则对话气泡/输入框的形态会失控）。
 *
 * 存储：app_secrets JSON 里每个 APP 一个可选 theme 字段。
 * 传输：入口路由 set forge_h5_theme cookie（2h，与身份同步过期）。
 * 应用：H5ClientApp mount 时把 theme 写到 :root.style 覆盖 layout 默认值。
 */

/**
 * 可定制主题字段。所有字段可选——未提供的字段用 DEFAULT_H5_THEME 兜底。
 *
 * UI 初版只暴露 accent/bg/text 三个（覆盖 90% 品牌需求），
 * 但 schema 完整定义所有颜色，后续 UI 可逐步开放。
 */
export interface H5Theme {
  /** 语义标记（仅用于 owner 端归类，不影响渲染——渲染完全由颜色值决定） */
  mode?: 'dark' | 'light'
  /** 页面背景 */
  bg?: string
  /** 卡片/气泡表面 */
  surface?: string
  /** 表面悬停态 */
  surfaceHover?: string
  /** 表面激活态（如 active session 项底色由 accent 决定，这里指其他激活态） */
  surfaceActive?: string
  /** 主边框 */
  border?: string
  /** 次边框 */
  borderSubtle?: string
  /** 主文字 */
  text?: string
  /** 次文字 */
  textSecondary?: string
  /** 弱文字 */
  textMuted?: string
  /** 品牌强调色（气泡、按钮、链接、聚焦边框） */
  accent?: string
  /** 强调色悬停 */
  accentHover?: string
  /** 强调色上的文字 */
  onAccent?: string
  /** 成功语义色 */
  success?: string
  /** 警告语义色 */
  warning?: string
  /** 错误语义色 */
  error?: string
  /** 正文字体族（含 fallback）。不设置则用 layout 默认系统字体栈。 */
  fontBody?: string
  /** 等宽字体族（代码块、行内 code）。不设置则用 layout 默认系统等宽栈。 */
  fontMono?: string
  /** 标题字体族（顶栏、空状态、大标题）。不设置则用 body 字体兜底。 */
  fontHeading?: string
  /** 对话阅读字体（assistant 正文、用户消息、输入草稿）。不设置则用 body 字体兜底。 */
  fontConversation?: string
  /** 对话正文字号（如 "17px"）。不设置则用 layout 默认值。 */
  fontSizeConversation?: string
  /** 对话正文行高（如 "1.7"）。不设置则用 layout 默认值。 */
  lineHeightConversation?: string
  /** 阅读栏宽度（如 "680px"）。不设置则用 layout 默认值。 */
  readWidth?: string
  /** 用户消息背景。未设置时回退 accent，兼容传统气泡主题。 */
  userMessageBg?: string
  /** 用户消息文字。未设置时回退 onAccent。 */
  userMessageText?: string
  /** 输入胶囊背景。未设置时回退 surface。 */
  composerBg?: string
  /** 圆形控件底色。未设置时回退 surfaceHover。 */
  controlBg?: string
  /** 对话正文颜色。未设置时回退 text。 */
  conversationText?: string
  /** 消息气泡圆角（如 "16px"）。不设置则用 layout 默认值。 */
  radiusBubble?: string
  /** 输入框圆角（如 "16px"）。不设置则用 layout 默认值。 */
  radiusInput?: string
}

/**
 * 默认主题（深色）。
 * 必须与 src/app/h5/layout.tsx 里 H5_ROOT_CSS 的 --h5-* 默认值保持一致。
 * 修改任一处时同步另一处。
 */
export const DEFAULT_H5_THEME: Required<H5Theme> = {
  mode: 'dark',
  bg: '#0a0a0a',
  surface: '#1a1a1a',
  surfaceHover: '#1f1f1f',
  surfaceActive: '#252525',
  border: '#2a2a2a',
  borderSubtle: '#1a1a1a',
  text: '#ffffff',
  textSecondary: '#999999',
  textMuted: '#6c6c6c',
  accent: '#6366f1',
  accentHover: '#5558e3',
  onAccent: '#ffffff',
  success: '#22c55e',
  warning: '#f59e0b',
  error: '#ef4444',
  // 字体需与 src/app/h5/layout.tsx 的 --h5-font-* 默认值保持一致。
  fontBody:
    "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif",
  fontMono:
    "'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
  fontHeading:
    "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif",
  fontConversation: '',
  fontSizeConversation: '',
  lineHeightConversation: '',
  readWidth: '',
  userMessageBg: '',
  userMessageText: '',
  composerBg: '',
  controlBg: '',
  conversationText: '',
  radiusBubble: '',
  radiusInput: '',
}

/**
 * 合并主题：override 的非空字段覆盖 base，其余用 base。
 * mode 字段特殊处理：override.mode 仅作语义标记，不参与渲染，
 * 但为方便 owner 端归类仍合并传递。
 */
export function mergeTheme(base: Required<H5Theme>, override: H5Theme | null | undefined): Required<H5Theme> {
  if (!override) return base
  return {
    mode: override.mode ?? base.mode,
    bg: override.bg ?? base.bg,
    surface: override.surface ?? base.surface,
    surfaceHover: override.surfaceHover ?? base.surfaceHover,
    surfaceActive: override.surfaceActive ?? base.surfaceActive,
    border: override.border ?? base.border,
    borderSubtle: override.borderSubtle ?? base.borderSubtle,
    text: override.text ?? base.text,
    textSecondary: override.textSecondary ?? base.textSecondary,
    textMuted: override.textMuted ?? base.textMuted,
    accent: override.accent ?? base.accent,
    accentHover: override.accentHover ?? base.accentHover,
    onAccent: override.onAccent ?? base.onAccent,
    success: override.success ?? base.success,
    warning: override.warning ?? base.warning,
    error: override.error ?? base.error,
    fontBody: override.fontBody ?? base.fontBody,
    fontMono: override.fontMono ?? base.fontMono,
    fontHeading: override.fontHeading ?? base.fontHeading,
    fontConversation: override.fontConversation ?? base.fontConversation,
    fontSizeConversation: override.fontSizeConversation ?? base.fontSizeConversation,
    lineHeightConversation: override.lineHeightConversation ?? base.lineHeightConversation,
    readWidth: override.readWidth ?? base.readWidth,
    userMessageBg: override.userMessageBg ?? base.userMessageBg,
    userMessageText: override.userMessageText ?? base.userMessageText,
    composerBg: override.composerBg ?? base.composerBg,
    controlBg: override.controlBg ?? base.controlBg,
    conversationText: override.conversationText ?? base.conversationText,
    radiusBubble: override.radiusBubble ?? base.radiusBubble,
    radiusInput: override.radiusInput ?? base.radiusInput,
  }
}

/** H5Theme 字段名 → CSS 变量名映射（驼峰 → kebab） */
const THEME_TO_CSS_VAR: Record<keyof Required<H5Theme>, string> = {
  mode: '--h5-mode',
  bg: '--h5-bg',
  surface: '--h5-surface',
  surfaceHover: '--h5-surface-hover',
  surfaceActive: '--h5-surface-active',
  border: '--h5-border',
  borderSubtle: '--h5-border-subtle',
  text: '--h5-text',
  textSecondary: '--h5-text-secondary',
  textMuted: '--h5-text-muted',
  accent: '--h5-accent',
  accentHover: '--h5-accent-hover',
  onAccent: '--h5-on-accent',
  success: '--h5-success',
  warning: '--h5-warning',
  error: '--h5-error',
  fontBody: '--h5-font-body',
  fontMono: '--h5-font-mono',
  fontHeading: '--h5-font-heading',
  fontConversation: '--h5-font-conversation',
  fontSizeConversation: '--h5-fs-conversation',
  lineHeightConversation: '--h5-lh-conversation',
  readWidth: '--h5-read-width',
  userMessageBg: '--h5-user-message-bg',
  userMessageText: '--h5-user-message-text',
  composerBg: '--h5-composer-bg',
  controlBg: '--h5-control-bg',
  conversationText: '--h5-conversation-text',
  radiusBubble: '--h5-radius-bubble',
  radiusInput: '--h5-radius-input',
}

/**
 * 把 H5Theme（相对默认值的 override 部分）转为一组 CSS 自定义属性声明，
 * 用于注入到 :root 覆盖 layout 默认值。
 *
 * 只输出非空字段，避免用 undefined 覆盖已有默认值。
 * mode 不是 CSS 变量，跳过。
 */
export function themeToCssVars(theme: H5Theme): string {
  const lines: string[] = []
  for (const [key, value] of Object.entries(theme)) {
    if (key === 'mode') continue
    if (typeof value === 'string' && value.length > 0) {
      const cssVar = THEME_TO_CSS_VAR[key as keyof Required<H5Theme>]
      lines.push(`${cssVar}: ${value};`)
    }
  }
  return lines.join('\n  ')
}

/**
 * 把 H5Theme 转为 React.CSSProperties（inline style 形式的 CSS 变量）。
 * 用于直接写到容器元素的 style 属性——inline style 特异性最高（1,0,0,0），
 * 压过 layout 的 <style> 规则，避免层叠冲突。
 * 未设置的字段不写入（让 layout 默认值兜底）。
 */
export function themeToInlineStyle(theme: H5Theme | null | undefined): React.CSSProperties {
  if (!theme) return {}
  const style: Record<string, string> = {}
  for (const [key, value] of Object.entries(theme)) {
    if (key === 'mode') continue
    if (typeof value === 'string' && value.length > 0) {
      const cssVar = THEME_TO_CSS_VAR[key as keyof Required<H5Theme>]
      style[cssVar] = value
    }
  }
  return style as React.CSSProperties
}

/**
 * 序列化 H5Theme 为 cookie 值（紧凑 JSON，去掉空字段）。
 * 失败回退空字符串（表示"无主题覆盖"，前端用默认值）。
 */
export function serializeTheme(theme: H5Theme | null | undefined): string {
  if (!theme) return ''
  const compact: Record<string, string> = {}
  for (const [key, value] of Object.entries(theme)) {
    if (key === 'mode') {
      if (value) compact.mode = value
      continue
    }
    if (typeof value === 'string' && value.length > 0) {
      compact[key] = value
    }
  }
  if (Object.keys(compact).length === 0) return ''
  return JSON.stringify(compact)
}

/**
 * 从 cookie 值反序列化 H5Theme。
 * 非法 JSON / 非对象 → 返回 null（前端用默认值）。
 */
export function deserializeTheme(cookieValue: string | null | undefined): H5Theme | null {
  if (!cookieValue) return null
  try {
    const parsed = JSON.parse(cookieValue) as Record<string, unknown>
    if (!parsed || typeof parsed !== 'object') return null
    const theme: H5Theme = {}
    for (const [key, value] of Object.entries(parsed)) {
      if (key === 'mode' && (value === 'dark' || value === 'light')) {
        theme.mode = value
      } else if (typeof value === 'string' && value.length > 0) {
        // 只接受字符串值，防注入（CSS var 值里塞 `;` 之类）
        ;(theme as Record<string, unknown>)[key] = value
      }
    }
    return Object.keys(theme).length > 0 ? theme : null
  } catch {
    return null
  }
}
