<script setup lang="ts">
import { ref, reactive, nextTick, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import MarkdownView from '@/components/MarkdownView.vue'
import { useStreamChat } from '@/composables/useStreamChat'
import { getCompare } from '@/api/modules/compare'
import type { CompareTask, LoadedModel } from '@/types'

const route = useRoute()
const router = useRouter()
const taskId = route.params.id as string
/** 是否为 mock 直通模式（新建推理假数据进入，不走真实任务接口） */
const isMock = taskId === 'mock'
/** 当前对话使用的模型名 */
const modelName = ref(route.query.model as string || '')

const { message, loading, send, reset } = useStreamChat()

interface ChatMessage {
  role: 'user' | 'assistant'
  content: string
  think?: string
  isThinking?: boolean
  isStreaming?: boolean
  done: boolean
}

const task = ref<CompareTask | null>(null)
const messages = ref<ChatMessage[]>([])
const inputQuestion = ref('')
const systemPrompt = ref('')
const temperature = ref(0.7)
const top_p = ref(0.95)
const maxTokens = ref(2048)
const contentRef = ref<HTMLElement>()
let activeAssistant: ChatMessage | null = null
/** 设置面板抽屉 */
const showSettings = ref(false)

/** 获取任务信息，定位已启动的模型（mock 模式跳过） */
async function loadTask() {
  if (isMock) return
  try {
    task.value = await getCompare(taskId)
    const models = parseLoadedModels(task.value)
    if (models[0]?.model_name) modelName.value = models[0].model_name
  } catch {
    // ignore
  }
}

function parseLoadedModels(t: CompareTask | null): LoadedModel[] {
  if (!t?.load_status) return []
  try {
    const ls = typeof t.load_status === 'string' ? JSON.parse(t.load_status) : t.load_status
    return ls.loaded_models || []
  } catch {
    return []
  }
}

async function handleSend() {
  const question = inputQuestion.value.trim()
  if (!question || loading.value) return

  // 推入用户消息
  messages.value.push({ role: 'user', content: question, done: true })
  // 推入占位助手消息
  const assistantMsg = reactive<ChatMessage>({
    role: 'assistant',
    content: '',
    think: '',
    isThinking: false,
    isStreaming: true,
    done: false,
  })
  messages.value.push(assistantMsg)

  inputQuestion.value = ''
  await nextTick()
  resetInputHeight()
  scrollToBottom()

  // mock 模式：直接用假数据逐字填充
  if (isMock) {
    await mockReply(assistantMsg, question)
    return
  }

  // 真实模式：获取已启动模型的端口/路径
  const models = parseLoadedModels(task.value)
  const target = models[0]
  if (!target) {
    ElMessage.error('未找到已启动的模型')
    assistantMsg.content = '未找到已启动的模型，请先返回列表加载模型'
    assistantMsg.done = true
    assistantMsg.isStreaming = false
    return
  }

  // 流式状态变化时只同步当前回复，避免固定定时器空转。
  activeAssistant = assistantMsg

  await send({
    port: target.port,
    model_name: target.model_name,
    model_path: '',
    system_prompt: systemPrompt.value,
    user_question: question,
    temperature: temperature.value,
    top_p: top_p.value,
    max_tokens: maxTokens.value,
  })

  // 完成后同步最终内容
  assistantMsg.content = message.value.displayContent || message.value.error || '(无回复)'
  assistantMsg.think = message.value.thinkContent
  assistantMsg.isThinking = false
  assistantMsg.isStreaming = false
  assistantMsg.done = true
  activeAssistant = null
  reset()
  await nextTick()
  scrollToBottom()
}

/**
 * Mock 模式：生成假回答并逐字填入消息（模拟流式效果）
 */
async function mockReply(assistantMsg: ChatMessage, question: string) {
  const answer =
    `你好！我是 **${modelName.value || '示例模型'}**（mock 演示）。\n\n` +
    `你刚才问的是：\n\n> ${question}\n\n` +
    `这是一段模拟回复，用于演示对话界面。接入真实模型后，这里会展示模型的真实推理输出。\n\n` +
    `## 说明\n- 当前为前端 mock 环境\n- 回复内容由本地生成\n- 流式打字效果为前端模拟`
  // 逐字填充，模拟流式
  for (const ch of answer) {
    assistantMsg.content += ch
    await nextTick()
    scrollToBottom()
    // 每 3 个字符暂停一下，控制速度
    if (assistantMsg.content.length % 3 === 0) {
      await new Promise((r) => setTimeout(r, 16))
    }
  }
  assistantMsg.isStreaming = false
  assistantMsg.done = true
  await nextTick()
  scrollToBottom()
}

watch(
  () => [
    message.value.displayContent,
    message.value.thinkContent,
    message.value.isThinking,
    message.value.done,
  ] as const,
  async ([content, think, isThinking, done]) => {
    if (!activeAssistant) return
    activeAssistant.content = content
    activeAssistant.think = think
    activeAssistant.isThinking = isThinking
    activeAssistant.isStreaming = !done
    await nextTick()
    scrollToBottom()
  },
  { flush: 'post' },
)

function scrollToBottom() {
  if (contentRef.value) {
    contentRef.value.scrollTop = contentRef.value.scrollHeight
  }
}

function handleNewChat() {
  activeAssistant = null
  messages.value = []
  reset()
}

/** 输入框自适应高度 */
function autoResize(e: Event) {
  const el = e.target as HTMLTextAreaElement
  el.style.height = 'auto'
  el.style.height = Math.min(el.scrollHeight, 120) + 'px'
}

/** 重置输入框高度 */
function resetInputHeight() {
  const el = document.querySelector('.input-box') as HTMLTextAreaElement
  if (el) el.style.height = 'auto'
}

onMounted(loadTask)
</script>

<template>
  <div class="chat-wrap">
    <!-- 顶部栏 -->
    <header class="chat-header">
      <div class="header-left">
        <div class="header-title">
          <span class="title-text">{{ modelName || '模型对话' }}</span>
          <span v-if="isMock" class="mock-badge">mock</span>
        </div>
      </div>
      <button class="header-btn" title="设置" @click="showSettings = true">
        <i class="fa fa-sliders" />
      </button>
    </header>

    <!-- 消息列表 -->
    <div ref="contentRef" class="chat-body">
      <div class="chat-body-inner">
        <div v-if="messages.length === 0" class="empty-hint">
          <div class="empty-logo">
            <i class="fa fa-cube" />
          </div>
          <h2>有什么我可以帮你的吗？</h2>
          <p>开始与 {{ modelName || '模型' }} 对话</p>
        </div>
        
        <div
          v-for="(msg, idx) in messages"
          :key="idx"
          class="msg-row"
          :class="msg.role"
        >
          <!-- 头像 -->
          <div v-if="msg.role === 'assistant'" class="avatar assistant">
            <i class="fa fa-robot" />
          </div>
          
          <!-- 消息内容 -->
          <div class="bubble-wrap">
            <!-- 思考过程（可折叠） -->
            <el-collapse v-if="msg.think" class="think-collapse">
              <el-collapse-item title="思考过程" name="think">
                <div class="think-content">{{ msg.think }}</div>
              </el-collapse-item>
            </el-collapse>
            
            <div v-if="msg.role === 'user'" class="bubble user-bubble">
              {{ msg.content }}
            </div>
            
            <div v-else-if="msg.done" class="bubble ai-bubble markdown">
              <MarkdownView :content="msg.content" />
            </div>
            
            <div v-else class="bubble ai-bubble streaming">
              <span>{{ msg.content || (msg.isThinking ? '思考中...' : '生成中') }}</span>
              <span class="typing-cursor" />
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 输入栏 -->
    <footer class="chat-input-container">
      <div class="chat-input-inner">
        <button class="clear-btn" title="清空对话" @click="handleNewChat">
          <i class="fa fa-eraser" />
        </button>
        <div class="input-wrapper">
          <textarea
            v-model="inputQuestion"
            class="input-box"
            rows="1"
            :disabled="loading"
            placeholder="给模型发送消息..."
            @keydown.enter.exact.prevent="handleSend"
            @input="autoResize"
          />
          <button
            class="send-btn"
            :class="{ active: inputQuestion.trim() && !loading }"
            :disabled="!inputQuestion.trim() || loading"
            @click="handleSend"
          >
            <i class="fa fa-arrow-up" />
          </button>
        </div>
      </div>
      <div class="footer-hint">内容由 AI 生成，请仔细甄别。</div>
    </footer>

    <!-- 设置抽屉（系统提示词等） -->
    <el-drawer v-model="showSettings" title="对话设置" size="360px">
      <el-form label-position="top">
        <el-form-item label="系统提示词">
          <el-input
            v-model="systemPrompt"
            type="textarea"
            :rows="6"
            placeholder="设置模型角色/约束（可选）"
            resize="none"
          />
        </el-form-item>
        
        <el-form-item label="Temperature (温度)">
          <el-slider v-model="temperature" :min="0" :max="2" :step="0.1" show-input />
        </el-form-item>
        
        <el-form-item label="Top P (核心采样)">
          <el-slider v-model="top_p" :min="0" :max="1" :step="0.05" show-input />
        </el-form-item>
        
        <el-form-item label="Max Tokens (最大生成长度)">
          <el-slider v-model="maxTokens" :min="128" :max="8192" :step="128" show-input />
        </el-form-item>

        <el-form-item>
          <el-button type="danger" plain @click="handleNewChat" style="width: 100%; margin-top: 20px;">
            <i class="fa fa-trash-o" style="margin-right: 4px" />清空当前对话
          </el-button>
        </el-form-item>
      </el-form>
    </el-drawer>
  </div>
</template>

<style scoped lang="scss">
.chat-wrap {
  height: calc(100vh - 80px);
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  background: #ffffff;
  border-radius: 12px;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);
  overflow: hidden;
  border: 1px solid #f3f4f6;
}

