<template>
  <div
    class="chat-input"
    :class="{ 'chat-input--drag-over': isDragOver }"
    @dragenter="handleDragEnter"
    @dragover="handleDragOver"
    @dragleave="handleDragLeave"
    @drop="handleDrop"
  >
    <div v-if="isDragOver" class="chat-input__drag-overlay">
      <span class="chat-input__drag-text">拖放以附加</span>
    </div>
    <div v-if="contextPills.length > 0" class="chat-input__pills">
      <ContextPill
        v-for="(pill, idx) in contextPills"
        :key="idx"
        :label="pill.label"
        :icon="pill.icon"
        :removable="pill.removable"
        @remove="removePill(idx)"
      />
    </div>
    <MentionDropdown
      :visible="mentionVisible"
      :query="mentionQuery"
      :skills="skillSuggestions"
      :position="mentionPosition"
      @select="insertMention"
      @close="closeMention"
    />
    <div class="chat-input__row">
      <a-textarea
        ref="textareaRef"
        v-model:value="inputText"
        :placeholder="placeholder"
        :auto-size="{ minRows: 1, maxRows: 4 }"
        :disabled="disabled"
        @pressEnter="handlePressEnter"
        @input="handleInput"
        class="chat-input__textarea"
      />
      <a-button
        v-if="!isGenerating"
        type="primary"
        :disabled="!canSend"
        :loading="disabled"
        @click="handleSend"
        class="chat-input__send"
      >
        <template #icon><SendOutlined /></template>
      </a-button>
      <a-button
        v-else
        danger
        @click="handleStop"
        class="chat-input__stop"
      >
        <template #icon><PoweroffOutlined /></template>
      </a-button>
    </div>
    <div class="chat-input__footer">
      <div class="chat-input__footer-left">
        <a-button
          size="small"
          :disabled="disabled"
          @click="showTeamModal = true"
          class="chat-input__action-btn chat-input__action-btn--team"
        >
          <template #icon><UsergroupAddOutlined /></template>
          专家团
        </a-button>
        <a-button
          ref="boardButtonRef"
          size="small"
          :disabled="disabled"
          @click="handleBoardClick"
          class="chat-input__action-btn chat-input__action-btn--board"
        >
          <template #icon><TeamOutlined /></template>
          私董会
        </a-button>
        <a-button
          v-if="teamStore?.isTeamMode"
          size="small"
          :disabled="disabled && !teamStore?.isTeamMode"
          @click="handleDebateClick"
          class="chat-input__action-btn chat-input__action-btn--debate"
          title="发起辩论"
        >
          <template #icon><CommentOutlined /></template>辩论
        </a-button>
        <a-button
          size="small"
          :disabled="disabled || fileUploading"
          :loading="fileUploading"
          @click="openFilePicker"
          class="chat-input__action-btn chat-input__action-btn--file"
        >
          <template #icon><PaperClipOutlined v-if="!fileUploading" /></template>
          {{ fileUploading ? '上传中' : '文件' }}
        </a-button>
        <input
          ref="fileInputRef"
          type="file"
          class="chat-input__file-input"
          @change="handleFileChange"
        />
      </div>
      <div class="chat-input__footer-right">
        <a-select
          v-model:value="selectedModel"
          size="small"
          class="chat-input__model-select"
          :loading="modelsLoading"
          :options="modelOptions"
          placeholder="模型"
        />
        <a-button
          size="small"
          :disabled="disabled || (!inputText && contextPills.length === 0)"
          class="chat-input__action-btn chat-input__action-btn--clear"
          @click="handleClear"
        >
          清空
        </a-button>
        <span class="chat-input__hint">Enter 发送，Shift + Enter 换行</span>
      </div>
    </div>
    <a-modal
      v-model:open="showBoardBlockModal"
      title="当前会话已存在私董会"
      ok-text="新建会话"
      cancel-text="我知道了"
      @ok="handleCreateNewConversationForBoard"
      @cancel="handleBoardBlockCancel"
    >
      <p>请新建会话来创建新的私董会</p>
    </a-modal>
    <BoardMeetingModal
      v-model:open="showBoardModal"
      @submit="handleBoardSubmit"
    />
    <TeamModal
      v-model:open="showTeamModal"
      @submit="handleTeamSubmit"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted, onUnmounted, nextTick, type Component } from 'vue'
