<template>
  <div class="page-content">
    <div class="mb-5 flex items-center justify-between gap-4">
      <div>
        <h2 class="text-xl font-semibold">通用聊天</h2>
        <p class="text-g-500 mt-1 text-sm">直接与已获批准接入的模型对话，用量与审计归属到你的账号；新模型请先在「模型权限」申请</p>
      </div>
      <div class="flex items-center gap-3">
        <ElSelect v-model="selectedModel" placeholder="选择模型" class="w-72" filterable @change="onModelChange">
          <ElOptionGroup v-for="group in modelGroups" :key="group.provider" :label="group.provider">
            <ElOption v-for="m in group.models" :key="m.model" :label="m.model" :value="`${m.provider_code}\n${m.model}`" />
          </ElOptionGroup>
        </ElSelect>
        <ElButton type="primary" :disabled="!selectedModel" @click="newChat">新会话</ElButton>
      </div>
    </div>

    <ElEmpty v-if="!loading && !models.length" description="暂无已批准的模型，请先在「模型权限」页申请">
      <ElButton type="primary" @click="$router.push('/portal/access')">去申请</ElButton>
    </ElEmpty>

    <div v-else class="flex gap-4" style="height: calc(100vh - 220px)">
      <!-- 会话列表 -->
      <div class="w-64 shrink-0 overflow-auto rounded-lg border border-g-200 bg-white">
        <div class="border-b border-g-100 px-3 py-2 text-sm font-medium text-g-500">会话历史</div>
        <div
          v-for="session in sessions"
          :key="session.id"
          class="group cursor-pointer border-b border-g-100 px-3 py-2 hover:bg-g-50"
          :class="currentId === session.id ? 'bg-primary-50' : ''"
          @click="openSession(session)"
        >
          <div class="flex items-center justify-between gap-2">
            <div class="min-w-0">
              <div class="truncate text-sm">{{ session.title || session.model }}</div>
              <div class="text-g-400 mt-0.5 truncate text-xs">{{ session.model }}</div>
            </div>
            <div class="hidden shrink-0 gap-1 group-hover:flex">
              <ElButton link size="small" @click.stop="rename(session)">改名</ElButton>
              <ElButton link size="small" type="danger" @click.stop="remove(session)">删除</ElButton>
            </div>
          </div>
        </div>
        <ElEmpty v-if="!sessions.length" description="暂无会话" :image-size="60" />
      </div>

      <!-- 对话区 -->
      <div class="flex min-w-0 flex-1 flex-col rounded-lg border border-g-200 bg-white">
        <div class="flex-1 space-y-4 overflow-auto p-4" ref="scrollRef">
          <ElEmpty v-if="!messages.length" description="开始你的第一轮对话吧" :image-size="80" />
          <div v-for="message in messages" :key="message.sequence" class="flex" :class="message.role === 'user' ? 'justify-end' : 'justify-start'">
            <div
              class="max-w-[80%] whitespace-pre-wrap break-words rounded-lg px-3 py-2 text-sm"
              :class="message.role === 'user' ? 'bg-primary-600 text-white' : 'bg-g-100 text-g-800'"
            >{{ message.content }}</div>
          </div>
        </div>
        <div class="border-t border-g-100 p-3">
          <ElInput
            v-model="draft"
            type="textarea"
            :rows="3"
            maxlength="100000"
            resize="none"
            placeholder="输入消息，Enter 发送，Shift+Enter 换行"
            @keydown.enter.exact.prevent="send"
          />
          <div class="mt-2 flex items-center justify-between">
            <span class="text-g-400 text-xs">{{ sending ? '模型思考中…' : `${draft.length} / 100000` }}</span>
            <ElButton type="primary" :loading="sending" :disabled="!draft.trim()" @click="send">发送</ElButton>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ElMessage, ElMessageBox } from 'element-plus'
import {
  ChatMessage, ChatModel, ChatSession,
  appendChatMessage, createChatSession, deleteChatSession, fetchChatModels,
  fetchChatSession, fetchChatSessions, renameChatSession
} from '@/api/portal'