/* ============ 顶部栏 ============ */
.chat-header {
  flex-shrink: 0;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 20px;
  background: #ffffff;
  border-bottom: 1px solid #f3f4f6;

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

  .header-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 16px;
    font-weight: 600;
    color: #111827;

    .title-text {
      max-width: 300px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .mock-badge {
      padding: 2px 6px;
      font-size: 11px;
      font-weight: 600;
      color: #b45309;
      background: #fef3c7;
      border-radius: 4px;
      text-transform: uppercase;
    }
  }

  .header-btn {
    width: 36px;
    height: 36px;
    border: none;
    background: transparent;
    border-radius: 8px;
    font-size: 18px;
    color: #6b7280;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s;

    &:hover {
      background: #f3f4f6;
      color: #111827;
    }
  }
}

/* ============ 消息列表 ============ */
.chat-body {
  flex: 1;
  overflow-y: auto;
  padding: 24px 0;
  scroll-behavior: smooth;
  
  /* 隐藏滚动条但保留功能 */
  &::-webkit-scrollbar {
    width: 6px;
  }
  &::-webkit-scrollbar-thumb {
    background: #e5e7eb;
    border-radius: 3px;
  }
  &::-webkit-scrollbar-track {
    background: transparent;
  }
}

.chat-body-inner {
  max-width: 800px;
  margin: 0 auto;
  padding: 0 20px;
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.empty-hint {
  margin-top: 10vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #6b7280;

  .empty-logo {
    width: 64px;
    height: 64px;
    border-radius: 16px;
    background: #f3f4f6;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 24px;
    
    i {
      font-size: 32px;
      color: #9ca3af;
    }
  }

  h2 {
    font-size: 24px;
    font-weight: 600;
    color: #111827;
    margin: 0 0 8px 0;
  }

  p {
    margin: 0;
    font-size: 15px;
  }
}

.msg-row {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  width: 100%;

  /* 用户消息：靠右排列 */
  &.user {
    flex-direction: row-reverse;
  }

  /* AI 消息：靠左排列 */
  &.assistant {
    flex-direction: row;
  }
}

/* 头像 */
.avatar {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 16px;
  
  &.assistant {
    background: #111827;
  }
}

/* 气泡容器 */
.bubble-wrap {
  max-width: 85%;
  min-width: 0;
}

/* 气泡 */
.bubble {
  font-size: 15px;
  line-height: 1.6;
  word-break: break-word;
  white-space: pre-wrap;
}

.user-bubble {
  background: #f3f4f6;
  color: #111827;
  padding: 12px 20px;
  border-radius: 20px;
  border-top-right-radius: 4px;
}

.ai-bubble {
  color: #111827;
  padding: 4px 0;
  
  &.markdown {
    white-space: normal;

    :deep(.markdown-view p:last-child) {
      margin-bottom: 0;
    }
    
    :deep(pre) {
      border-radius: 8px;
      background: #f9fafb !important;
      border: 1px solid #e5e7eb;
      margin: 12px 0;
    }
    
    :deep(code) {
      background: #f3f4f6;
      padding: 2px 6px;
      border-radius: 4px;
      font-size: 0.9em;
    }
  }
}

/* 思考过程折叠 */
.think-collapse {
  margin-bottom: 12px;
  max-width: 100%;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  background: #f9fafb;
  overflow: hidden;

  :deep(.el-collapse-item__header) {
    padding: 0 16px;
    font-size: 13px;
    font-weight: 500;
    color: #6b7280;
    height: 36px;
    background: transparent;
    border-bottom: none;
  }

  :deep(.el-collapse-item__wrap) {
    border-bottom: none;
    background: transparent;
  }

  .think-content {
    padding: 0 16px 12px;
    font-size: 13px;
    color: #4b5563;
    line-height: 1.6;
    white-space: pre-wrap;
    border-top: 1px dashed #e5e7eb;
    margin-top: 4px;
    padding-top: 12px;
  }
}

/* 流式打字光标 */
.streaming .typing-cursor {
  display: inline-block;
  width: 4px;
  height: 16px;
  background: #111827;
  border-radius: 2px;
  margin-left: 4px;
  vertical-align: middle;
  animation: blink 1s steps(1) infinite;
}

@keyframes blink {
  0%, 50% { opacity: 1; }
  51%, 100% { opacity: 0; }
}

/* ============ 输入栏 ============ */
.chat-input-container {
  flex-shrink: 0;
  padding: 16px 20px 24px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, #ffffff 20%);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.chat-input-inner {
  width: 100%;
  max-width: 800px;
  display: flex;
  align-items: flex-end;
  gap: 12px;
}

.clear-btn {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  margin-bottom: 4px;
  border: 1px solid #e5e7eb;
  background: #ffffff;
  border-radius: 50%;
  font-size: 16px;
  color: #6b7280;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);

  &:hover {
    background: #f9fafb;
    color: #ef4444;
    border-color: #fca5a5;
  }
}

.input-wrapper {
  flex: 1;
  position: relative;
  background: #f4f4f5;
  border-radius: 24px;
  padding: 8px 16px;
  display: flex;
  align-items: flex-end;
  transition: all 0.2s;
  border: 1px solid transparent;
  
  &:focus-within {
    background: #ffffff;
    border-color: #d1d5db;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.03);
  }
}

.input-box {
  flex: 1;
  max-height: 200px;
  padding: 4px 44px 4px 0;
  border: none;
  background: transparent;
  font-size: 15px;
  line-height: 1.5;
  color: #111827;
  resize: none;
  outline: none;
  font-family: inherit;

  &::placeholder {
    color: #9ca3af;
  }
}

.send-btn {
  position: absolute;
  right: 12px;
  bottom: 8px;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 50%;
  background: #e5e7eb;
  color: #ffffff;
  font-size: 14px;
  cursor: not-allowed;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;

  &.active {
    background: #111827;
    cursor: pointer;

    &:hover {
      background: #374151;
      transform: translateY(-1px);
    }
    
    &:active {
      transform: translateY(1px);
    }
  }
}

.footer-hint {
  margin-top: 12px;
  font-size: 12px;
  color: #9ca3af;
}
</style>