import { Input as AInput, Button as AButton, Select as ASelect, Modal as AModal } from 'ant-design-vue'
import { SendOutlined, TeamOutlined, UsergroupAddOutlined, PaperClipOutlined, PoweroffOutlined, CommentOutlined } from '@ant-design/icons-vue'
import ContextPill from './ContextPill.vue'
import MentionDropdown from './MentionDropdown.vue'
import BoardMeetingModal from './BoardMeetingModal.vue'
import TeamModal from './TeamModal.vue'
import { useSkillsStore } from '@/stores/skills'
import { useTeamStore } from '@/stores/team'
import { useChatStore } from '@/stores/chatStore'
import type { ISkillInfo } from '@/api/skills'
import { apiClient } from '@/api/client'
import { message as antMessage } from 'ant-design-vue'

const ATextarea = AInput.TextArea

interface ContextPillData {
  label: string
  icon?: Component
  removable?: boolean
}

interface SkillSuggestion {
  name: string
  description: string
}

interface ModelInfo {
  id: string
  provider: string
  model: string
  max_tokens: number | null
  cost_per_1k_input: number | null
  cost_per_1k_output: number | null
}

interface IProps {
  disabled?: boolean
  isGenerating?: boolean
  placeholder?: string
}

const props = withDefaults(defineProps<IProps>(), {
  disabled: false,
  isGenerating: false,
  placeholder: '输入消息，按 Enter 发送...',
})

const emit = defineEmits<{
  send: [message: string, model?: string]
  stop: []
}>()

const inputText = ref('')
const contextPills = ref<ContextPillData[]>([])
const textareaRef = ref<InstanceType<typeof ATextarea> | null>(null)
const selectedModel = ref<string | undefined>(undefined)
const availableModels = ref<ModelInfo[]>([])
const modelsLoading = ref(false)
const showBoardModal = ref(false)
const showTeamModal = ref(false)
const showBoardBlockModal = ref(false)
const boardButtonRef = ref<InstanceType<typeof AButton> | null>(null)
const fileInputRef = ref<HTMLInputElement | null>(null)
const fileUploading = ref(false)
const isDragOver = ref(false)
let dragLeaveTimer: ReturnType<typeof setTimeout> | null = null

const modelOptions = computed(() => {
  return availableModels.value.map((m: ModelInfo) => ({
    value: m.id,
    label: m.model,
  }))
})

async function fetchModels() {
  modelsLoading.value = true
  try {
    const data = await apiClient.listModels()
    availableModels.value = data.models || []
    selectedModel.value = data.default || (availableModels.value.length > 0 ? availableModels.value[0].id : undefined)
  } catch {
    availableModels.value = []
  } finally {
    modelsLoading.value = false
  }
}

onMounted(fetchModels)

onUnmounted(() => {
  if (dragLeaveTimer) {
    clearTimeout(dragLeaveTimer)
    dragLeaveTimer = null
  }
})

// @-mention state
const mentionVisible = ref(false)
const mentionQuery = ref('')
const mentionStartIndex = ref(-1)
const mentionPosition = ref({ left: 0 })
const skillsStore = useSkillsStore()
const teamStore = useTeamStore()
const chatStore = useChatStore()

const skillSuggestions = computed<SkillSuggestion[]>(() => {
  return (skillsStore.skills || []).map((s: ISkillInfo) => ({
    name: s.name,
    description: s.description || '',
  }))
})

const canSend = computed(() => {
  return inputText.value.trim().length > 0 && !props.disabled
})

// U6: backfill from a UserBubble "回填" click. Consume then clear so a
// second click on the same message re-triggers the watcher ("" -> content).
watch(
  () => chatStore.refillText,
  (text) => {
    if (!text) return
    inputText.value = text
    chatStore.clearRefillText()
    const el = textareaRef.value?.$el?.querySelector('textarea') as HTMLTextAreaElement | null
    el?.focus()
  },
)

function handleInput(): void {
  detectMention()
}

function getCursorPosition(): number {
  const el = textareaRef.value?.$el?.querySelector('textarea') as HTMLTextAreaElement | null
  return el?.selectionStart ?? inputText.value.length
}

