<template>
  <AppShell>
    <div class="flex h-[calc(100vh-8rem)] -m-6">
      <!-- 左侧会话列表 -->
      <div class="w-72 border-r overflow-y-auto p-2 flex flex-col gap-1">
        <NButton
          block
          class="mb-2"
          @click="showCreate = true"
        >
          + 新建对话
        </NButton>
        <div
          v-for="c in chat.conversations"
          :key="c.id"
          :class="[
            'p-2 rounded cursor-pointer hover:bg-neutral-100',
            chat.currentConversation?.id === c.id ? 'bg-blue-50' : '',
          ]"
          @click="open(c.id)"
        >
          <div class="truncate text-sm">
            {{ c.title || '(未命名)' }}
          </div>
          <div class="text-xs text-neutral-400">
            {{ formatTime(c.updated_at) }}
          </div>
        </div>
        <div
          v-if="chat.conversations.length === 0"
          class="text-xs text-neutral-400 px-2"
        >
          暂无对话
        </div>
      </div>

      <!-- 右侧消息流 -->
      <div class="flex-1 flex flex-col">
        <div
          v-if="!chat.currentConversation"
          class="flex-1 flex items-center justify-center text-neutral-400"
        >
          选择或新建会话
        </div>
        <template v-else>
          <div
            ref="scrollEl"
            class="flex-1 overflow-y-auto p-4 space-y-3"
          >
            <MessageBubble
              v-for="m in chat.messages"
              :key="m.id"
              :message="m"
              @retry="onRetry"
            />
          </div>
          <div class="border-t p-3 space-y-2">
            <AttachmentUploader
              ref="uploaderRef"
              :model-capabilities="currentModelCaps"
              @change="onAttachmentChange"
            />
            <div class="flex gap-2">
              <NInput
                v-model:value="draft"
                type="textarea"
                :autosize="{ minRows: 1, maxRows: 6 }"
                placeholder="发送消息（Enter 发送，Shift+Enter 换行）"
                :disabled="chat.isStreaming"
                @keydown.enter.exact.prevent="send"
              />
              <NButton
                v-if="!chat.isStreaming"
                type="primary"
                :disabled="!draft.trim()"
                @click="send"
              >
                发送
              </NButton>
              <NButton
                v-else
                type="warning"
                @click="chat.cancelMessage"
              >
                中断
              </NButton>
            </div>
          </div>
        </template>
      </div>

      <ConversationCreateModal
        v-model:show="showCreate"
        :project-id="projectId"
        @created="onCreated"
      />
    </div>
  </AppShell>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { NButton, NInput } from 'naive-ui'

import AppShell from '@/layouts/AppShell.vue'
import { useChatStore } from '@/stores/chat'
import MessageBubble from './components/MessageBubble.vue'
import AttachmentUploader from './components/AttachmentUploader.vue'
import ConversationCreateModal from './ConversationCreateModal.vue'
import { llmAdminApi, type LLMModel, type ModelCapabilities } from '@/api/llmAdmin'

const chat = useChatStore()
const route = useRoute()
const router = useRouter()

const draft = ref('')
const attachmentIds = ref<string[]>([])
const showCreate = ref(false)
const uploaderRef = ref<InstanceType<typeof AttachmentUploader> | null>(null)
const scrollEl = ref<HTMLElement | null>(null)
const allModels = ref<LLMModel[]>([])

const projectId = computed(() => {
  const v = route.params.pid
  return typeof v === 'string' && v !== '' ? v : undefined
})

const defaultCaps: ModelCapabilities = {
  image: false,
  pdf: false,
  audio: false,
  reasoning: false,
  tools: false,
}

const currentModelCaps = computed<ModelCapabilities>(() => {
  const id = chat.currentConversation?.model_id
  if (!id) return defaultCaps
  const m = allModels.value.find((x) => x.id === id)
  return m?.capabilities ?? defaultCaps
})

onMounted(async () => {
  allModels.value = await llmAdminApi.listModels(true)
  await chat.loadConversations({ project_id: projectId.value })
  const cid = route.params.conversationId
  if (typeof cid === 'string' && cid !== '') {
    await open(cid)
  }
})

watch(
  () => chat.messages.length,
  () => {
    nextTick(() => {
      const el = scrollEl.value
      if (el) el.scrollTo(0, el.scrollHeight)
    })
  },
)

async function open(id: string) {
  await chat.openConversation(id)
  await router.replace({
    path: projectId.value ? `/projects/${projectId.value}/chat/${id}` : `/chat/${id}`,
  })
}

async function send() {
  if (!draft.value.trim() || chat.isStreaming) return
  const body = draft.value
  const ids = [...attachmentIds.value]
  draft.value = ''
  uploaderRef.value?.clear()
  attachmentIds.value = []
  await chat.sendMessage(body, ids)
}

function onAttachmentChange(ids: string[]) {
  attachmentIds.value = ids
}

function onRetry(id: number) {
  chat.retryMessage(id)
}

async function onCreated(id: string) {
  await chat.loadConversations({ project_id: projectId.value })
  await open(id)
}

function formatTime(iso: string) {
  return new Date(iso).toLocaleString('zh-CN', { hour12: false })
}
</script>
