<template>
  <div class="chat-panel">
    <!-- Config bar -->
    <div class="chat-config-bar">
      <span class="config-label">对话</span>
      <a-button size="small" @click="showConfig = true">
        <SettingOutlined />
      </a-button>
    </div>

    <!-- Messages -->
    <div class="chat-messages" ref="messagesRef">
      <div v-if="!messages.length && !isStreaming" class="chat-welcome">
        <div class="welcome-title">开始对话</div>
        <div class="welcome-desc">基于左侧来源材料进行问答。AI 仅引用已添加的来源内容。</div>
      </div>

      <template v-for="msg in messages" :key="msg.id">
        <ChatMessage
          :message="{ role: msg.role, content: msg.content || '', references: msg.references, timestamp: msg.created_at ? new Date(msg.created_at).getTime() : Date.now() }"
          @reference-click="(idx: number) => handleReferenceClickForMessage(idx, msg.references || [])"
        />
        <!-- Per-message references grouped by document -->
        <div v-if="showRefList && msg.role === 'assistant' && msg.references?.length" class="references-section">
          <div class="references-label">引用来源</div>
          <div class="references-list">
            <div
              v-for="(group, gIdx) in groupRefsByDoc(msg.references, msg.content)"
              :key="group.doc_id"
              class="ref-group-card"
              @click="handleOpenReference(group)"
            >
              <div class="ref-group-header">
                <span class="ref-group-index">{{ gIdx + 1 }}.</span>
                <span class="ref-group-title">{{ group.title || group.doc_id }}</span>
              </div>
              <div class="ref-group-indices">
                <a-tag v-for="idx in group.indices" :key="idx" color="blue" size="small">[{{ idx }}]</a-tag>
              </div>
            </div>
          </div>
        </div>
      </template>

      <!-- Streaming message -->

      <ChatMessage
        v-if="isStreaming && currentContent"
        :message="{ role: 'assistant', content: currentContent, timestamp: Date.now() }"
        @reference-click="(idx: number) => handleReferenceClickForMessage(idx, references)"
      />

      <!-- Streaming references grouped by document -->
      <div v-if="showRefList && isStreaming && references.length" class="references-section">
        <div class="references-label">引用来源</div>
        <div class="references-list">
          <div
            v-for="(group, gIdx) in groupRefsByDoc(references, currentContent)"
            :key="group.doc_id"
            class="ref-group-card"
            @click="handleOpenReference(group)"
          >
            <div class="ref-group-header">
              <span class="ref-group-index">{{ gIdx + 1 }}.</span>
              <span class="ref-group-title">{{ group.title || group.doc_id }}</span>
            </div>
            <div class="ref-group-indices">
              <a-tag v-for="idx in group.indices" :key="idx" color="blue" size="small">[{{ idx }}]</a-tag>
            </div>
          </div>
      </div>
      <!-- Suggested questions (inside scroll area, after last message) -->
      <SuggestedQuestions
        v-if="!isStreaming && suggestions.length"
        :suggestions="suggestions"
        @select="handleSendMessage"
      />
      </div>
    </div>

    <!-- Input -->
    <div class="chat-input-wrapper">
      <div class="chat-input-box">
        <a-textarea
          v-model:value="inputText"
          placeholder="输入问题… (Shift+Enter 换行)"
          :auto-size="{ minRows: 2, maxRows: 6 }"
          :disabled="isStreaming"
          :bordered="false"
          @keydown.enter="handleEnter"
        />
        <div class="chat-input-footer">
          <span class="input-hint">Enter 发送，Shift+Enter 换行</span>
          <a-button
            type="primary"
            shape="circle"
            size="small"
            :disabled="!inputText.trim() || isStreaming"
            :loading="isStreaming"
            class="send-btn"
            @click="handleSendMessage(inputText)"
          >
            <template #icon><SendOutlined /></template>
          </a-button>
        </div>
      </div>
    </div>

    <!-- Config drawer -->
    <ChatConfigDrawer
      :open="showConfig"
      :notebook-id="notebookId"
      @close="showConfig = false"
    />

    <!-- Document preview -->
    <DocumentQuickPreview
      v-if="previewDocId"
      :doc-id="previewDocId"
      :open="previewOpen"
      :matched-chunks="previewChunks"
      :highlights="previewHighlights"
      @update:open="(val: boolean) => { if (!val) { previewDocId = ''; previewOpen = false } }"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, nextTick } from 'vue'
