<script setup lang="tsx">
import {
  Attachments,
  type AttachmentsProps,
  Bubble,
  type BubbleListProps,
  Conversations,
  type ConversationsProps,
  Prompts,
  type PromptsProps,
  Sender,
  Welcome,
  useXAgent,
  useXChat,
} from 'ant-design-x-vue';
import {
  CloudUploadOutlined,
  CommentOutlined,
  EllipsisOutlined,
  FireOutlined,
  HeartOutlined,
  PaperClipOutlined,
  PlusOutlined,
  ReadOutlined,
  ShareAltOutlined,
  SmileOutlined,
} from '@ant-design/icons-vue';
import { Badge, Button, Space, theme } from 'ant-design-vue';
import { computed, ref, watch, type VNode, h, onMounted } from 'vue';
import MarkdownIt from 'markdown-it';

defineOptions({ name: 'PlaygroundIndependent' });

const sleep = () => new Promise((resolve) => setTimeout(resolve, 500));

const renderTitle = (icon: VNode, title: string) => (
  <Space align="start">
    {icon}
    <span>{title}</span>
  </Space>
);

const defaultConversationsItems = [
  {
    key: '0',
    label: 'What is Ant Design X?',
  },
];

const placeholderPromptsItems: PromptsProps['items'] = [
  {
    key: '1',
    label: renderTitle(<FireOutlined style={{ color: '#FF4D4F' }} />, 'Hot Topics'),
    description: 'What are you interested in?',
    children: [
      {
        key: '1-1',
        description: `What's new in X?`,
      },
      {
        key: '1-2',
        description: `What's AGI?`,
      },
      {
        key: '1-3',
        description: `Where is the doc?`,
      },
    ],
  },
  {
    key: '2',
    label: renderTitle(<ReadOutlined style={{ color: '#1890FF' }} />, 'Design Guide'),
    description: 'How to design a good product?',
    children: [
      {
        key: '2-1',
        icon: <HeartOutlined />,
        description: `Know the well`,
      },
      {
        key: '2-2',
        icon: <SmileOutlined />,
        description: `Set the AI role`,
      },
      {
        key: '2-3',
        icon: <CommentOutlined />,
        description: `Express the feeling`,
      },
    ],
  },
];

const senderPromptsItems: PromptsProps['items'] = [
  {
    key: '1',
    description: 'Hot Topics',
    icon: <FireOutlined style={{ color: '#FF4D4F' }} />,
  },
  {
    key: '2',
    description: 'Design Guide',
    icon: <ReadOutlined style={{ color: '#1890FF' }} />,
  },
];

const roles: BubbleListProps['roles'] = {
  ai: {
    placement: 'start',
    typing: { step: 5, interval: 20 },
    styles: {
      content: {
        borderRadius: '16px',
      },
    },
  },
  local: {
    placement: 'end',
    variant: 'shadow',
  },
};

// ==================== Style ====================
const { token } = theme.useToken();
const styles = computed(() => {
  return {
    layout: {
      width: '100%',
      'min-width': '1000px',
      height: '722px',
      'border-radius': `${token.value.borderRadius}px`,
      display: 'flex',
      background: `${token.value.colorBgContainer}`,
      'font-family': `AlibabaPuHuiTi, ${token.value.fontFamily}, sans-serif`,
    },
    menu: {
      background: `${token.value.colorBgLayout}80`,
      width: '280px',
      height: '100%',
      display: 'flex',
      'flex-direction': 'column',
    },
    conversations: {
      padding: '0 12px',
      flex: 1,
      'overflow-y': 'auto',
    },
    chat: {
      height: '100%',
      width: '100%',
      'max-width': '700px',
      margin: '0 auto',
      'box-sizing': 'border-box',
      display: 'flex',
      'flex-direction': 'column',
      padding: `${token.value.paddingLG}px`,
      gap: '16px',
    },
    messages: {
      flex: 1,
    },
    placeholder: {
      'padding-top': '32px',
    },
    sender: {
      'box-shadow': token.value.boxShadow,
    },
    logo: {
      display: 'flex',
      height: '72px',
      'align-items': 'center',
      'justify-content': 'start',
      padding: '0 24px',
      'box-sizing': 'border-box',
    },
    'logo-img': {
      width: '24px',
      height: '24px',
      display: 'inline-block',
    },
    'logo-span': {
      display: 'inline-block',
      margin: '0 8px',
      'font-weight': 'bold',
      color: token.value.colorText,
      'font-size': '16px',
    },
    addBtn: {
      background: '#1677ff0f',
      border: '1px solid #1677ff34',
      width: 'calc(100% - 24px)',
      margin: '0 12px 24px 12px',
    }
  } as const
});

