import React, { useEffect, useRef, useState } from 'react';
import { loadXmovSDK } from '../utils/sdkLoader';
import { getXmovConfig, isXmovConfigValid } from '../services/xmovConfig';
import { WebSocketService, WebSocketMessage } from '../services/websocketService';
import type { XmovAvatarSDK } from '../types/xmov';

interface XmovAvatarProps {
  isActive?: boolean;
  websocketUrl?: string;
  onSDKReady?: () => void;
  onSDKError?: (error: any) => void;
  onSpeaking?: (isSpeaking: boolean) => void;
  onSDKStatusChange?: (status: 'loading' | 'ready' | 'error' | 'config-missing') => void;
  onWSStatusChange?: (status: 'disconnected' | 'connecting' | 'connected') => void;
  onLogMessage?: (message: string) => void;
}

/**
 * Xmov 数字人组件
 * 连接到 WebSocket (10002端口) 接收消息驱动数字人说话
 * 与 XmovAvatarSDK 原项目保持一致
 */
export const XmovAvatar: React.FC<XmovAvatarProps> = ({
  isActive: _isActive = false,
  websocketUrl = 'ws://127.0.0.1:10002',
  onSDKReady,
  onSDKError,
  onSpeaking,
  onSDKStatusChange,
  onWSStatusChange,
  onLogMessage,
}) => {
  const containerRef = useRef<HTMLDivElement>(null);
  const sdkRef = useRef<XmovAvatarSDK | null>(null);
  const wsServiceRef = useRef<WebSocketService | null>(null);
  const [sdkStatus, setSDKStatus] = useState<'loading' | 'ready' | 'error' | 'config-missing'>('loading');
  const [wsStatus, setWsStatus] = useState<'disconnected' | 'connecting' | 'connected'>('disconnected');
  const [errorMessage, setErrorMessage] = useState<string>('');
  const [loadingProgress, setLoadingProgress] = useState<number>(0);
  const isConversationActiveRef = useRef<boolean>(false); // 追踪当前对话是否在进行中
  const hasSpeakStartedRef = useRef<boolean>(false); // 追踪当前对话是否已开始播放（用于处理 think 标签后的第一次播放）
  const isThinkingRef = useRef<boolean>(false); // 追踪是否正在思考中（<think> 和 </think> 之间）
  const conversationTimeoutRef = useRef<number | null>(null); // 对话超时定时器

  // 使用 ref 保存最新的回调函数，避免触发 useEffect 重新执行
  const onSDKReadyRef = useRef(onSDKReady);
  const onSDKErrorRef = useRef(onSDKError);
  const onSpeakingRef = useRef(onSpeaking);
  const onSDKStatusChangeRef = useRef(onSDKStatusChange);
  const onWSStatusChangeRef = useRef(onWSStatusChange);

  useEffect(() => {
    onSDKReadyRef.current = onSDKReady;
    onSDKErrorRef.current = onSDKError;
    onSpeakingRef.current = onSpeaking;
    onSDKStatusChangeRef.current = onSDKStatusChange;
    onWSStatusChangeRef.current = onWSStatusChange;
  });

  // 当状态变化时通知父组件
  useEffect(() => {
    onSDKStatusChangeRef.current?.(sdkStatus);
  }, [sdkStatus]);

  useEffect(() => {
    onWSStatusChangeRef.current?.(wsStatus);
  }, [wsStatus]);

  useEffect(() => {
    let mounted = true;
    let initTimeout: number | null = null;

    const initializeSDK = async () => {
      try {
        // 检查配置
        const config = getXmovConfig();
        if (!isXmovConfigValid(config)) {
          console.error('[xmov] 配置无效');
          setSDKStatus('config-missing');
          setErrorMessage('请配置 XMOV_APP_ID 和 XMOV_APP_SECRET');
          return;
        }

        // 加载 SDK
        console.log('[xmov] 正在加载SDK...');
        await loadXmovSDK();

        if (!mounted) return;

        // 创建 SDK 实例
        console.log('[xmov] 正在创建SDK实例...');
        const containerId = `xmov-container-${Date.now()}`;
        if (containerRef.current) {
          containerRef.current.id = containerId;
        }

        initTimeout = window.setTimeout(() => {
          console.error('[xmov] SDK初始化超时');
          setSDKStatus('error');
          setErrorMessage('SDK初始化超时');
          onSDKErrorRef.current?.(new Error('SDK initialization timeout'));
        }, 30000);

        const sdk = new window.XmovAvatar({
          containerId: `#${containerId}`,
          appId: config.appId,
          appSecret: config.appSecret,
          gatewayServer: config.gatewayServer || 'https://nebula-agent.xingyun3d.com/user/v1/ttsa/session',

          onWidgetEvent(data: any) {
            console.log('[xmov] Widget事件:', data);
          },

          onNetworkInfo(networkInfo: any) {
            console.log('[xmov] 网络信息:', networkInfo);
          },

          onMessage(message: any) {
            console.log('[xmov] 📩 SDK消息:', message);
            // 检查是否有音频相关的消息
            if (message && typeof message === 'object') {
              if (message.type === 'audio' || message.audio) {
                console.log('[xmov] 🔊 收到音频消息:', message);
              }
            }
          },

          onStateChange(state: string) {
            console.log('[xmov] 状态变化:', state);
          },

          onStatusChange(status: string) {
            console.log('[xmov] SDK状态:', status);
          },

          onStateRenderChange(state: string, duration: number) {
            console.log('[xmov] 渲染状态:', state, duration);
          },

          onVoiceStateChange(status: 'start' | 'end') {
            console.log('[xmov] 🎵 音频状态变化:', status);
            if (status === 'start') {
              console.log('[xmov] 🎵 数字人开始说话');
              onSpeakingRef.current?.(true);
            } else if (status === 'end') {
              console.log('[xmov] 🎵 数字人结束说话');
              onSpeakingRef.current?.(false);
            }
          },

          enableLogger: true,
        });

        sdkRef.current = sdk;

        // 初始化 SDK
        await sdk.init({
          onDownloadProgress: (progress: number) => {
            console.log('[xmov] 加载资源:', progress + '%');
            setLoadingProgress(progress);
          },
          onError: (error: any) => {
            console.error('[xmov] SDK错误:', error);
            if (initTimeout) clearTimeout(initTimeout);
            setSDKStatus('error');
            setErrorMessage('SDK初始化失败');
            onSDKErrorRef.current?.(error);
          },
          onClose: () => {
            console.log('[xmov] SDK连接关闭');
          },
        });

        if (!mounted) return;

        if (initTimeout) clearTimeout(initTimeout);
        console.log('[xmov] SDK初始化成功');

        // 检查音频上下文状态
        console.log('[xmov] 🔊 检查浏览器音频支持...');
        if (typeof AudioContext !== 'undefined' || typeof (window as any).webkitAudioContext !== 'undefined') {
          console.log('[xmov] ✅ 浏览器支持 Web Audio API');

          // 检查自动播放策略
          const checkAutoplay = async () => {
            try {
              const AudioContextClass = (window as any).AudioContext || (window as any).webkitAudioContext;
              const audioCtx = new AudioContextClass();
              console.log('[xmov] 🔊 AudioContext 状态:', audioCtx.state);

              if (audioCtx.state === 'suspended') {
                console.warn('[xmov] ⚠️ AudioContext 被暂停，尝试恢复...');
                await audioCtx.resume();
                console.log('[xmov] ✅ AudioContext 已恢复');
              }
              audioCtx.close();
            } catch (error) {
              console.error('[xmov] ❌ AudioContext 检查失败:', error);
            }
          };
          checkAutoplay();
        } else {
          console.error('[xmov] ❌ 浏览器不支持 Web Audio API');
        }

        setSDKStatus('ready');
        onSDKReadyRef.current?.();

        // 检查SDK实例的所有方法和属性
        console.log('[xmov] 🔍 SDK实例方法:', Object.getOwnPropertyNames(Object.getPrototypeOf(sdk)));
        console.log('[xmov] 🔍 SDK实例属性:', Object.keys(sdk));

        // 暴露SDK实例到全局，方便在控制台调试
        (window as any).xmovSDK = sdk;
        console.log('[xmov] 💡 SDK实例已暴露到 window.xmovSDK，可在控制台检查');

        // 暴露测试函数到全局，方便调试
        (window as any).testXmovSpeak = (text: string = '你好，这是测试') => {
          console.log('[xmov] 🧪 测试speak功能:', text);
          if (sdkRef.current) {
            console.log('[xmov] 🧪 SDK实例存在，调用speak...');
            try {
              sdkRef.current.speak(text, true, true);
              console.log('[xmov] 🧪 speak调用完成');
            } catch (error) {
              console.error('[xmov] 🧪 speak调用失败:', error);
            }
          } else {
            console.error('[xmov] 🧪 SDK实例不存在');
          }
        };
        console.log('[xmov] 💡 提示：在控制台输入 testXmovSpeak("测试文字") 来测试音频播放');

        // SDK 就绪后，连接 WebSocket
        connectWebSocket();
      } catch (error) {
        console.error('[xmov] 初始化错误:', error);
        if (initTimeout) clearTimeout(initTimeout);
        if (mounted) {
          setSDKStatus('error');
          setErrorMessage(error instanceof Error ? error.message : '未知错误');
          onSDKErrorRef.current?.(error);
        }
      }
    };

    const connectWebSocket = () => {
      if (wsServiceRef.current) {
        wsServiceRef.current.disconnect();
      }

      wsServiceRef.current = new WebSocketService({
        url: websocketUrl,
        onConnect: () => {
          setWsStatus('connected');
        },
        onDisconnect: () => {
          setWsStatus('disconnected');
        },
        onError: () => {
          setWsStatus('disconnected');
        },
        onMessage: (message: WebSocketMessage) => {
          handleWebSocketMessage(message);
        },
      });

      setWsStatus('connecting');
      wsServiceRef.current.connect();
    };

    // 清除对话超时定时器
    const clearConversationTimeout = () => {
      if (conversationTimeoutRef.current) {
        clearTimeout(conversationTimeoutRef.current);
        conversationTimeoutRef.current = null;
        console.log('[xmov] ⏱️ 清除对话超时定时器');
      }
    };

    // 设置对话超时定时器（30秒无消息自动结束）
    const resetConversationTimeout = () => {
      clearConversationTimeout();

      if (isConversationActiveRef.current && hasSpeakStartedRef.current) {
        conversationTimeoutRef.current = window.setTimeout(() => {
          console.warn('[xmov] ⏰ 对话超时，30秒未收到结束信号，强制结束对话');
          if (sdkRef.current && hasSpeakStartedRef.current) {
            try {
              sdkRef.current.speak(' ', false, true);
              console.log('[xmov] ✅ 已发送超时结束信号');
            } catch (error) {
              console.error('[xmov] ❌ 发送超时结束信号失败:', error);
            }
          }
          isConversationActiveRef.current = false;
          hasSpeakStartedRef.current = false;
          isThinkingRef.current = false;
        }, 30000); // 30秒超时
        console.log('[xmov] ⏱️ 设置对话超时定时器（30秒）');
      }
    };

    // 确保 AudioContext 处于运行状态（修复iOS和浏览器自动播放策略问题）
    const ensureAudioContextRunning = async () => {
      try {
        if (typeof AudioContext === 'undefined' && typeof (window as any).webkitAudioContext === 'undefined') {
          console.warn('[xmov] ⚠️ 浏览器不支持 AudioContext');
          return;
        }

        const AudioContextClass = (window as any).AudioContext || (window as any).webkitAudioContext;
        // 尝试获取全局的 audioContext（如果SDK暴露了的话）
        const audioCtx = (window as any).audioContext || new AudioContextClass();

        if (audioCtx.state === 'suspended') {
          console.warn('[xmov] ⚠️ AudioContext 处于暂停状态，尝试恢复...');
          await audioCtx.resume();
          console.log('[xmov] ✅ AudioContext 已恢复到运行状态:', audioCtx.state);
        } else {
          console.log('[xmov] ✅ AudioContext 状态正常:', audioCtx.state);
        }

        // 保存到全局以便后续检查
        (window as any).audioContext = audioCtx;
      } catch (error) {
        console.error('[xmov] ❌ AudioContext 检查/恢复失败:', error);
      }
    };

    const handleWebSocketMessage = async (message: WebSocketMessage) => {
      console.log('[xmov] 📨 handleWebSocketMessage 被调用');
      console.log('[xmov] 📨 消息内容:', JSON.stringify(message, null, 2));

      if (!sdkRef.current) {
        console.error('[xmov] ❌ SDK未就绪或speak方法不可用');
        return;
      }

      const { Data } = message;
      let text = '';
      const isFirst = Data.IsFirst === 1;
      const isEnd = Data.IsEnd === 1;

      // 处理 log 消息（用于思考状态切换）
      if (Data.Key === 'log') {
        const logText = Data.Value || '';
        console.log('[xmov] 📝 收到日志消息:', logText);

        // 传递log消息给父组件显示
        if (onLogMessage) {
          onLogMessage(logText);
        }

        // 检测是否是思考状态
        if (logText.includes('思考')) {
          console.log('[xmov] 🧠 检测到思考状态日志，调用 SDK think()');
          isThinkingRef.current = true;
          try {
            sdkRef.current.think();
            console.log('[xmov] ✅ SDK 已切换到思考状态');
          } catch (error) {
            console.error('[xmov] ❌ 切换到思考状态失败:', error);
          }
        }
        return; // log 消息不需要播放
      }

      if (Data.Key === 'text') {
        text = Data.Value || '';
      } else if (Data.Key === 'audio') {
        text = Data.Text || '';
      }

      console.log('[xmov] 📋 提取的文本:', text);
      console.log('[xmov] 📋 isFirst:', isFirst, 'isEnd:', isEnd);

      // 检测到新对话开始（isFirst=1）
      if (isFirst) {
        // 清除旧的超时定时器
        clearConversationTimeout();

        // 如果上一轮对话未结束，强制结束
        if (isConversationActiveRef.current && hasSpeakStartedRef.current) {
          console.warn('[xmov] ⚠️ 检测到新对话开始，上一轮对话未结束，强制发送结束信号');
          try {
            // 先发送一个 is_end=true 来结束上一轮对话
            sdkRef.current.speak(' ', false, true);
            console.log('[xmov] ✅ 步骤1：已发送结束信号 (is_start=false, is_end=true)');

            // 🔧 根据SDK文档要求：speak不允许连续调用，必须中间调用状态切换方法
            // 调用 interactiveIdle() 切换状态，避免连续speak调用
            sdkRef.current.interactiveIdle();
            console.log('[xmov] ✅ 步骤2：已切换到待机互动状态（避免连续speak）');
          } catch (error) {
            console.error('[xmov] ❌ 强制结束对话失败:', error);
          }
        }
        // 重置状态，开始新对话
        isConversationActiveRef.current = true;
        hasSpeakStartedRef.current = false;
        isThinkingRef.current = false; // 新对话开始，重置思考状态
        console.log('[xmov] 🆕 新对话开始');
      }

      if (text && text.trim()) {
        const thinkStartIndex = text.indexOf('<think>');
        const thinkEndIndex = text.indexOf('</think>');

        // 检测思考结束标签（<think> 通过 log 消息处理）
        if (thinkStartIndex !== -1 && !isThinkingRef.current) {
          // 如果在 text 消息中检测到 <think>，也切换状态（兼容处理）
          isThinkingRef.current = true;
          console.log('[xmov] 🧠 在 text 消息中检测到 <think>，调用 SDK think()');
          try {
            sdkRef.current.think();
            console.log('[xmov] ✅ SDK 已切换到思考状态');
          } catch (error) {
            console.error('[xmov] ❌ 切换到思考状态失败:', error);
          }
        }
        if (thinkEndIndex !== -1 && isThinkingRef.current) {
          isThinkingRef.current = false;
          console.log('[xmov] 🧠 检测到 </think>，退出思考模式');
          // 注意：不需要调用 interactiveIdle，因为接下来会调用 speak
        }

        let contentToSpeak = '';

        // 情况1: 当前正在思考中，且消息中没有 </think>
        if (isThinkingRef.current && thinkEndIndex === -1) {
          console.log('[xmov] 🧠 正在思考中，跳过内容播放');
          console.log('[xmov] 原始文本:', text);
          // 如果是 isEnd，必须发送结束信号给 SDK
          if (isEnd && hasSpeakStartedRef.current) {
            console.log('[xmov] 📢 虽然在思考中，但必须发送 is_end=true 结束对话');
            try {
              sdkRef.current.speak(' ', false, true);
              console.log('[xmov] ✅ 已发送结束信号');
            } catch (error) {
              console.error('[xmov] ❌ 发送结束信号失败:', error);
            }
            isConversationActiveRef.current = false;
            hasSpeakStartedRef.current = false;
          }
          return; // 不播放思考内容
        }
        // 情况2: 同时包含 <think> 和 </think>（在同一条消息中完成思考）
        else if (thinkStartIndex !== -1 && thinkEndIndex !== -1 && thinkStartIndex < thinkEndIndex) {
          const beforeThink = text.substring(0, thinkStartIndex);
          const afterThink = text.substring(thinkEndIndex + 8); // 8 是 '</think>' 的长度
          contentToSpeak = (beforeThink + afterThink).trim();
          console.log('[xmov] 🧠 检测到完整的 <think> 标签，移除思考内容');
          console.log('[xmov] 原始文本:', text);
          console.log('[xmov] 移除思考后:', contentToSpeak);
        }
        // 情况3: 只有 </think>（跨消息思考结束）
        else if (thinkStartIndex === -1 && thinkEndIndex !== -1) {
          contentToSpeak = text.substring(thinkEndIndex + 8).trim();
          console.log('[xmov] 🧠 检测到 </think> 标签（跨消息思考结束），提取后续内容:', contentToSpeak);
        }
        // 情况4: 没有思考标签，正常内容
        else {
          contentToSpeak = text;
        }

        // 如果有内容要播放
        if (contentToSpeak && contentToSpeak.trim()) {
          const shouldBeStart = !hasSpeakStartedRef.current;
          console.log('[xmov] 🔊 准备调用speak');
          console.log('[xmov] 🔊 参数: contentToSpeak=', contentToSpeak);
          console.log('[xmov] 🔊 参数: shouldBeStart=', shouldBeStart);
          console.log('[xmov] 🔊 参数: isEnd=', isEnd);
          console.log('[xmov] 🔊 状态: hasSpeakStartedRef=', hasSpeakStartedRef.current);
          console.log('[xmov] 🔊 状态: isConversationActiveRef=', isConversationActiveRef.current);
          console.log('[xmov] 🔊 SDK实例状态:', {
            sdkExists: !!sdkRef.current,
            speakMethod: typeof sdkRef.current?.speak,
          });
          try {
            // 🔧 在调用speak之前，确保AudioContext处于运行状态
            await ensureAudioContextRunning();

            console.log('[xmov] 🔊 ===== 正在调用 sdkRef.current.speak() =====');
            sdkRef.current.speak(contentToSpeak, shouldBeStart, isEnd);
            console.log('[xmov] 🔊 ===== speak() 调用完成，无异常 =====');

            hasSpeakStartedRef.current = true; // 标记已开始播放

            if (isEnd) {
              // 对话结束，清除超时定时器
              clearConversationTimeout();
              isConversationActiveRef.current = false;
              hasSpeakStartedRef.current = false;
              console.log('[xmov] 🔊 对话已结束，状态已重置');
            } else {
              // 对话继续，重置超时定时器
              resetConversationTimeout();
              console.log('[xmov] 🔊 对话进行中，已重置超时定时器');
            }

            console.log('[xmov] 🔊 最终状态: 对话状态=', isConversationActiveRef.current ? '进行中' : '已结束');
          } catch (error) {
            console.error('[xmov] ❌ speak调用失败:', error);
            console.error('[xmov] ❌ 错误详情:', error);
          }
        } else {
          console.log('[xmov] ⚠️ 移除思考内容后无有效内容, contentToSpeak=', contentToSpeak);
          // 如果是 isEnd，必须发送结束信号给 SDK（即使没有内容）
          if (isEnd && hasSpeakStartedRef.current) {
            console.log('[xmov] 📢 虽然无内容，但必须发送 is_end=true 结束对话');
            try {
              sdkRef.current.speak(' ', false, true);
              console.log('[xmov] ✅ 已发送结束信号');
            } catch (error) {
              console.error('[xmov] ❌ 发送结束信号失败:', error);
            }
            clearConversationTimeout();
            isConversationActiveRef.current = false;
            hasSpeakStartedRef.current = false;
          }
        }
      }
    };

    initializeSDK();

    return () => {
      mounted = false;
      if (initTimeout) clearTimeout(initTimeout);

      // 清理对话超时定时器
      clearConversationTimeout();

      // 清理 WebSocket
      if (wsServiceRef.current) {
        wsServiceRef.current.disconnect();
        wsServiceRef.current = null;
      }

      // 清理 SDK
      if (sdkRef.current) {
        try {
          sdkRef.current.destroy();
          console.log('[xmov] SDK已销毁');
        } catch (error) {
          console.warn('[xmov] 销毁SDK时出错:', error);
        }
        sdkRef.current = null;
      }
    };
  }, [websocketUrl]);

  return (
    <div className="relative w-full h-full bg-gradient-to-br from-blue-50 via-cyan-50 to-blue-100">
      {/* SDK 容器 - 使用style设置z-index为1，确保UI按钮可以覆盖在上面 */}
      <div ref={containerRef} className="w-full h-full relative" style={{ zIndex: 1 }} />

      {/* 状态覆盖层 */}
      {sdkStatus !== 'ready' && (
        <div className="absolute inset-0 flex items-center justify-center bg-gradient-to-br from-blue-50 via-cyan-50 to-blue-100 z-10">
          <div className="text-center px-8">
            {sdkStatus === 'loading' && (
              <>
                <div className="w-16 h-16 mx-auto mb-4 border-4 border-blue-500 border-t-transparent rounded-full animate-spin" />
                <p className="text-xl text-gray-700 font-medium mb-2">初始化中...</p>
                {loadingProgress > 0 && (
                  <p className="text-base text-gray-500">加载资源 {loadingProgress}%</p>
                )}
              </>
            )}
            {sdkStatus === 'config-missing' && (
              <>
                <div className="w-20 h-20 mx-auto mb-4 flex items-center justify-center text-6xl">⚠️</div>
                <p className="text-xl text-red-600 font-medium mb-2">配置未完成</p>
                <p className="text-base text-gray-600 mb-4">{errorMessage}</p>
                <div className="bg-white p-4 rounded-lg text-left text-sm text-gray-700 max-w-md">
                  <p className="font-semibold mb-2">请在系统环境变量中配置：</p>
                  <div className="bg-gray-100 p-3 rounded font-mono text-xs">
                    <p>变量名: XMOV_APP_ID</p>
                    <p>变量值: 您的AppID</p>
                    <p className="mt-2">变量名: XMOV_APP_SECRET</p>
                    <p>变量值: 您的AppSecret</p>
                  </div>
                  <p className="text-xs text-gray-600 mt-3">
                    在 <a href="https://xingyun3d.com/" target="_blank" rel="noopener noreferrer" className="text-blue-600 underline">魔珐星云</a> 应用中心创建驱动应用后获取。
                    配置后需<strong className="text-red-600">重启应用程序</strong>。
                  </p>
                </div>
              </>
            )}
            {sdkStatus === 'error' && (
              <>
                <div className="w-20 h-20 mx-auto mb-4 flex items-center justify-center text-6xl">❌</div>
                <p className="text-xl text-red-600 font-medium mb-2">加载失败</p>
                <p className="text-base text-gray-600">{errorMessage}</p>
              </>
            )}
          </div>
        </div>
      )}

    </div>
  );
};
