<script setup lang="ts">
import type { BubbleProps } from 'vue-element-plus-x/types/Bubble';
import type { BubbleListInstance } from 'vue-element-plus-x/types/BubbleList';
import type { ThinkingStatus } from 'vue-element-plus-x/types/Thinking';
import { Loading, Tools, Check, Plus, Delete } from '@element-plus/icons-vue';
import { ElIcon, ElMessage, ElMessageBox } from 'element-plus';
import { computed, onMounted, ref, watch } from 'vue';
import { Sender } from 'vue-element-plus-x';
import { agentSend, getAgentTools, getAgentContext } from '@/api/agent';
import type { AgentToolOutput, AgentResultOutput, AgentUsage } from '@/api/agent/types';
import { getSelectableTokenInfo } from '@/api';
import { useUserStore } from '@/stores/modules/user';
import { useAgentSessionStore } from '@/stores/modules/agentSession';
import { getUserProfilePicture } from '@/utils/user.ts';
import MarkedMarkdown from '@/components/MarkedMarkdown/index.vue';
import agentAvatar from '@/assets/images/czld.png';
import '@/styles/github-markdown.css';
import '@/styles/yixin-markdown.scss';

// 消息类型定义
type MessageItem = BubbleProps & {
  key: number;
  role: 'ai' | 'user' | 'assistant';
  avatar: string;
  thinkingStatus?: ThinkingStatus;
  thinlCollapse?: boolean;
  reasoning_content?: string;
  toolCalls?: { name: string; status: 'calling' | 'called'; result?: any; usage?: { prompt: number; completion: number; total: number } }[];
  tokenUsage?: { prompt: number; completion: number; total: number };
};

const userStore = useUserStore();
const agentSessionStore = useAgentSessionStore();

// 响应式数据
const inputValue = ref('');
const bubbleItems = ref<MessageItem[]>([]);
const bubbleListRef = ref<BubbleListInstance | null>(null);
const isSending = ref(false);
const sessionId = ref('');

// 会话列表相关
const showSessionList = ref(true);

// 工具相关
const availableTools = ref<AgentToolOutput[]>([]);
const selectedTools = ref<string[]>([]);
const showToolsPanel = ref(false);

// 配置相关
const tokenId = ref('');
const tokenOptions = ref<any[]>([]);
const tokenLoading = ref(false);
const modelId = ref('gpt-5.2-chat');

// 加载Token列表
async function loadTokens() {
  tokenLoading.value = true;
  try {
    const res = await getSelectableTokenInfo();
    const data = Array.isArray(res) ? res : (res as any).data || [];
    tokenOptions.value = data;
    // 默认选中第一个可用的token
    if (tokenOptions.value.length > 0 && !tokenId.value) {
      const firstAvailable = tokenOptions.value.find(t => !t.isDisabled);
      if (firstAvailable) {
        tokenId.value = firstAvailable.tokenId;
      }
    }
  } catch (error) {
    console.error('加载Token列表失败:', error);
  } finally {
    tokenLoading.value = false;
  }
}

// 加载工具列表
async function loadTools() {
  try {
    const res = await getAgentTools();
    availableTools.value = res.data || [];
    // 默认选中所有工具
    selectedTools.value = availableTools.value.map(t => t.code);
  } catch (error) {
    console.error('加载工具列表失败:', error);
  }
}

onMounted(() => {
  loadTokens();
  loadTools();
  // 加载会话列表
  if (userStore.token) {
    agentSessionStore.requestSessionList(1);
  }
});

// 创建新会话
async function createNewSession() {
  sessionId.value = '';
  bubbleItems.value = [];
  agentSessionStore.setCurrentSession(null);
}

// 选择会话
async function selectSession(session: any) {
  sessionId.value = session.id;
  agentSessionStore.setCurrentSession(session);
  bubbleItems.value = [];

  // 加载历史上下文
  await loadSessionContext(session.id);
}