// ==================== State ====================
const headerOpen = ref(false);
const content = ref('');
const conversationsItems = ref(defaultConversationsItems);
const activeKey = ref(defaultConversationsItems[0].key);
const attachedFiles = ref<AttachmentsProps['items']>([]);
const agentRequestLoading = ref(false);
const pagination = ref({
  total: 0,
  page: 1,
  pageSize: 20,
  totalPages: 0
});
const loadingHistory = ref(false);

// 添加文件类型分类存储
const imageUrls = ref<string[]>([]);
const documentUrls = ref<string[]>([]);

// ==================== Runtime ====================
const [ agent ] = useXAgent({
  request: async ({ message, attachments }, { onSuccess, onError }) => {
    agentRequestLoading.value = true;
    
    try {
      // 调用多模态聊天接口
      const apiUrl = `http://121.36.251.245:8082/chatbot/multimodal`;
      const response = await fetch(apiUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          message: message,
          chat_config_id: "17",
          user_id: 4,
          session_id: "",
          source: "pc",
          image_urls: imageUrls.value,
          documents: documentUrls.value,
          merchant_id: "3",
          model_type: "REMOTE_CLAUDE",
	        model_name: "claude-3-sonnet-20240229"
        }),
      });
      
      if (!response.ok) {
        throw new Error(`API request failed with status ${response.status}`);
      }
      
      const responseData = await response.json();
      
      // 检查响应状态码
      if (responseData.code !== 2000) {
        throw new Error(`API returned error code: ${responseData.code}, message: ${responseData.message}`);
      }
      
      // 从响应中提取内容
      if (responseData.choices && responseData.choices[0].message.content) {
        // 将AI回复内容传递给onSuccess
        onSuccess(responseData.choices[0].message.content);
        
        // 可选：记录模型信息和token使用情况
        console.log(`Model used: ${responseData.data.model}`);
        if (responseData.usage) {
          console.log(`Token usage: ${JSON.stringify(responseData.usage)}`);
        }
      } else {
        throw new Error('Response data is missing content');
      }
    } catch (error) {
      console.error('Error calling multimodal API:', error);
      onError(error instanceof Error ? error : new Error('Unknown error occurred'));
    } finally {
      agentRequestLoading.value = false;
      // 清空URL数组
      imageUrls.value = [];
      documentUrls.value = [];
    }
  },
});

const { onRequest, messages, setMessages } = useXChat({
  agent: agent.value,
  onRequest: (message, attachments) => {
    return agent.value.request({
      message,
      attachments,
    });
  }
});

watch(activeKey, () => {
  if (activeKey.value !== undefined) {
    setMessages([]);
  }
}, { immediate: true });

// ==================== Event ====================
const onSubmit = (nextContent: string) => {
  if (!nextContent) return;
  
  // 检查是否有正在上传的文件
  const hasUploadingFiles = attachedFiles.value.some(file => file.status === 'uploading');
  if (hasUploadingFiles) {
    // 可以显示一个提示，告诉用户等待文件上传完成
    console.warn('Please wait for file uploads to complete');
    return;
  }
  
  // 将附件文件传递给请求，同时传递分类后的URLs
  onRequest(nextContent, attachedFiles.value);
  
  // 发送后清空输入和附件
  content.value = '';
  attachedFiles.value = [];
  // 清空URL数组
  imageUrls.value = [];
  documentUrls.value = [];
  headerOpen.value = false;
};

const onPromptsItemClick: PromptsProps['onItemClick'] = (info) => {
  onRequest(info.data.description as string);
};

const onAddConversation = () => {
  // 添加一个特殊的"新会话"选项
  const newConversationKey = 'new';
  
  // 检查是否已经有新会话选项
  if (!conversationsItems.value.some(item => item.key === newConversationKey)) {
    conversationsItems.value = [
      {
        key: newConversationKey,
        label: '新会话',
      },
      ...conversationsItems.value,
    ];
  }
  
  // 选中新会话
  activeKey.value = newConversationKey;
  // 清空消息
  setMessages([]);
};

