/**
 * MessageContent 组件
 *
 * 渲染单条消息内容，接入 textRenderer 和 regexEngine 完成完整渲染管线：
 *  1. 调用 regexEngine.processAIOutput（需要从外部传入 regexScripts）
 *  2. 调用 textRenderer.parseRawMessage 提取特殊块（statusYaml、choices 等）
 *  3. 调用 textRenderer.renderMessageHtml 生成可渲染 HTML
 *  4. 若有 html-code-block 或 statusYaml → 渲染 <StatusBarIframe>
 *  5. 普通文本 → dangerouslySetInnerHTML
 *
 * 组件仅负责渲染，不持有业务状态（消息列表、AI 配置等）。
 */

import { useMemo, useState } from 'react'
import { Code, Eye } from 'lucide-react'
import {
  parseRawMessage,
  renderMessageHtml,
  type Choice,
} from '../lib/textRenderer'
import { processAIOutput, processUserInput } from '../lib/regexEngine'
import type { RegexScript } from '../api/regex'
import StatusBarIframe from './StatusBarIframe'

// ============= Props =============

interface MessageContentProps {
  /** 消息原始内容 */
  content: string
  /** 消息角色 */
  role: 'user' | 'assistant'
  /** 消息在对话中的索引（用于 StatusBarIframe __CURRENT_ID__） */
  messageIndex?: number
  /** ST 兼容深度（0=最新消息），用于正则脚本 minDepth/maxDepth 过滤 */
  regexDepth?: number
  /** 角色名称（变量替换 {{char}}） */
  characterName?: string
  /** 用户名称（变量替换 {{user}}） */
  userName?: string
  /** 已启用的正则脚本列表（由父组件加载并传入） */
  regexScripts?: RegexScript[]
  /** 所有消息的原始内容（用于 iframe shim 注入 __CHAT_MESSAGES__） */
  allMessages?: string[]
  /** 选择项被点击时的回调 */
  onChoiceSelect?: (choice: string) => void
  /**
   * iframe 内操作回调（透传给 StatusBarIframe）。
   * - type='fillInput'    → 仅填充输入框
   * - type='playerAction' → 仅填充输入框
   * - type='triggerAction'→ 填充并发送
   */
  onAction?: (type: 'fillInput' | 'playerAction' | 'triggerAction' | 'setChatMessage', payload: string, messageIndex?: number) => void
  /**
   * 是否处于流式传输中。
   * true  → 跳过完整渲染管线，直接显示原始文本（低延迟，实时打字效果）
   * false → 运行完整渲染管线（正则、iframe、状态栏等）
   */
  isStreaming?: boolean
}

// ============= 组件 =============