const loading = ref(false)
const sending = ref(false)
const models = ref<ChatModel[]>([])
const sessions = ref<ChatSession[]>([])
const currentId = ref('')
const messages = ref<ChatMessage[]>([])
const draft = ref('')
const selectedModel = ref('')
const scrollRef = ref<HTMLElement>()

const modelGroups = computed(() => {
  const groups: { provider: string; models: ChatModel[] }[] = []
  const index = new Map<string, ChatModel[]>()
  for (const m of models.value) {
    if (!index.has(m.provider_code)) index.set(m.provider_code, [])
    index.get(m.provider_code)!.push(m)
  }
  for (const [provider, list] of index) groups.push({ provider, models: list })
  return groups
})

function modelOf(value: string): { provider_code: string; model: string } {
  const [provider_code, model] = value.split('\n')
  return { provider_code: provider_code || '', model: model || '' }
}

async function loadAll() {
  loading.value = true
  try {
    const [modelList, sessionList] = await Promise.all([fetchChatModels(), fetchChatSessions()])
    models.value = modelList
    sessions.value = sessionList
    if (models.value.length && !selectedModel.value) {
      selectedModel.value = `${models.value[0].provider_code}\n${models.value[0].model}`
    }
  } finally {
    loading.value = false
  }
}

function onModelChange() {
  currentId.value = ''
  messages.value = []
}

function scrollToBottom() {
  nextTick(() => scrollRef.value?.scrollTo({ top: scrollRef.value.scrollHeight }))
}

async function newChat() {
  if (!selectedModel.value) return
  const { provider_code, model } = modelOf(selectedModel.value)
  sending.value = true
  try {
    const session = await createChatSession({ provider_code, model })
    sessions.value.unshift(session)
    currentId.value = session.id
    messages.value = []
    draft.value = ''
    ElMessage.success('已创建新会话')
  } catch (error) {
    ElMessage.error('创建会话失败，请确认模型已批准且可用')
  } finally {
    sending.value = false
  }
}

async function openSession(session: ChatSession) {
  currentId.value = session.id
  const detail = await fetchChatSession(session.id)
  messages.value = detail.messages || []
  scrollToBottom()
}

async function send() {
  const text = draft.value.trim()
  if (!text || sending.value) return
  if (!currentId.value) {
    if (!selectedModel.value) {
      ElMessage.warning('请先选择模型')
      return
    }
    await newChat()
    if (!currentId.value) return
  }
  sending.value = true
  const id = currentId.value
  messages.value.push({ sequence: messages.value.length + 1, role: 'user', content: text, created_at: '' })
  draft.value = ''
  scrollToBottom()
  try {
    const response = await appendChatMessage(id, text)
    const choices = (response.choices as Array<{ message?: { content?: string } }>) || []
    const answer = choices[0]?.message?.content || ''
    messages.value.push({ sequence: messages.value.length + 1, role: 'assistant', content: answer, created_at: '' })
    const session = sessions.value.find((item) => item.id === id)
    if (session && !session.title) session.title = text.slice(0, 60)
  } catch (error) {
    const message = (error as Error)?.message || '调用失败'
    ElMessage.error(message)
  } finally {
    sending.value = false
    scrollToBottom()
  }
}

async function rename(session: ChatSession) {
  const { value } = await ElMessageBox.prompt('输入新的会话标题', '重命名会话', { inputValue: session.title || session.model, inputValidator: (v: string) => (v.trim() ? true : '标题不能为空') })
  if (value) {
    await renameChatSession(session.id, value.trim())
    session.title = value.trim()
    ElMessage.success('已重命名')
  }
}

async function remove(session: ChatSession) {
  await ElMessageBox.confirm('删除后会话记录不可恢复，确定删除？', '删除会话', { type: 'warning' })
  await deleteChatSession(session.id)
  sessions.value = sessions.value.filter((item) => item.id !== session.id)
  if (currentId.value === session.id) {
    currentId.value = ''
    messages.value = []
  }
  ElMessage.success('已删除')
}

onMounted(loadAll)
</script>