const onConversationClick: ConversationsProps['onActiveChange'] = async (key) => {
  activeKey.value = key;
  
  // 如果是新会话，清空消息
  if (key === 'new') {
    setMessages([]);
    return;
  }
  
  // 查找选中的会话
  const selectedSession = conversationsItems.value.find(item => item.key === key);
  if (!selectedSession) return;
  
  // 这里可以添加加载特定会话消息的逻辑
  // 例如：
  try {
    const response = await fetch(`http://121.36.251.245:8082/api/chat/messages?session_id=${key}`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      }
    });
    
    if (!response.ok) {
      throw new Error(`Failed to fetch messages: ${response.status}`);
    }
    
    const result = await response.json();
    if (result.code !== 2000) {
      throw new Error(`API returned error: ${result.message}`);
    }
    
    // 假设API返回的消息格式与您的消息格式兼容
    if (result.data && result.data.messages) {
      // 转换消息格式
      const formattedMessages = result.data.messages.map((msg: any) => ({
        id: msg.id || Math.random().toString(36).substring(2, 9),
        message: msg.content,
        status: msg.role === 'assistant' ? 'ai' : 'local'
      }));
      
      setMessages(formattedMessages);
    }
  } catch (error) {
    console.error('Error fetching messages:', error);
    // 如果获取失败，清空消息
    setMessages([]);
  }
};

const handleFileChange: AttachmentsProps['onChange'] = (info) => {
  console.log('File change event:', info);
  
  // 获取新添加的文件
  const newFile = info.file;
  
  // 保存文件列表，包括原始文件对象
  attachedFiles.value = info.fileList.map(file => ({
    ...file,
    // 确保保留原始文件对象以便上传
    originFileObj: file.originFileObj
  }));
  
  // 检查是否有新文件添加
  if (newFile && newFile.status === 'uploading' && newFile.originFileObj) {
    console.log('Starting upload for file:', newFile.name);
    
    // 立即上传文件
    uploadFile(newFile.originFileObj)
      .then(fileUrl => {
        console.log('File uploaded successfully:', fileUrl);
        // 更新文件状态为已上传成功
        attachedFiles.value = attachedFiles.value.map(file => {
          if (file.uid === newFile.uid) {
            return {
              ...file,
              status: 'done',
              url: fileUrl,
              response: { url: fileUrl }
            };
          }
          return file;
        });
      })
      .catch(error => {
        console.error('File upload failed:', error);
        // 更新文件状态为上传失败
        attachedFiles.value = attachedFiles.value.map(file => {
          if (file.uid === newFile.uid) {
            return {
              ...file,
              status: 'error',
              error
            };
          }
          return file;
        });
      });
  }
};

// 添加文件上传函数
const uploadFile = async (file: File): Promise<string> => {
  const formData = new FormData();
  formData.append('file', file);
  
  try {
    const uploadResponse = await fetch('http://121.36.251.245:8082/upload/file', {
      method: 'POST',
      body: formData,
    });
    
    if (!uploadResponse.ok) {
      throw new Error(`File upload failed with status ${uploadResponse.status}`);
    }
    
    const uploadResult = await uploadResponse.json();
    
    // 检查上传响应状态码
    if (uploadResult.status !== 2000) {
      throw new Error(`Upload API returned error: ${uploadResult.message}`);
    }
    
    // 从响应中获取文件URL
    const fileUrl = uploadResult.data?.fileUrl;
    
    if (!fileUrl) {
      throw new Error('Upload response missing file URL');
    }
    
    // 根据文件URL后缀或文件类型判断是否为图片
    const isImage = (url: string, fileType: string): boolean => {
      // 检查URL后缀
      const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'];
      const hasImageExtension = imageExtensions.some(ext => url.toLowerCase().endsWith(ext));
      
      // 检查MIME类型
      const isImageMimeType = fileType.startsWith('image/');
      
      return hasImageExtension || isImageMimeType;
    };
    
    // 根据判断结果分类存储URL
    if (isImage(fileUrl, file.type)) {
      imageUrls.value.push(fileUrl);
      console.log('Added image URL:', fileUrl);
      console.log('Current image URLs:', imageUrls.value);
    } else {
      documentUrls.value.push(fileUrl);
      console.log('Added document URL:', fileUrl);
      console.log('Current document URLs:', documentUrls.value);
    }
    
    return fileUrl;
  } catch (error) {
    console.error('Error uploading file:', error);
    throw error;
  }
};

// ==================== Nodes ====================
const placeholderNode = computed(() => (
  <Space direction="vertical" size={16} style={styles.value.placeholder}>
    <Welcome
      variant="borderless"
      icon="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp"
      title="Hello, I'm Ant Design X"
      description="Base on Ant Design, AGI product interface solution, create a better intelligent vision~"
      extra={
        <Space>
          <Button icon={<ShareAltOutlined />} />
          <Button icon={<EllipsisOutlined />} />
        </Space>
      }
    />
    <Prompts
      title="Do you want?"
      items={placeholderPromptsItems}
      styles={{
        list: {
          width: '100%',
        },
        item: {
          flex: 1,
        },
      }}
      onItemClick={onPromptsItemClick}
    />
  </Space>
));