// 加载会话历史上下文
async function loadSessionContext(sid: string) {
  try {
    const res = await getAgentContext(sid);

    // 获取实际数据，可能是 res.data 或直接是 res
    let rawData = res?.data ?? res;
    if (!rawData) return;

    // 如果是字符串则解析JSON
    let contextData = typeof rawData === 'string' ? JSON.parse(rawData) : rawData;

    // 获取消息列表
    const messages = contextData?.storeState?.messages || [];

    if (messages.length === 0) return;

    // 转换为消息列表
    messages.forEach((msg: any, index: number) => {
      const isUser = msg.role === 'user';
      const content = msg.contents
        ?.filter((c: any) => c.$type === 'text')
        ?.map((c: any) => c.text)
        ?.join('') || '';

      if (content) {
        const obj: MessageItem = {
          key: index,
          avatar: isUser ? getUserProfilePicture() : agentAvatar,
          avatarSize: '32px',
          role: isUser ? 'user' : 'assistant',
          placement: isUser ? 'end' : 'start',
          isMarkdown: !isUser,
          loading: false,
          content,
          reasoning_content: '',
          thinkingStatus: 'end',
          thinlCollapse: false,
          noStyle: !isUser,
          toolCalls: [],
        };
        bubbleItems.value.push(obj);
      }
    });

    // 滚动到底部
    setTimeout(() => {
      bubbleListRef.value?.scrollToBottom();
    }, 100);
  } catch (error) {
    console.error('加载会话上下文失败:', error);
  }
}

// 删除会话
async function handleDeleteSession(session: any, event: Event) {
  event.stopPropagation();
  try {
    await ElMessageBox.confirm('确定要删除该会话吗？', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    });
    await agentSessionStore.deleteSession([session.id]);
    if (sessionId.value === session.id) {
      createNewSession();
    }
    ElMessage.success('删除成功');
  } catch {
    // 取消删除
  }
}

// 切换工具选择
function toggleTool(code: string) {
  const index = selectedTools.value.indexOf(code);
  if (index > -1) {
    selectedTools.value.splice(index, 1);
  } else {
    selectedTools.value.push(code);
  }
}

// 添加消息
function addMessage(message: string, isUser: boolean) {
  const i = bubbleItems.value.length;
  const obj: MessageItem = {
    key: i,
    avatar: isUser ? getUserProfilePicture() : agentAvatar,
    avatarSize: '32px',
    role: isUser ? 'user' : 'assistant',
    placement: isUser ? 'end' : 'start',
    isMarkdown: !isUser,
    loading: !isUser,
    content: message || '',
    reasoning_content: '',
    thinkingStatus: 'start',
    thinlCollapse: false,
    noStyle: !isUser,
    toolCalls: [],
  };
  bubbleItems.value.push(obj);
}

// AbortController 用于取消请求
let abortController: AbortController | null = null;

// 临时存储工具调用用量
let pendingToolUsage: { prompt: number; completion: number; total: number } | null = null;

