import { useState, useEffect, useRef, useCallback } from 'react';
import { CyreneAvatar } from '@/components/persona/CyreneAvatar';
import { useAuthStore } from '@/store/authStore';
import { useChatStore } from '@/store/chatStore';
import { useSpeechSynthesis } from '@/hooks/useSpeechSynthesis';
import type { MessageAttachment, MultiMessageItem, StreamSegment, MessageDisplayType, ToolProgressInfo, ToolCall } from '@/types/chat';
import { ImageLightbox } from './ImageLightbox';
import { MarkdownRenderer } from './MarkdownRenderer';

interface MessageBubbleProps {
  id: string;
  role: 'user' | 'assistant' | 'system' | 'action';
  content: string;
  timestamp: number;
  isStreaming?: boolean;
  attachments?: MessageAttachment[];
  multiMessages?: MultiMessageItem[];
  streamSegments?: StreamSegment[];
  msgType?: MessageDisplayType;
  metadata?: Record<string, unknown>;
  audioUrl?: string;
}

/**
 * 打字机逐字显示 Hook
 * 当 isStreaming 为 true 时，逐字显示 content；当流式结束时一次性显示全部
 */
function useTypewriter(content: string, isStreaming: boolean): string {
  const [displayed, setDisplayed] = useState('');
  const prevContentRef = useRef('');
  const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);

  useEffect(() => {
    if (!isStreaming) {
      // 流式结束，直接显示全部内容
      setDisplayed(content);
      prevContentRef.current = content;
      if (timerRef.current) {
        clearInterval(timerRef.current);
        timerRef.current = null;
      }
      return;
    }

    // 如果 content 重置了（新消息），从头开始
    if (content.length < prevContentRef.current.length && content.length < displayed.length) {
      setDisplayed('');
      prevContentRef.current = '';
    }

    // 启动逐字显示定时器
    const tick = () => {
      setDisplayed((prev) => {
        if (prev.length >= content.length) {
          if (timerRef.current) {
            clearInterval(timerRef.current);
            timerRef.current = null;
          }
          return prev;
        }
        // 每次显示一个字符，遇到中文字符时多等一帧
        return content.slice(0, prev.length + 1);
      });
    };

    if (timerRef.current) {
      clearInterval(timerRef.current);
    }

    // 根据内容长度动态调整速度：短内容快，长内容稍慢
    const speed = content.length > 200 ? 15 : content.length > 100 ? 20 : 30;
    timerRef.current = setInterval(tick, speed);

    prevContentRef.current = content;

    return () => {
      if (timerRef.current) {
        clearInterval(timerRef.current);
        timerRef.current = null;
      }
    };
  }, [content, isStreaming]);

  return displayed;
}

/**
 * AI 消息的操作栏 — 包含 TTS 朗读按钮
 */
function AIMessageActions({ content }: { content: string }) {
  const { isSpeaking, isSupported, speak, stop } = useSpeechSynthesis();
  const [isThisSpeaking, setIsThisSpeaking] = useState(false);
  const contentRef = useRef(content);

  // 当全局 TTS 正在朗读且对应的是本条消息时，设置 isThisSpeaking
  useEffect(() => {
    if (!isSpeaking) {
      setIsThisSpeaking(false);
    }
  }, [isSpeaking]);

  const handleToggleTTS = useCallback(() => {
    if (isThisSpeaking) {
      stop();
      setIsThisSpeaking(false);
    } else {
      setIsThisSpeaking(true);
      speak(content, { lang: 'zh-CN' });
      // 朗读结束后重置
      const checkEnd = setInterval(() => {
        if (!window.speechSynthesis.speaking) {
          setIsThisSpeaking(false);
          clearInterval(checkEnd);
        }
      }, 200);
    }
  }, [content, isThisSpeaking, speak, stop]);

  if (!isSupported) return null;

  return (
    <div className="flex items-center gap-1 mt-1.5">
      <button
        onClick={handleToggleTTS}
        className={`inline-flex items-center gap-1 text-xs px-2 py-1 rounded-full transition-all duration-200 ${
          isThisSpeaking
            ? 'bg-pink-100 text-pink-600 tts-playing'
            : 'text-gray-400 hover:text-pink-500 hover:bg-pink-50'
        }`}
        title={isThisSpeaking ? '停止朗读' : '朗读此消息'}
      >
        {isThisSpeaking ? (
          <>
            <span className="text-sm">⏹</span>
            <span>停止</span>
          </>
        ) : (
          <>
            <span className="text-sm">🔊</span>
            <span>朗读</span>
          </>
        )}
      </button>
    </div>
  );
}