// 创建 markdown-it 实例
const md = new MarkdownIt({
  html: true,
  linkify: true,
  typographer: true
});

const items = computed<BubbleListProps['items']>(() => messages.value.map(({ id, message, status }) => {
  // 检查消息是否是 markdown 格式
  const isMarkdown = status === 'ai' && 
    (message.includes('#') || message.includes('**') || message.includes('\n'));
  
  let content;
  
  if (isMarkdown && status === 'ai') {
    // 渲染 markdown 内容
    const htmlContent = md.render(message);
    content = h('div', {
      class: 'markdown-content',
      innerHTML: htmlContent
    });
  } else {
    // 普通文本内容
    content = message;
  }
  
  return {
    key: id,
    loading: status === 'loading',
    role: status === 'local' ? 'local' : 'ai',
    content: content,
  };
}));

const attachmentsNode = computed(() => (
  <Badge dot={attachedFiles.value.length > 0 && !headerOpen.value}>
    <Button type="text" icon={<PaperClipOutlined />} onClick={() => headerOpen.value = !headerOpen.value} />
  </Badge>
));

const senderHeader = computed(() => (
  <Sender.Header
    title="Attachments"
    open={headerOpen.value}
    onOpenChange={(open) => headerOpen.value = open}
    styles={{
      content: {
        padding: 0,
      },
    }}
  >
    <Attachments
      action="http://121.36.251.245:8082/upload/file" // 添加上传地址
      name="file" // 指定上传字段名
      items={attachedFiles.value}
      onChange={handleFileChange}
      customRequest={({ file, onSuccess, onError, onProgress }) => {
        // 手动处理文件上传
        if (file && file.originFileObj) {
          console.log('Custom request triggered for file:', file.name);
          uploadFile(file.originFileObj)
            .then(fileUrl => {
              console.log('Custom upload successful:', fileUrl);
              onSuccess({ url: fileUrl }, new XMLHttpRequest());
            })
            .catch(err => {
              console.error('Custom upload failed:', err);
              onError(err);
            });
        }
      }}
      placeholder={(type) =>
        type === 'drop'
          ? { title: 'Drop file here' }
          : {
            icon: <CloudUploadOutlined />,
            title: 'Upload files',
            description: 'Click or drag files to this area to upload',
          }
      }
    />
  </Sender.Header>
));

const logoNode = computed(() => (
  <div style={styles.value.logo}>
    <img
      src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*eco6RrQhxbMAAAAAAAAAAAAADgCCAQ/original"
      draggable={false}
      alt="logo"
      style={styles.value['logo-img']}
    />
    <span style={styles.value['logo-span']}>Ant Design X Vue</span>
  </div>
));

// 添加 markdown 样式
const markdownStyles = `
.markdown-content h3 {
  font-size: 1.3em;
  margin-top: 1em;
  margin-bottom: 0.5em;
  font-weight: 600;
}

.markdown-content h4 {
  font-size: 1.1em;
  margin-top: 1em;
  margin-bottom: 0.5em;
  font-weight: 600;
}

.markdown-content p {
  margin-bottom: 0.8em;
}

.markdown-content ul, .markdown-content ol {
  padding-left: 1.5em;
  margin-bottom: 0.8em;
}

.markdown-content li {
  margin-bottom: 0.3em;
}

.markdown-content strong {
  font-weight: 600;
}
`;

// 修改 fetchChatHistory 函数，处理 last_message 和 user_message
const fetchChatHistory = async () => {
  loadingHistory.value = true;
  try {
    const response = await fetch('http://121.36.251.245:8082/api/chat/history', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        merchant_id: "3",
        user_id: 4,
        page: pagination.value.page,
        page_size: pagination.value.pageSize
      }),
    });

    if (!response.ok) {
      throw new Error(`获取聊天历史失败: ${response.status}`);
    }

    const result = await response.json();
    
    if (result.code !== 2000) {
      throw new Error(`API返回错误: ${result.message}`);
    }

    // 更新会话列表
    if (result.data && result.data.sessions) {
      conversationsItems.value = result.data.sessions.map((session: any) => {
        // 优先使用用户消息作为会话标签，如果没有则使用AI回复
        const displayContent = session.user_message?.content || session.last_message?.content || '新会话';
        
        return {
          key: session.session_id,
          // 截取前20个字符作为标签，如果超过则添加省略号
          label: displayContent.substring(0, 20) + (displayContent.length > 20 ? '...' : ''),
          // 保存时间戳
          timestamp: new Date(session.last_message?.created_at || Date.now()),
          // 保存用户消息和AI回复，以便在UI中显示
          userMessage: session.user_message,
          aiMessage: session.last_message,
          // 保存完整会话数据以备后用
          sessionData: session
        };
      });
      
      // 如果有会话，默认选中第一个
      if (conversationsItems.value.length > 0) {
        activeKey.value = conversationsItems.value[0].key;
        
        // 加载第一个会话的消息
        await loadSessionMessages(conversationsItems.value[0].key);
      }
      
      // 更新分页信息
      if (result.data.pagination) {
        pagination.value = {
          total: result.data.pagination.total,
          page: result.data.pagination.page,
          pageSize: result.data.pagination.page_size,
          totalPages: result.data.pagination.total_pages
        };
      }
    }
  } catch (error) {
    console.error('获取聊天历史出错:', error);
    // 如果获取失败，使用默认会话列表
    conversationsItems.value = defaultConversationsItems;
  } finally {
    loadingHistory.value = false;
  }
};