export default function MessageContent({
  content,
  role,
  messageIndex = 0,
  regexDepth,
  characterName = '',
  userName = '',
  regexScripts = [],
  allMessages = [],
  onChoiceSelect,
  onAction,
  isStreaming = false,
}: MessageContentProps) {
  const [showRaw, setShowRaw] = useState(false)

  // ---- 渲染管线（纯计算，memo 缓存） ----
  // 必须在所有条件 return 之前调用，遵守 Rules of Hooks。
  // 流式期间 isStreaming=true 时结果不会被使用，但 hook 仍需执行以保持调用顺序一致。
  const rendered = useMemo(() => {
    // Step 1: 执行正则脚本（使用 ST 兼容深度：0=最新消息）
    const depth = regexDepth ?? messageIndex
    const afterRegex =
      role === 'assistant'
        ? processAIOutput(content, regexScripts, depth)
        : processUserInput(content, regexScripts, depth)

    // Step 2: 解析特殊块
    const parsed = parseRawMessage(afterRegex)

    // Step 3a: 渲染主 bodyText → HTML（含 htmlBlocks）
    const { html: bodyHtml, htmlBlocks } = renderMessageHtml(parsed.bodyText, role, {
      index: messageIndex,
      characterName,
      userName,
    })

    // Step 3b: 若有 maintext，单独渲染
    const { html: maintextHtml } = parsed.maintext
      ? renderMessageHtml(parsed.maintext, 'assistant', { characterName, userName })
      : { html: '' }

    return { parsed, bodyHtml, htmlBlocks, maintextHtml }
  }, [content, role, messageIndex, regexDepth, characterName, userName, regexScripts])

  const { parsed, bodyHtml, htmlBlocks, maintextHtml } = rendered

  // ---- 流式传输中：所有 Hook 已执行完毕，现在可以提前返回 ----
  // 跳过完整渲染管线，直接显示原始文本（低延迟，实时打字效果）。
  // 流结束后（isStreaming=false）才切换到完整渲染路径。
  if (role === 'assistant' && isStreaming) {
    return (
      <div className="text-sm leading-relaxed whitespace-pre-wrap break-words overflow-wrap-anywhere text-white/90">
        {content}
        <span className="inline-block w-0.5 h-4 bg-white/70 ml-0.5 align-middle animate-pulse" />
      </div>
    )
  }

  const hasVisualExtras =
    parsed.statusYaml ||
    parsed.statusJson ||
    parsed.hasScript ||
    htmlBlocks.length > 0

  // ---- 用户消息：直接纯文本 ----
  if (role === 'user') {
    return (
      <p className="text-sm leading-relaxed whitespace-pre-wrap break-words overflow-wrap-anywhere">
        {content}
      </p>
    )
  }

  // ---- AI 消息 ----
  return (
    <div className="space-y-2">
      {/* 源码/渲染切换按钮 */}
      {(parsed.hasHtml || hasVisualExtras) && (
        <div className="flex items-center gap-2 mb-2">
          <button
            onClick={() => setShowRaw(v => !v)}
            className="flex items-center gap-1 px-2 py-1 text-xs glass-hover rounded cursor-pointer"
            title={showRaw ? '显示渲染' : '显示源码'}
          >
            {showRaw ? <Eye className="w-3 h-3" /> : <Code className="w-3 h-3" />}
            {showRaw ? '渲染' : '源码'}
          </button>
        </div>
      )}

      {/* 主内容区 */}
      {showRaw ? (
        /* 原始源码 */
        <pre className="text-xs bg-black/30 p-3 rounded-lg overflow-x-auto">
          <code>{content}</code>
        </pre>
      ) : (
        <>
          {/* maintext 优先作为主要叙事内容（始终显示） */}
          {parsed.maintext && (
            <div
              className="text-sm leading-relaxed break-words overflow-wrap-anywhere message-body"
              dangerouslySetInnerHTML={{ __html: maintextHtml }}
            />
          )}

          {/* bodyText 渲染区：检查 bodyHtml 本身是否非空，避免 html块清除后仍留白 */}
          {!parsed.maintext && bodyHtml.trim() && (
            <div
              className="text-sm leading-relaxed break-words overflow-wrap-anywhere message-body"
              dangerouslySetInnerHTML={{ __html: bodyHtml }}
            />
          )}

          {/* HTML code blocks → StatusBarIframe */}
          {htmlBlocks.map((html, i) => (
            <StatusBarIframe
              key={`html-block-${i}`}
              rawMessage={content}
              allMessages={allMessages}
              messageIndex={messageIndex}
              htmlContent={html}
              statusYaml={parsed.statusYaml}
              minHeight={400}
              onAction={onAction}
            />
          ))}

          {/* YAML 状态栏（无 html-code-block 时单独显示） */}
          {parsed.statusYaml && htmlBlocks.length === 0 && (
            <StatusBarIframe
              rawMessage={content}
              allMessages={allMessages}
              messageIndex={messageIndex}
              statusYaml={parsed.statusYaml}
              minHeight={200}
              onAction={onAction}
            />
          )}

          {/* 旧版 JSON 状态面板（兼容） */}
          {parsed.statusJson && !parsed.statusYaml && (
            <JsonStatusPanel data={parsed.statusJson} />
          )}
        </>
      )}

      {/* 选择项按钮 */}
      {parsed.choices.length > 0 && onChoiceSelect && (
        <ChoiceList choices={parsed.choices} onSelect={onChoiceSelect} />
      )}
    </div>
  )
}

// ============= 子组件 =============

/** 选择项按钮列表 */
function ChoiceList({
  choices,
  onSelect,
}: {
  choices: Choice[]
  onSelect: (text: string) => void
}) {
  return (
    <div className="mt-4 p-4 glass rounded-lg border border-primary/20">
      <div className="text-sm font-medium text-primary mb-3">请选择以下选项之一</div>
      <div className="space-y-2">
        {choices.map(choice => (
          <button
            key={choice.label}
            onClick={() => onSelect(choice.text)}
            className="w-full text-left px-4 py-3 glass-hover rounded-lg border border-white/10 hover:border-primary/50 transition-all group"
          >
            <span className="text-primary font-bold mr-2">{choice.label}.</span>
            <span className="text-white/80 group-hover:text-white">{choice.text}</span>
          </button>
        ))}
      </div>
    </div>
  )
}

/** 旧版 JSON 状态面板（向后兼容） */
function JsonStatusPanel({ data }: { data: Record<string, unknown> }) {
  return (
    <div className="mt-4 p-4 glass rounded-lg border border-secondary/20">
      <div className="text-sm font-medium text-secondary mb-3">状态面板</div>
      <div className="space-y-3">
        {Object.entries(data).map(([category, val]) => (
          <div key={category} className="space-y-1">
            <div className="text-xs font-semibold text-secondary/80">{category}</div>
            <div className="pl-3 space-y-1">
              {typeof val === 'object' && val !== null ? (
                Object.entries(val as Record<string, unknown>).map(([k, v]) => (
                  <div key={k} className="flex justify-between text-xs">
                    <span className="text-white/60">{k}:</span>
                    <span className="text-white/90 font-medium">
                      {typeof v === 'object' ? JSON.stringify(v) : String(v)}
                    </span>
                  </div>
                ))
              ) : (
                <div className="text-xs text-white/90">{String(val)}</div>
              )}
            </div>
          </div>
        ))}
      </div>
    </div>
  )
}