// 处理Agent流式数据
function handleAgentChunk(data: AgentResultOutput) {
  const latest = bubbleItems.value[bubbleItems.value.length - 1];
  if (!latest) return;

  switch (data.type) {
    case 'text':
      latest.content += data.content || '';
      latest.loading = false;
      break;
    case 'toolCalling':
      // 工具调用中
      if (!latest.toolCalls) latest.toolCalls = [];
      const newToolCall: { name: string; status: 'calling' | 'called'; result?: any; usage?: { prompt: number; completion: number; total: number } } = {
        name: data.content as string,
        status: 'calling',
      };
      // 如果有待处理的用量（toolCallUsage 先于 toolCalling 到达），设置到这个工具调用
      if (pendingToolUsage) {
        newToolCall.usage = pendingToolUsage;
        pendingToolUsage = null;
      }
      latest.toolCalls.push(newToolCall);
      break;
    case 'toolCallUsage':
      // 工具调用用量统计 - 先保存，等 toolCalled 时再设置
      const toolUsage = data.content as AgentUsage;
      pendingToolUsage = {
        prompt: toolUsage.input_tokens || toolUsage.prompt_tokens || 0,
        completion: toolUsage.output_tokens || toolUsage.completion_tokens || 0,
        total: toolUsage.total_tokens || 0,
      };
      // 同时尝试设置到最后一个工具调用
      if (latest.toolCalls && latest.toolCalls.length > 0) {
        const lastTool = latest.toolCalls[latest.toolCalls.length - 1];
        if (lastTool) {
          lastTool.usage = pendingToolUsage;
        }
      }
      break;
    case 'toolCalled':
      // 工具调用完成
      if (latest.toolCalls && latest.toolCalls.length > 0) {
        const lastTool = latest.toolCalls[latest.toolCalls.length - 1];
        if (lastTool) {
          lastTool.status = 'called';
          lastTool.result = data.content;
          // 如果有待处理的用量，设置到这个工具调用
          if (pendingToolUsage && !lastTool.usage) {
            lastTool.usage = pendingToolUsage;
          }
        }
      }
      pendingToolUsage = null;
      break;
    case 'usage':
      // 对话用量统计
      const chatUsage = data.content as AgentUsage;
      latest.tokenUsage = {
        prompt: chatUsage.input_tokens || chatUsage.prompt_tokens || 0,
        completion: chatUsage.output_tokens || chatUsage.completion_tokens || 0,
        total: chatUsage.total_tokens || 0,
      };
      break;
  }
}