function detectMention(): void {
  const text = inputText.value
  const cursorPos = getCursorPosition()

  const lastAtIndex = text.lastIndexOf('@', cursorPos - 1)
  if (lastAtIndex === -1) {
    closeMention()
    return
  }

  const textAfterAt = text.slice(lastAtIndex + 1, cursorPos)
  if (textAfterAt.includes(' ') || textAfterAt.includes('\n')) {
    closeMention()
    return
  }

  if (lastAtIndex > 0 && !/\s/.test(text[lastAtIndex - 1])) {
    closeMention()
    return
  }

  mentionVisible.value = true
  mentionQuery.value = textAfterAt
  mentionStartIndex.value = lastAtIndex

  mentionPosition.value = { left: Math.min(lastAtIndex * 8, 200) }
}

function insertMention(skill: SkillSuggestion): void {
  if (mentionStartIndex.value === -1) return
  const text = inputText.value
  const before = text.slice(0, mentionStartIndex.value)
  const after = text.slice(mentionStartIndex.value + 1 + mentionQuery.value.length)
  inputText.value = `${before}@${skill.name} ${after}`
  closeMention()
}

function closeMention(): void {
  mentionVisible.value = false
  mentionQuery.value = ''
  mentionStartIndex.value = -1
}

function handleSend(): void {
  const message = inputText.value.trim()
  if (!message) return
  closeMention()
  emit('send', message, selectedModel.value)
  setTimeout(() => { inputText.value = '' }, 0)
}

function handleStop(): void {
  emit('stop')
}

function handleBoardClick(): void {
  // U1: 拦截"当前会话已存在进行中的私董会"场景
  const status = chatStore.boardState?.status
  if (status === 'discussing' || status === 'concluding') {
    showBoardBlockModal.value = true
    return
  }
  showBoardModal.value = true
}

async function handleCreateNewConversationForBoard(): Promise<void> {
  showBoardBlockModal.value = false
  chatStore.createConversation()
  await chatStore.selectConversation(chatStore.currentConversationId!, true)
  // 不自动打开 BoardMeetingModal，由用户在新会话中再次点击"私董会"按钮继续
}

function handleBoardBlockCancel(): void {
  // R4-D3: 焦点恢复 — a-modal 关闭后将焦点返回触发按钮（WAI-ARIA modal 对话模式）
  showBoardBlockModal.value = false
  nextTick(() => {
    const el = boardButtonRef.value?.$el as HTMLElement | undefined
    el?.focus()
  })
}

function handleBoardSubmit(command: string): void {
  // The BoardMeetingModal constructs an @board:expert1,expert2 topic command.
  // Send it through the normal chat pipeline — the backend intercepts @board prefix.
  if (!command.trim()) return
  emit('send', command, selectedModel.value)
}

function handleTeamSubmit(command: string): void {
  if (!command.trim()) return
  emit('send', command, selectedModel.value)
}

function handleDebateClick(): void {
  // Prompt user for debate topic, then send as intervention
  const topic = window.prompt('请输入辩论主题')
  if (topic && topic.trim()) {
    emit('send', `/debate ${topic.trim()}`, selectedModel.value)
  }
}

function openFilePicker(): void {
  fileInputRef.value?.click()
}

async function handleFileChange(event: Event): Promise<void> {
  const target = event.target as HTMLInputElement
  const file = target.files?.[0]
  if (!file) return
  await uploadFile(file)
  target.value = ''
}

function handlePressEnter(event: KeyboardEvent): void {
  if (mentionVisible.value) return
  if (event.shiftKey) return
  event.preventDefault()
  handleSend()
}

function handleClear(): void {
  inputText.value = ''
  contextPills.value = []
  closeMention()
}

function handleDragEnter(event: DragEvent): void {
  if (!event.dataTransfer?.types.includes('Files')) return
  event.preventDefault()
  if (dragLeaveTimer) {
    clearTimeout(dragLeaveTimer)
    dragLeaveTimer = null
  }
  isDragOver.value = true
}

function handleDragOver(event: DragEvent): void {
  if (!event.dataTransfer?.types.includes('Files')) return
  event.preventDefault()
  isDragOver.value = true
}

function handleDragLeave(event: DragEvent): void {
  if (!event.dataTransfer?.types.includes('Files')) return
  // Delay to avoid flicker when dragging over child elements
  dragLeaveTimer = setTimeout(() => {
    isDragOver.value = false
  }, 50)
}