// 修改加载会话消息的函数，处理用户消息和AI回复
const loadSessionMessages = async (sessionId: string) => {
  try {
    // 显示加载状态
    setMessages([{ id: 'loading', message: '加载消息中...', status: 'loading' }]);
    
    const response = await fetch(`http://121.36.251.245:8082/api/chat/messages?session_id=${sessionId}`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      }
    });
    
    if (!response.ok) {
      throw new Error(`获取消息失败: ${response.status}`);
    }
    
    const result = await response.json();
    if (result.code !== 2000) {
      throw new Error(`API返回错误: ${result.message}`);
    }
    
    // 处理消息数据
    if (result.data && result.data.messages) {
      // 转换消息格式并按时间排序
      const formattedMessages = [];
      
      // 遍历消息，每组包含用户消息和AI回复
      for (const msg of result.data.messages) {
        // 如果有用户消息，添加到列表
        if (msg.user_message && msg.user_message.content) {
          formattedMessages.push({
            id: `user_${msg.id || Math.random().toString(36).substring(2, 9)}`,
            message: msg.user_message.content,
            status: 'local',
            timestamp: new Date(msg.user_message.created_at || Date.now())
          });
        }
        
        // 如果有AI回复，添加到列表
        if (msg.last_message && msg.last_message.content) {
          formattedMessages.push({
            id: `ai_${msg.id || Math.random().toString(36).substring(2, 9)}`,
            message: msg.last_message.content,
            status: 'ai',
            timestamp: new Date(msg.last_message.created_at || Date.now())
          });
        }
      }
      
      // 按时间排序
      formattedMessages.sort((a, b) => a.timestamp - b.timestamp);
      
      // 更新消息列表
      setMessages(formattedMessages);
    } else {
      // 如果没有消息，显示空列表
      setMessages([]);
    }
  } catch (error) {
    console.error('加载会话消息出错:', error);
    // 显示错误消息
    setMessages([{
      id: 'error',
      message: '加载消息失败，请重试',
      status: 'ai'
    }]);
  }
};

// 在组件挂载时获取聊天历史
onMounted(() => {
  /* fetchChatHistory(); */
});

defineRender(() => {
  return (
    <div style={styles.value.layout}>
      {/* 添加 markdown 样式 */}
      <style>{markdownStyles}</style>
      
      <div style={styles.value.menu}>
        {/* 🌟 Logo */}
        {logoNode.value}
        {/* 🌟 添加会话 */}
        <Button
          onClick={onAddConversation}
          type="link"
          style={styles.value.addBtn}
          icon={<PlusOutlined />}
        >
          New Conversation
        </Button>
        {/* 🌟 会话管理 */}
        <Conversations
          items={conversationsItems.value}
          style={styles.value.conversations}
          activeKey={activeKey.value}
          onActiveChange={onConversationClick}
        />
      </div>
      <div style={styles.value.chat}>
        {/* 🌟 消息列表 */}
        <Bubble.List
          items={items.value.length > 0 ? items.value : [{ content: placeholderNode.value, variant: 'borderless' }]}
          roles={roles}
          style={styles.value.messages}
        />
        {/* 🌟 提示词 */}
        <Prompts style={{ color: token.value.colorText }} items={senderPromptsItems} onItemClick={onPromptsItemClick} />
        {/* 🌟 输入框 */}
        <Sender
          value={content.value}
          header={senderHeader.value}
          onSubmit={onSubmit}
          onChange={(value) => content.value = value}
          prefix={attachmentsNode.value}
          loading={agentRequestLoading.value}
          style={styles.value.sender}
        />
      </div>
    </div>
  )
});
</script>