// 发送消息
async function startSSE(chatContent: string) {
  if (isSending.value) return;
  if (!chatContent.trim()) {
    ElMessage.warning('请输入消息内容');
    return;
  }
  if (!tokenId.value) {
    ElMessage.warning('请先选择 API 密钥');
    showToolsPanel.value = true;
    return;
  }

  isSending.value = true;
  inputValue.value = '';

  // 如果没有会话ID，先创建会话
  let currentSessionId = sessionId.value;
  if (!currentSessionId && userStore.token) {
    const newSession = await agentSessionStore.createSession({
      sessionTitle: chatContent.slice(0, 20),
      sessionContent: chatContent,
      userId: userStore.userInfo?.userId as number,
    });
    if (newSession) {
      currentSessionId = newSession.id!;
      sessionId.value = currentSessionId;
    } else {
      currentSessionId = crypto.randomUUID();
      sessionId.value = currentSessionId;
    }
  } else if (!currentSessionId) {
    currentSessionId = crypto.randomUUID();
    sessionId.value = currentSessionId;
  }

  // 添加用户消息和AI消息占位
  addMessage(chatContent, true);
  addMessage('', false);

  // 滚动到底部
  setTimeout(() => {
    bubbleListRef.value?.scrollToBottom();
  }, 100);

  abortController = new AbortController();

  try {
    const response = await fetch(`${import.meta.env.VITE_WEB_BASE_API}/ai-chat/agent/send`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${userStore.token}`,
      },
      body: JSON.stringify({
        sessionId: currentSessionId,
        content: chatContent,
        tokenId: tokenId.value,
        modelId: modelId.value,
        tools: selectedTools.value,
      }),
      signal: abortController.signal,
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const reader = response.body?.getReader();
    if (!reader) throw new Error('No reader available');

    const decoder = new TextDecoder();
    let buffer = '';

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      buffer += decoder.decode(value, { stream: true });
      const lines = buffer.split('\n');
      buffer = lines.pop() || '';

      for (const line of lines) {
        if (line.startsWith('data: ')) {
          const data = line.slice(6).trim();
          if (data === '[DONE]') {
            break;
          }
          try {
            const parsed = JSON.parse(data) as AgentResultOutput;
            handleAgentChunk(parsed);
          } catch (e) {
            console.error('解析数据失败:', e);
          }
        }
      }
    }
  } catch (err: any) {
    if (err.name === 'AbortError') {
      console.log('请求已取消');
    } else {
      console.error('请求失败:', err);
      ElMessage.error(err.message || '请求失败');
    }
  } finally {
    isSending.value = false;
    abortController = null;
    // 停止加载状态
    if (bubbleItems.value.length) {
      const latest = bubbleItems.value[bubbleItems.value.length - 1];
      latest.loading = false;
    }
  }
}

// 取消请求
function cancelSSE() {
  if (abortController) {
    abortController.abort();
    isSending.value = false;
  }
}
</script>

<template>
  <div class="agent-page">
    <!-- 左侧会话列表 -->
    <div class="session-sidebar" :class="{ collapsed: !showSessionList }">
      <div class="sidebar-header">
        <span class="sidebar-title">会话列表</span>
        <el-button type="primary" :icon="Plus" circle size="small" @click="createNewSession" />
      </div>
      <div class="session-list">
        <div
          v-for="session in agentSessionStore.sessionList"
          :key="session.id"
          class="session-item"
          :class="{ active: sessionId === session.id }"
          @click="selectSession(session)"
        >
          <span class="session-title">{{ session.sessionTitle }}</span>
          <el-icon class="delete-icon" @click="handleDeleteSession(session, $event)">
            <Delete />
          </el-icon>
        </div>
        <div v-if="agentSessionStore.sessionList.length === 0" class="empty-tip">
          暂无会话记录
        </div>
      </div>
    </div>

    <!-- 右侧主内容区 -->
    <div class="main-content">
      <!-- 头部 -->
    <div class="agent-header">
      <div class="header-left">
        <el-icon :size="24" color="var(--el-color-primary)">
          <Tools />
        </el-icon>
        <span class="header-title">AI 智能体</span>
      </div>
      <div class="header-right">
        <el-button type="primary" plain size="small" @click="showToolsPanel = !showToolsPanel">
          <el-icon><Tools /></el-icon>
          <span>配置</span>
        </el-button>
      </div>
    </div>

    <!-- 工具配置面板 -->
    <el-collapse-transition>
      <div v-show="showToolsPanel" class="tools-panel">
        <div class="tools-header">
          <span>可用工具</span>
          <el-button link type="primary" size="small" @click="selectedTools = availableTools.map(t => t.code)">
            全选
          </el-button>
          <el-button link type="info" size="small" @click="selectedTools = []">
            清空
          </el-button>
        </div>
        <div class="tools-list">
          <div
            v-for="tool in availableTools"
            :key="tool.code"
            class="tool-item"
            :class="{ active: selectedTools.includes(tool.code) }"
            @click="toggleTool(tool.code)"
          >
            <el-icon v-if="selectedTools.includes(tool.code)" class="check-icon">
              <Check />
            </el-icon>
            <span>{{ tool.name }}</span>
          </div>
        </div>
        <div class="tools-config">
          <el-select
            v-model="tokenId"
            placeholder="请选择"
            size="small"
            style="width: 300px;"
            :loading="tokenLoading"
            clearable
          >
            <template #prefix>
              <span style="color: var(--el-text-color-regular);">API密钥（可选）</span>
            </template>
            <el-option
              v-for="token in tokenOptions"
              :key="token.tokenId"
              :label="token.name"
              :value="token.tokenId"
              :disabled="token.isDisabled"
            />
          </el-select>
          <!-- 模型ID固定为 gpt-5.2-chat，不允许用户修改 -->
          <!-- <el-input v-model="modelId" placeholder="请输入模型ID" size="small" style="width: 300px;">
            <template #prepend>模型</template>
          </el-input> -->
        </div>
      </div>
    </el-collapse-transition>

    <!-- 聊天区域 -->
    <div class="chat-area">
      <!-- 消息为空时的欢迎界面 -->
      <div v-if="bubbleItems.length === 0" class="welcome-container">
        <div class="welcome-icon">
          <img :src="agentAvatar" alt="Agent" class="welcome-avatar" />
        </div>
        <h2 class="welcome-title">意心Ai 智能体</h2>
        <p class="welcome-desc">我叫橙子老弟，我，啥都会</p>
        <div class="welcome-tips">
          <div class="tip-item">可选择 API 密钥后开始对话</div>
          <div class="tip-item">选择需要的工具来增强我的能力</div>
        </div>
      </div>

      <!-- 消息列表 -->
      <BubbleList v-else ref="bubbleListRef" :list="bubbleItems" max-height="calc(100vh - 320px)">
        <template #header="{ item }">
          <!-- 工具调用状态 -->
          <div v-if="item.toolCalls && item.toolCalls.length > 0" class="tool-calls-container">
            <div v-for="(tc, idx) in item.toolCalls" :key="idx" class="tool-call-item">
              <el-icon v-if="tc.status === 'calling'" class="is-loading">
                <Loading />
              </el-icon>
              <el-icon v-else color="var(--el-color-success)">
                <Check />
              </el-icon>
              <span class="tool-name">{{ tc.name }}</span>
              <span class="tool-status">{{ tc.status === 'calling' ? '调用中...' : '已完成' }}</span>
              <span v-if="tc.usage?.total" class="tool-usage">token: {{ tc.usage.total }}</span>
            </div>
          </div>
        </template>

        <template #content="{ item }">
          <MarkedMarkdown
            v-if="item.content && (item.role === 'assistant' || item.role === 'system')"
            class="markdown-body"
            :content="item.content"
          />
          <div v-if="item.role === 'user'" class="user-content">
            {{ item.content }}
          </div>
        </template>

        <template #footer="{ item }">
          <div v-if="item.tokenUsage?.total" class="footer-wrapper">
            <span class="footer-token">token: {{ item.tokenUsage.total }}</span>
          </div>
        </template>
      </BubbleList>

      <!-- 输入区域 -->
      <Sender
        v-model="inputValue"
        class="agent-sender"
        :auto-size="{ maxRows: 6, minRows: 2 }"
        variant="updown"
        clearable
        allow-speech
        :loading="isSending"
        :disabled="!tokenId"
        @submit="startSSE"
        @cancel="cancelSSE"
      >
        <template #suffix>
          <ElIcon v-if="isSending" class="is-loading">
            <Loading />
          </ElIcon>
        </template>
      </Sender>
    </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
.agent-page {
  display: flex;
  flex-direction: row;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
}

.session-sidebar {
  width: 240px;
  height: 100%;
  border-right: 1px solid var(--el-border-color-lighter);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  background: var(--el-bg-color);

  &.collapsed {
    width: 0;
    overflow: hidden;
  }

  .sidebar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px;
    border-bottom: 1px solid var(--el-border-color-lighter);

    .sidebar-title {
      font-weight: 600;
      font-size: 14px;
    }
  }

  .session-list {
    flex: 1;
    overflow-y: auto;
    padding: 8px;

    &::-webkit-scrollbar {
      width: 4px;
    }

    &::-webkit-scrollbar-track {
      background: transparent;
    }

    &::-webkit-scrollbar-thumb {
      background: var(--el-border-color-lighter);
      border-radius: 2px;

      &:hover {
        background: var(--el-border-color);
      }
    }
  }

  .session-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 12px;
    border-radius: 6px;
    cursor: pointer;
    margin-bottom: 4px;
    transition: all 0.2s;

    &:hover {
      background: var(--el-fill-color-light);

      .delete-icon {
        opacity: 1;
      }
    }

    &.active {
      background: var(--el-color-primary-light-9);
      color: var(--el-color-primary);
    }

    .session-title {
      flex: 1;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      font-size: 13px;
    }

    .delete-icon {
      opacity: 0;
      color: var(--el-text-color-secondary);
      transition: opacity 0.2s;

      &:hover {
        color: var(--el-color-danger);
      }
    }
  }

  .empty-tip {
    text-align: center;
    color: var(--el-text-color-secondary);
    font-size: 13px;
    padding: 20px;
  }
}

.main-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 0 20px;
  overflow: hidden;
}

.agent-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 60px;
  flex-shrink: 0;

  .header-left {
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .header-title {
    font-size: 18px;
    font-weight: 600;
    color: var(--el-text-color-primary);
  }
}

.tools-panel {
  background: var(--el-bg-color-page);
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 16px;

  .tools-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
    font-weight: 500;
  }

  .tools-list {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 16px;
  }

  .tool-item {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 6px 12px;
    border-radius: 16px;
    border: 1px solid var(--el-border-color);
    cursor: pointer;
    font-size: 13px;
    transition: all 0.2s;

    &:hover {
      border-color: var(--el-color-primary);
    }

    &.active {
      background: var(--el-color-primary-light-9);
      border-color: var(--el-color-primary);
      color: var(--el-color-primary);
    }

    .check-icon {
      font-size: 12px;
    }
  }

  .tools-config {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--el-border-color-lighter);
  }
}

.chat-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  max-width: 1000px;
  width: 100%;
  margin: 0 auto;
  overflow: hidden;
}

.welcome-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 40px 20px;

  .welcome-icon {
    margin-bottom: 20px;

    .welcome-avatar {
      width: 80px;
      height: 80px;
      border-radius: 50%;
      object-fit: cover;
    }
  }

  .welcome-title {
    font-size: 24px;
    font-weight: 600;
    margin: 0 0 12px;
    color: var(--el-text-color-primary);
  }

  .welcome-desc {
    font-size: 14px;
    color: var(--el-text-color-secondary);
    margin: 0 0 24px;
  }

  .welcome-tips {
    display: flex;
    flex-direction: column;
    gap: 8px;

    .tip-item {
      font-size: 13px;
      color: var(--el-text-color-regular);
      padding: 8px 16px;
      background: var(--el-fill-color-light);
      border-radius: 6px;
    }
  }
}

.tool-calls-container {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 12px;
  padding: 8px 12px;
  background: var(--el-fill-color-lighter);
  border-radius: 8px;
  border-left: 3px solid var(--el-color-primary);
}

.tool-call-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;

  .tool-name {
    font-weight: 500;
    color: var(--el-text-color-primary);
  }

  .tool-status {
    color: var(--el-text-color-secondary);
    font-size: 12px;
  }

  .tool-usage {
    font-size: 11px;
    background: rgba(255, 153, 0, 0.6);
    padding: 1px 6px;
    border-radius: 4px;
    color: #ffffff;
    margin-left: auto;
  }
}

.user-content {
  white-space: pre-wrap;
  word-break: break-word;
}

.footer-wrapper {
  margin-top: 4px;

  .footer-token {
    font-size: 12px;
    background: rgba(1, 183, 86, 0.53);
    padding: 2px 6px;
    border-radius: 4px;
    color: #ffffff;
  }
}

.agent-sender {
  margin-top: auto;
  margin-bottom: 20px;
}

.is-loading {
  animation: rotating 2s linear infinite;
}

@keyframes rotating {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

:deep(.el-bubble-list) {
  padding-top: 24px;
}

:deep(.el-bubble) {
  padding: 0 12px;
  padding-bottom: 24px;
}

:deep(.markdown-body) {
  background-color: transparent;
}

/* 移动端适配 */
@media (max-width: 768px) {
  .agent-page {
    padding: 0 12px;
  }

  .agent-header {
    height: 50px;

    .header-title {
      font-size: 16px;
    }
  }

  .tools-panel {
    padding: 12px;

    .tools-config {
      flex-direction: column;

      :deep(.el-input) {
        width: 100% !important;
        margin-right: 0 !important;
      }
    }
  }

  .welcome-container {
    padding: 20px 12px;

    .welcome-title {
      font-size: 20px;
    }
  }
}
</style>