import { SettingOutlined, SendOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import ChatMessage from '@/components/ChatMessage.vue'
import DocumentQuickPreview from '@/components/DocumentQuickPreview.vue'
import SuggestedQuestions from './SuggestedQuestions.vue'
import ChatConfigDrawer from './ChatConfigDrawer.vue'
import { useNotebookStore } from '@/stores/notebook'
import { useSSE } from '@/composables/useSSE'
import { buildChatUrl } from '@/api/notebook'

const props = defineProps<{
  notebookId: string
}>()

const store = useNotebookStore()
const messages = computed(() => store.messages)
const references = computed(() => store.references)
const suggestions = computed(() => store.suggestions)
const isStreaming = computed(() => store.isStreaming)
const currentContent = computed(() => store.currentAssistantContent)
const showRefList = ref(false)

const hasReadySources = computed(
  () => store.selectedSources.length > 0,
)

const inputText = ref('')
const showConfig = ref(false)
const previewDocId = ref('')
const previewOpen = ref(false)
const previewChunks = ref<any[]>([])
const previewHighlights = ref<string[]>([])
const messagesRef = ref<HTMLElement>()

const { connect } = useSSE()

function scrollToBottom() {
  nextTick(() => {
    if (messagesRef.value) {
      messagesRef.value.scrollTop = messagesRef.value.scrollHeight
    }
  })
}

function handleEnter(e: KeyboardEvent) {
  if (e.shiftKey) return // Shift+Enter: allow newline
  e.preventDefault() // Enter alone: send message
  handleSendMessage(inputText.value)
}

async function handleSendMessage(text: string) {
  const question = typeof text === 'string' ? text.trim() : inputText.value.trim()
  if (!question || isStreaming.value) return

  inputText.value = ''
  store.addUserMessage(question)
  store.startStreaming()
  scrollToBottom()

  try {
    await connect({
      url: buildChatUrl(props.notebookId),
      body: { question, session_id: 'default' },
      onMessage(data: any) {
        if (data.type === 'text') {
          store.appendStreamChunk(data.content || '')
          scrollToBottom()
        } else if (data.type === 'reference') {
          store.addReference(data)
        } else if (data.type === 'suggestions') {
          store.setSuggestions(data.payload?.suggestions || [])
        } else if (data.type === 'error') {
          message.error(data.content || '对话出错')
        }
        // Note: 'done' type is handled by onDone callback from useSSE
      },
      onDone() {
        if (store.isStreaming) {
          store.finishStreaming(props.notebookId)
          scrollToBottom()
        }
      },
      onError() {
        if (store.isStreaming) {
          message.error('连接失败')
          store.finishStreaming(props.notebookId)
        }
      },
    })
  } catch (e: any) {
    if (store.isStreaming) {
      message.error('请求失败')
      store.finishStreaming(props.notebookId)
    }
  }
}

function openPreview(ref_: any) {
  if (!ref_?.doc_id) return
  previewDocId.value = ref_.doc_id
  // Extract matched_chunks and highlights from the reference payload
  const payload = ref_.payload || ref_
  const text = payload?.text || ''

  // Build a matched_chunk object from citation_map entry
  if (payload?.page_number || payload?.heading_hierarchy?.length || payload?.chunk_index != null) {
    previewChunks.value = [{
      text: text.replace(/<em>/g, '').replace(/<\/em>/g, ''),
      page_number: payload.page_number,
      page_numbers: payload.page_numbers || [],
      heading_hierarchy: payload.heading_hierarchy || [],
      element_type: payload.element_type || '',
      chunk_index: payload.chunk_index,
    }]
    previewHighlights.value = []
  } else if (text) {
    previewChunks.value = []
    previewHighlights.value = [text.replace(/<em>/g, '').replace(/<\/em>/g, '')]
  } else {
    previewChunks.value = []
    previewHighlights.value = []
  }
  previewOpen.value = true
}

function handleReferenceClickForMessage(index: number, msgRefs: any[]) {
  const ref_ = msgRefs[index - 1]
  openPreview(ref_)
}

function handleOpenReference(ref_: any) {
  openPreview(ref_)
}

interface RefGroup {
  doc_id: string
  title: string
  indices: number[]  // 1-based ref numbers actually used in the text
}

/** Extract which [N] numbers appear in the message text */
function extractUsedIndices(text: string): Set<number> {
  const used = new Set<number>()
  const regex = /\[(\d+)\]/g
  let match
  while ((match = regex.exec(text)) !== null) {
    used.add(parseInt(match[1], 10))
  }
  return used
}

function groupRefsByDoc(refs: any[], messageContent?: string): RefGroup[] {
  // If we have message content, only show indices that actually appear in it
  const usedIndices = messageContent ? extractUsedIndices(messageContent) : null

  const map = new Map<string, RefGroup>()
  refs.forEach((ref_, idx) => {
    const refNum = idx + 1  // 1-based
    // Skip refs not used in the text (if we know which are used)
    if (usedIndices && !usedIndices.has(refNum)) return

    const docId = ref_.doc_id || `unknown_${idx}`
    if (!map.has(docId)) {
      map.set(docId, {
        doc_id: docId,
        title: ref_.title || docId,
        indices: [],
      })
    }
    map.get(docId)!.indices.push(refNum)
  })
  // Filter out groups with no indices (all their refs were unused)
  return Array.from(map.values()).filter(g => g.indices.length > 0)
}

watch(messages, () => scrollToBottom(), { deep: true })
</script>

<style scoped lang="less">
.chat-panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: #fafafa;
}