export function MessageBubble({
  id,
  role,
  content,
  timestamp,
  isStreaming,
  attachments,
  multiMessages,
  streamSegments,
  msgType,
  metadata,
  audioUrl,
}: MessageBubbleProps) {
  const isUser = role === 'user';
  const isAction = role === 'action' || msgType === 'action';
  const isThinking = msgType === 'thinking';
  const isToolProgress = msgType === 'tool_progress';
  const isSystemInfo = msgType === 'system_info';
  const isMarkdown = msgType === 'markdown';
  const isCode = msgType === 'code';

  // 动作消息使用独立的渲染方式
  if (isAction) {
    return <ActionMessageBubble content={content} timestamp={timestamp} />;
  }

  // 思考内容 — 可折叠面板
  if (isThinking) {
    return (
      <details className="mx-4 my-1 px-3 py-2 bg-gray-50 dark:bg-gray-800 rounded border border-gray-200 dark:border-gray-700 text-xs text-gray-500 dark:text-gray-400 italic">
        <summary className="cursor-pointer select-none">昔涟正在思考...</summary>
        <p className="mt-1 whitespace-pre-wrap">{content}</p>
      </details>
    );
  }

  // 工具进度 — 带进度条的紧凑行
  if (isToolProgress) {
    const tp: ToolProgressInfo | undefined = metadata?.tool_progress as ToolProgressInfo | undefined;
    const progress = tp?.progress ?? 0;
    const toolName = tp?.tool_name ?? '';
    const status = tp?.status ?? 'running';
    const statusColor =
      status === 'completed' ? 'bg-green-400' :
      status === 'failed' ? 'bg-red-400' :
      status === 'started' ? 'bg-blue-400' :
      'bg-blue-400 animate-pulse';
    const progressText = status === 'completed' ? '完成' :
      status === 'failed' ? '失败' :
      `${Math.round(progress * 100)}%`;

    return (
      <div className="flex items-center gap-2 mx-4 my-1 px-3 py-1.5 text-xs text-gray-500 dark:text-gray-400 bg-gray-50 dark:bg-gray-800/50 rounded-lg border border-gray-100 dark:border-gray-800">
        {toolName && <span className="font-medium text-gray-600 dark:text-gray-300 flex-shrink-0">{toolName}</span>}
        <div className="flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden min-w-[60px]">
          <div
            className={`h-full rounded-full transition-all duration-300 ${statusColor}`}
            style={{ width: `${Math.max(progress * 100, 2)}%` }}
          />
        </div>
        <span className="flex-shrink-0 text-[10px]">{progressText}</span>
        {content && <span className="text-gray-400 truncate hidden sm:inline">{content}</span>}
      </div>
    );
  }

  // 系统信息 — 居中 Toast 风格
  if (isSystemInfo) {
    return (
      <div className="flex justify-center my-1">
        <span className="text-xs text-gray-400 dark:text-gray-500 bg-gray-100 dark:bg-gray-800 px-3 py-1 rounded-full">
          {content}
        </span>
      </div>
    );
  }

  // 代码块 — 独立渲染，深色背景 + 语言标签
  if (isCode) {
    const lang = (metadata?.language as string) || '';
    return (
      <div className="flex px-4 py-0.5 gap-2 items-start group animate-fadeIn">
        <div className="w-8 flex-shrink-0" />
        <div className="max-w-[85%] w-full my-1 rounded-xl overflow-hidden border border-gray-200 dark:border-gray-700 bg-gray-900 dark:bg-gray-950 shadow-sm">
          {lang && (
            <div className="flex items-center justify-between px-3 py-1.5 bg-gray-800 dark:bg-gray-900 border-b border-gray-700">
              <span className="text-[10px] uppercase tracking-wider text-gray-400 font-mono">{lang}</span>
            </div>
          )}
          <pre className="px-4 py-3 overflow-x-auto">
            <code className="text-xs md:text-sm text-gray-100 font-mono leading-relaxed whitespace-pre">{content}</code>
          </pre>
        </div>
        <p className="text-[10px] text-gray-400 flex-shrink-0 hidden md:block md:opacity-0 group-hover:opacity-100 transition-opacity">
          {new Date(timestamp).toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })}
        </p>
      </div>
    );
  }

  // Markdown — 在昔涟气泡内使用 MarkdownRenderer
  if (isMarkdown) {
    const time = new Date(timestamp).toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
    return (
      <div className="flex px-4 py-2 gap-2 items-end group">
        <CyreneAvatar size="sm" className="flex-shrink-0 mb-0.5" />
        <div className="max-w-[75%] px-4 py-2.5 rounded-2xl text-sm leading-relaxed shadow-sm bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 rounded-bl-md border border-pink-100 dark:border-pink-900">
          <MarkdownRenderer content={content} />
        </div>
        <p className="text-[10px] text-gray-400 dark:text-gray-500 flex-shrink-0 mb-1 hidden md:block md:opacity-0 group-hover:opacity-100 transition-opacity duration-200">
          {time}
        </p>
      </div>
    );
  }

  const toolCalls = (metadata?.tool_calls as ToolCall[] | undefined) ?? [];
  const [lightboxIndex, setLightboxIndex] = useState<number | null>(null);
  const time = new Date(timestamp).toLocaleTimeString('zh-CN', {
    hour: '2-digit',
    minute: '2-digit',
  });

  // 流式消息使用打字机逐字显示
  const displayedContent = useTypewriter(content, !!isStreaming);
  // 判断是否还有未显示完的字符
  const hasMoreChars = isStreaming && displayedContent.length < content.length;

  // When typewriter animation finishes, notify store to process next queued message.
  const typewriterComplete = isStreaming && content.length > 0 && displayedContent.length >= content.length;
  const doneNotifiedRef = useRef(false);
  useEffect(() => {
    if (typewriterComplete && !doneNotifiedRef.current) {
      doneNotifiedRef.current = true;
      const timer = setTimeout(() => {
        useChatStore.getState().onTypewriterDone(id);
      }, 200);
      return () => clearTimeout(timer);
    }
  }, [typewriterComplete, id]);

  // 图片附件
  const imageAttachments = attachments?.filter((a) => a.type === 'image') ?? [];

  return (
    <div className={`flex px-4 py-2 gap-2 items-end group ${isUser ? 'justify-end' : ''}`}>
      {/* 用户消息：时间在左侧（气泡外侧） */}
      {isUser && !isStreaming && (
        <p className="text-[10px] text-gray-400 dark:text-gray-500 flex-shrink-0 mb-1 hidden md:block md:opacity-0 group-hover:opacity-100 transition-opacity duration-200">
          {time}
        </p>
      )}

      {/* 头像 */}
      {!isUser && (
        <CyreneAvatar size="sm" className="flex-shrink-0 mb-0.5" />
      )}

      {/* 消息气泡 */}
      <div
        className={`
          max-w-[75%] px-4 py-2.5 rounded-2xl text-sm leading-relaxed shadow-sm
          ${
            isUser
              ? 'bg-pink-400 text-white rounded-br-md'
              : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200 rounded-bl-md border border-pink-100 dark:border-pink-900'
          }
          ${isStreaming ? 'message-streaming' : ''}
        `}
      >

        {/* 多段消息渲染 (multi_message 类型) */}
        {multiMessages && multiMessages.length > 0 && !isStreaming && (
          <div className="space-y-2">
            {multiMessages
              .sort((a, b) => a.index - b.index)
              .map((item) => (
                <p key={item.index} className="whitespace-pre-wrap break-words">
                  {item.content}
                </p>
              ))}
          </div>
        )}

        {/* 流式片段渲染 (stream_segments 类型) */}
        {streamSegments && streamSegments.length > 0 && !isStreaming && (
          <div className="space-y-1.5">
            {streamSegments
              .sort((a, b) => a.index - b.index)
              .map((seg) => (
                <p key={seg.index} className="whitespace-pre-wrap break-words text-gray-600 dark:text-gray-400">
                  {seg.text}
                </p>
              ))}
          </div>
        )}

        {/* 普通文本 / 流式文本 */}
        {(!multiMessages || multiMessages.length === 0) && (!streamSegments || streamSegments.length === 0) && (
          <p className="whitespace-pre-wrap break-words">
            {isStreaming ? displayedContent : content}
            {/* 流式消息末尾闪烁光标 — 用独立 span 避免 ::after 在隐藏字符后错位 */}
            {hasMoreChars && (
              <span className="animate-streaming-cursor" />
            )}
          </p>
        )}

        {/* 音频播放器 */}
        {!isStreaming && audioUrl && (
          <div className="mt-2">
            <audio controls className="w-full max-w-[300px] h-8" src={audioUrl}>
              您的浏览器不支持音频播放
            </audio>
          </div>
        )}

        {/* 工具调用信息 */}
        {!isStreaming && toolCalls.length > 0 && (
          <ToolCallsInfo toolCalls={toolCalls} />
        )}

        {/* 图片附件网格 */}
        {!isStreaming && imageAttachments.length > 0 && (
          <div
            className={`grid gap-1.5 mt-2 ${
              imageAttachments.length === 1
                ? 'grid-cols-1'
                : imageAttachments.length === 2
                ? 'grid-cols-2'
                : 'grid-cols-3'
            }`}
          >
            {imageAttachments.map((att, idx) => (
              <ImageThumbnail
                key={idx}
                attachment={att}
                onClick={() => setLightboxIndex(idx)}
              />
            ))}
          </div>
        )}
      </div>

      {/* 昔涟消息：时间在右侧（气泡外侧） */}
      {!isUser && !isStreaming && (
        <p className="text-[10px] text-gray-400 dark:text-gray-500 flex-shrink-0 mb-1 hidden md:block md:opacity-0 group-hover:opacity-100 transition-opacity duration-200">
          {time}
        </p>
      )}

      {/* 用户头像 */}
      {isUser && <UserAvatar />}

      {/* Lightbox */}
      {lightboxIndex !== null && (
        <ImageLightbox
          attachments={imageAttachments}
          currentIndex={lightboxIndex}
          onClose={() => setLightboxIndex(null)}
        />
      )}
    </div>
  );
}

