import axios from 'axios';

// Dify API的基础URL，可以根据你的实际部署地址进行修改
const BaseUrl = 'https://ai.nycjy1.cn/v1'; // 示例: 替换成你的 Dify API 地址

/**
 * 处理从Dify API返回的流式数据块。
 * @param chunk - 从服务器接收到的数据块字符串。
 * @param options - 包含当前状态和回调函数的对象。
 * @returns 更新后的状态对象。
 */
function handleStreamResponse(chunk, options) {
  try {
    // 忽略空的数据块
    if (!chunk.trim()) {
      return options;
    }

    // 流式数据可能包含多个 "data: {...}" 块，它们由两个换行符分隔
    const lines = chunk.split('\n\n');

    for (const line of lines) {
      // 跳过无效行或非数据行
      if (!line.trim() || !line.startsWith('data:')) continue;

      // 提取 "data:" 后面的JSON字符串
      const jsonStr = line.slice(5).trim();
      if (!jsonStr) continue;

      try {
        // 确保是完整的JSON对象
        if (!jsonStr.startsWith('{') || !jsonStr.endsWith('}')) {
          console.warn('接收到不完整的JSON对象:', jsonStr);
          continue;
        }

        const data = JSON.parse(jsonStr);

        // 事件类型为 'message'，表示正在接收AI的回答
        if (data.event === 'message') {
          const newContent = data.answer || '';
          options.fullResponse += newContent; // 将新的内容追加到完整响应中

          // 调用实时更新回调函数
          options.onMessageUpdate({
            content: options.fullResponse,
            isStreaming: true
          });

        // 事件类型为 'message_end'，表示消息流结束
        } else if (data.event === 'message_end') {
          options.isStreamEnded = true;

          // 调用最终更新回调函数
          options.onMessageUpdate({
            content: options.fullResponse,
            isStreaming: false
          });
          
          // 调用流结束的回调
          options.onStreamEnd();
        }
      } catch (parseError) {
        console.warn('JSON解析错误:', {
          error: parseError,
          rawData: jsonStr,
        });
        continue;
      }
    }
  } catch (e) {
    console.error('流处理时发生错误:', e);
  }
  return options;
}

/**
 * 一个简单的Dify聊天服务类。
 */
export class SimpleChatService {
  constructor(apiKey, baseUrl = BaseUrl) {
    if (!apiKey) {
      throw new Error("API Key是必须的。");
    }
    this.apiKey = apiKey;
    this.baseUrl = baseUrl;
  }

  /**
   * 发送消息到Dify API并处理流式响应。
   * @param userMessage - 用户发送的消息。
   * @param onMessageUpdate - 当收到新数据块时调用的回调函数。
   * @param onStreamEnd - 当流结束时调用的回调函数。
   * @param abortSignal - 用于取消请求的AbortSignal。
   */
  async sendMessage(
    userMessage,
    onMessageUpdate,
    onStreamEnd,
    abortSignal = null
  ) {
    const params = {
      inputs: {},
      query: userMessage,
      response_mode: 'streaming', // 声明需要流式响应
      conversation_id: '', // 如果需要继续之前的对话，请传入对应的ID
      user: 'web-user-axios-simple',
      auto_generate_name: true
    };

    let state = {
      fullResponse: '',
      isStreamEnded: false,
    };
    
    // 用于跟踪已处理的响应文本长度
    let processedLength = 0;

    try {
      await axios({
        method: 'POST',
        url: `${this.baseUrl}/chat-messages`,
        data: params,
        headers: {
          'Authorization': `Bearer ${this.apiKey}`,
          'Content-Type': 'application/json'
        },
        responseType: 'text', // 必须设置为 'text' 以便处理流式响应
        signal: abortSignal, // 关联取消信号
        onDownloadProgress: (progressEvent) => {
          // 获取自上次回调以来新增的文本部分
          const newChunk = progressEvent.event.target.responseText.substring(processedLength);
          processedLength = progressEvent.event.target.responseText.length;

          // 将新的数据块传递给处理函数
          state = handleStreamResponse(newChunk, {
            ...state,
            onMessageUpdate,
            onStreamEnd,
          });
        }
      });
      
      // 检查请求完成后，流是否已正常结束
      if (!state.isStreamEnded) {
        console.warn("请求已完成，但未收到 'message_end' 事件。");
        onMessageUpdate({
          content: state.fullResponse,
          isStreaming: false
        });
        onStreamEnd();
      }

    } catch (error) {
      if (axios.isCancel(error)) {
        console.log('请求已被用户取消。');
      } else {
        console.error('发送消息失败:', error);
        onMessageUpdate({
          content: '抱歉，发送消息失败，请检查API Key或网络连接后重试。',
          isStreaming: false
        });
      }
      // 确保在出错或取消时也调用 onStreamEnd
      onStreamEnd();
    }
  }
}