.chat-config-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid #f0f0f0;
  background: #fff;

  .config-label {
    font-weight: 600;
    font-size: 15px;
  }
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
}

.chat-welcome {
  text-align: center;
  padding: 60px 20px;

  .welcome-title {
    font-size: 20px;
    font-weight: 600;
    margin-bottom: 8px;
  }

  .welcome-desc {
    font-size: 14px;
    color: #8c8c8c;
  }
}

.chat-message {
  margin-bottom: 16px;
}

.references-section {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid #f0f0f0;

  .references-label {
    font-size: 12px;
    color: #8c8c8c;
    margin-bottom: 8px;
  }

  .references-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }
}

.ref-group-card {
  padding: 10px 12px;
  border: 1px solid #f0f0f0;
  border-radius: 6px;
  background: #fff;
  cursor: pointer;
  transition: all 0.2s;

  &:hover {
    border-color: #91caff;
    background: #f0f7ff;
  }

  .ref-group-header {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 6px;

    .ref-group-index {
      font-weight: 600;
      color: #1890ff;
      font-size: 13px;
    }

    .ref-group-title {
      font-size: 13px;
      font-weight: 500;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }

  .ref-group-indices {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
  }
}

.chat-input-wrapper {
  padding: 12px 16px;
  background: #fff;
  border-top: 1px solid #f0f0f0;
}

.chat-input-box {
  border: 1px solid #d9d9d9;
  border-radius: 12px;
  background: #fafafa;
  padding: 8px 12px 6px;
  transition: border-color 0.2s, box-shadow 0.2s;

  &:focus-within {
    border-color: #1890ff;
    box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.1);
    background: #fff;
  }

  :deep(.ant-input) {
    padding: 0;
    font-size: 14px;
    line-height: 1.6;
    background: transparent;
    resize: none;
  }
}

.chat-input-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 4px;

  .input-hint {
    font-size: 11px;
    color: #bfbfbf;
  }

  .send-btn {
    width: 32px;
    height: 32px;
    font-size: 14px;

    &:not(:disabled) {
      background: #1890ff;
      border-color: #1890ff;
    }
  }
}

.no-sources-hint {
  text-align: center;
  font-size: 12px;
  color: #faad14;
  padding: 0 16px 8px;
}
</style>