/** 动作消息气泡 — 居左，与昔涟头像对齐，灰色/斜体与聊天消息区分 */
function ActionMessageBubble({ content, timestamp }: { content: string; timestamp: number }) {
  const time = new Date(timestamp).toLocaleTimeString('zh-CN', {
    hour: '2-digit',
    minute: '2-digit',
  });

  return (
    <div className="flex px-4 py-0.5 gap-1.5 items-end group animate-fadeIn">
      <div className="w-8 flex-shrink-0" />
      <div className="max-w-[70%]">
        <p className="text-xs text-gray-400 dark:text-gray-500 italic leading-snug whitespace-pre-wrap break-words">
          {content}
        </p>
      </div>
      <p className="text-[10px] text-gray-400 dark:text-gray-500 flex-shrink-0 mb-0.5 hidden md:block md:opacity-0 group-hover:opacity-100 transition-opacity duration-200">
        {time}
      </p>
    </div>
  );
}

/** 图片缩略图组件 */
function ImageThumbnail({
  attachment,
  onClick,
}: {
  attachment: MessageAttachment;
  onClick: () => void;
}) {
  const [loaded, setLoaded] = useState(false);
  const [error, setError] = useState(false);
  const url = attachment.thumbnail_url || attachment.url;

  return (
    <button
      onClick={onClick}
      className="relative w-full aspect-square rounded-lg overflow-hidden border border-pink-100 dark:border-pink-800 bg-gray-100 dark:bg-gray-700 hover:ring-2 hover:ring-pink-400 transition-all cursor-pointer group"
      aria-label={`查看图片: ${attachment.filename || '未命名图片'}`}
    >
      {/* 加载中 */}
      {!loaded && !error && (
        <div className="absolute inset-0 flex items-center justify-center text-gray-400">
          <svg className="animate-spin h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
            <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
            <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
          </svg>
        </div>
      )}

      {/* 加载失败 */}
      {error && (
        <div className="absolute inset-0 flex items-center justify-center text-gray-400">
          <span className="text-2xl">🖼️</span>
        </div>
      )}

      {/* 图片 */}
      <img
        src={url}
        alt={attachment.filename || '图片'}
        className={`w-full h-full object-cover transition-transform group-hover:scale-105 ${loaded ? 'block' : 'hidden'}`}
        onLoad={() => setLoaded(true)}
        onError={() => setError(true)}
      />

      {/* 悬停遮罩 */}
      {loaded && (
        <div className="absolute inset-0 bg-black/0 group-hover:bg-black/20 transition-colors flex items-center justify-center">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-6 h-6 text-white opacity-0 group-hover:opacity-100 transition-opacity">
            <path fillRule="evenodd" d="M15 3.75a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0V5.56l-3.97 3.97a.75.75 0 11-1.06-1.06l3.97-3.97h-3.69a.75.75 0 010-1.5h4.5zM5.25 6.75a3 3 0 00-3 3v7.5a3 3 0 003 3h13.5a3 3 0 003-3v-7.5a3 3 0 00-3-3H15a.75.75 0 000 1.5h3.75a1.5 1.5 0 011.5 1.5v7.5a1.5 1.5 0 01-1.5 1.5H5.25a1.5 1.5 0 01-1.5-1.5v-7.5a1.5 1.5 0 011.5-1.5H9a.75.75 0 000-1.5H5.25z" clipRule="evenodd" />
          </svg>
        </div>
      )}
    </button>
  );
}