function handleDrop(event: DragEvent): void {
  isDragOver.value = false
  if (dragLeaveTimer) {
    clearTimeout(dragLeaveTimer)
    dragLeaveTimer = null
  }
  const files = event.dataTransfer?.files
  if (files && files.length > 0) {
    event.preventDefault()
    const file = files[0]
    uploadFile(file)
  }
}

async function uploadFile(file: File): Promise<void> {
  fileUploading.value = true
  try {
    const response = await apiClient.uploadFile(file)
    emit('send', `[文件] [${response.filename}](${response.download_url})`, selectedModel.value)
    antMessage.success(`文件上传成功: ${response.filename}`)
  } catch (error: unknown) {
    antMessage.error(`上传失败: ${error instanceof Error ? error.message : '未知错误'}`)
  } finally {
    fileUploading.value = false
  }
}

function removePill(idx: number): void {
  contextPills.value.splice(idx, 1)
}
</script>

<style scoped>
.chat-input {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--space-3) var(--space-5);
  background: var(--bg-primary);
  border-top: 1px solid var(--border-color);
}

.chat-input__drag-overlay {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px dashed var(--accent-team);
  border-radius: var(--radius-lg);
  pointer-events: none;
}

.chat-input__drag-overlay::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--bg-primary);
  opacity: 0.9;
  border-radius: inherit;
}

.chat-input__drag-text {
  font-size: var(--font-md);
  color: var(--accent-team);
  font-weight: var(--font-weight-medium);
}

.chat-input__pills {
  display: flex;
  gap: var(--space-1);
  flex-wrap: wrap;
  padding-bottom: var(--space-2);
}

.chat-input__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
}

.chat-input__textarea {
  flex: 1;
  min-height: 32px;
}

.chat-input__textarea :deep(.ant-input) {
  min-height: 32px;
  line-height: 1.5;
  padding: 0;
  background: transparent;
  border: none;
  box-shadow: none !important;
  font-size: var(--font-base);
  resize: none;
}

.chat-input__textarea :deep(.ant-input:focus) {
  box-shadow: none !important;
}

.chat-input__textarea :deep(.ant-input::placeholder) {
  color: var(--text-placeholder);
}

.chat-input__send {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-md) !important;
  background: var(--bg-secondary) !important;
  border: 1px solid var(--border-color) !important;
  color: var(--text-tertiary) !important;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 !important;
}

.chat-input__send:not(:disabled):hover {
  background: var(--text-primary) !important;
  color: var(--text-inverse) !important;
  border-color: var(--text-primary) !important;
}

.chat-input__stop {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-md) !important;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 !important;
}

.chat-input__stop:hover {
  opacity: 0.85;
}

.chat-input__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding-top: var(--space-1);
}

.chat-input__footer-left,
.chat-input__footer-right {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.chat-input__hint {
  font-size: var(--font-xs);
  color: var(--text-placeholder);
}

.chat-input__action-btn {
  flex-shrink: 0;
  font-size: var(--font-xs);
  color: var(--text-tertiary);
  border: none;
  background: transparent;
  padding: 0 var(--space-1);
}

.chat-input__action-btn:not(:disabled):hover {
  background: transparent;
}

.chat-input__action-btn--team {
  color: var(--accent-team);
}

.chat-input__action-btn--team:not(:disabled):hover {
  color: var(--accent-team);
  background: var(--accent-team-soft);
}

.chat-input__action-btn--board {
  color: var(--accent-board);
}

.chat-input__action-btn--board:not(:disabled):hover {
  color: var(--accent-board);
  background: var(--accent-board-soft);
}

.chat-input__action-btn--debate {
  color: #722ed1;
  border-color: #d3adf7;
}

.chat-input__action-btn--debate:not(:disabled):hover {
  color: #531dab;
  border-color: #722ed1;
  background: #f9f0ff;
}

.chat-input__action-btn--clear {
  color: var(--text-tertiary);
}

.chat-input__file-input {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  opacity: 0;
  pointer-events: none;
}

.chat-input__model-select {
  min-width: 120px;
}

.chat-input__model-select :deep(.ant-select-selector) {
  border: none !important;
  box-shadow: none !important;
  background: transparent !important;
  padding-left: 0 !important;
  font-size: var(--font-xs);
  color: var(--text-tertiary);
  cursor: pointer;
}
</style>