/** 工具调用信息展示 */
function ToolCallsInfo({ toolCalls }: { toolCalls: ToolCall[] }) {
  const [expanded, setExpanded] = useState(false);

  if (!toolCalls || toolCalls.length === 0) return null;

  return (
    <div className="mt-2 pt-2 border-t border-pink-100 dark:border-pink-800">
      <button
        onClick={() => setExpanded(!expanded)}
        className="flex items-center gap-1 text-[10px] text-gray-400 hover:text-pink-500 transition-colors"
      >
        <span>{expanded ? '▼' : '▶'}</span>
        <span>工具调用 ({toolCalls.length})</span>
      </button>
      {expanded && (
        <div className="mt-1.5 space-y-1.5">
          {toolCalls.map((tc, i) => (
            <div key={i} className="bg-gray-50 dark:bg-gray-900 rounded-lg p-2 text-xs">
              <div className="flex items-center gap-2">
                <span className="font-medium text-pink-500">{tc.name}</span>
                {tc.result !== undefined && (
                  <span className="text-[10px] text-green-500">
                    {typeof tc.result === 'string' && tc.result.length > 60
                      ? tc.result.slice(0, 60) + '...'
                      : JSON.stringify(tc.result).slice(0, 60)}
                  </span>
                )}
              </div>
              {tc.arguments && Object.keys(tc.arguments).length > 0 && (
                <div className="mt-1 text-gray-400 font-mono break-all">
                  {JSON.stringify(tc.arguments, null, 0).slice(0, 120)}
                </div>
              )}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

/** 用户头像组件：管理员使用 Admin_Avatar.jpg，普通用户使用 Default_Avatar.png */
function UserAvatar() {
  const [imgError, setImgError] = useState(false);
  const userId = useAuthStore((s) => s.userId);
  const isAdmin = userId === 'admin';
  const avatarSrc = isAdmin
    ? '/images/User_Avatar/Admin_Avatar.jpg'
    : '/images/User_Avatar/Default_Avatar.png';

  if (imgError) {
    return (
      <div className="w-8 h-8 rounded-full bg-gradient-to-br from-pink-300 to-pink-500 flex items-center justify-center flex-shrink-0 mt-1 shadow-sm">
        <span className="text-white text-sm">开拓者</span>
      </div>
    );
  }

  return (
    <img
      src={avatarSrc}
      alt={isAdmin ? '管理员' : '用户'}
      className="w-8 h-8 rounded-full object-cover flex-shrink-0 mt-1 shadow-sm"
      onError={() => setImgError(true)}
    />
  );
}
