import { defineComponent } from 'vue'
import { ref, reactive, computed, onMounted, onUnmounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { fileApi, chunkApi, modelApi, questionApi } from '@/core/api'
import DeleteDialog from '@/shared/components/common/DeleteDialog.vue'

export default defineComponent({
  name: 'TextSplit',
  components: { DeleteDialog },
  setup() {
    const router = useRouter()
    const route = useRoute()
    const projectId = computed(() => route.params.id)
    
    const loading = ref(false)
    const splitting = ref(false)
    const files = ref([])
    const filterStatus = ref('')
    const fileChunks = ref({})
    const isInitialLoad = ref(true)
    const availableModels = ref([])
    const filePollingTimer = ref(null)
    const generateDialogVisible = ref(false)
    const generatingQuestions = ref(false)
    
    const DEFAULT_GENERATE_PROMPT = '你是一名高质量中文问答数据构建助手。请基于给定 chunk 内容生成准确、自然、可用于训练的数据集问答对。问题必须清晰具体，答案必须直接来自内容或基于内容做合理概括，不要编造原文没有的信息，不要输出与目录、导航、页眉页脚、噪声文字相关的问题。'
    
    // Multi-select
    const selectedFiles = ref([])
    const splitDialogVisible = ref(false)
    
    // Chunk Preview Dialog
    const chunkPreviewVisible = ref(false)
    const previewFile = ref(null)
    const previewChunks = ref([])
    const previewLoading = ref(false)
    const savingChunks = ref(false)
    const deletingChunkId = ref('')
    const deletingFileChunksId = ref('')
    const deleteDialogVisible = ref(false)
    const deleteDialogMode = ref('')
    const deleteDialogTarget = ref(null)
    const previewSearch = ref('')
    const previewFilter = ref('all')
    const previewJumpInput = ref('')
    const selectedPreviewChunkId = ref('')
    
    const isAllSelected = computed(() => filteredFiles.value.length > 0 && selectedFiles.value.length === filteredFiles.value.length)
    const selectedCount = computed(() => selectedFiles.value.length)
    
    const filteredFiles = computed(() => {
      if (!filterStatus.value) return files.value
      return files.value.filter(f => {
        if (filterStatus.value === 'completed') {
          return fileChunks.value[f.id]
        }
        if (filterStatus.value === 'processing') {
          return f.status === 'processing'
        }
        return true
      })
    })
    
    const toggleSelectAll = () => {
      if (isAllSelected.value) {
        selectedFiles.value = []
      } else {
        selectedFiles.value = filteredFiles.value.map(f => f.id)
      }
    }
    
    const toggleSelect = (fileId) => {
      const index = selectedFiles.value.indexOf(fileId)
      if (index === -1) {
        selectedFiles.value.push(fileId)
      } else {
        selectedFiles.value.splice(index, 1)
      }
    }
    
    const isSelected = (fileId) => selectedFiles.value.includes(fileId)
    
    const clearSelection = () => {
      selectedFiles.value = []
    }
    
    const splitConfig = reactive({
      method: 'recursive',
      chunk_size: 500,
      overlap: 50,
      separator: '\n\n',
      embedding_model_id: '',
      similarity_threshold: 0.3,
      min_chunk_size: 100,
    })
    
    const generateConfig = reactive({
      model_id: '',
      dirty_data_filter: true,
      thinking_mode: true,
      preset_prompt: DEFAULT_GENERATE_PROMPT,
      count: 3,
    })
    
    const methods = [
      { value: 'recursive', label: '递归字符', tag: '基础' },
      { value: 'semantic', label: '句段优先', tag: '规则' },
      { value: 'semantic_embedding', label: '语义嵌入', tag: 'API' },
      { value: 'markdown_structure', label: 'Markdown', tag: '结构' },
    ]
    
    const completedFiles = computed(() => {
      return Object.keys(fileChunks.value).length
    })
    
    const processingCount = computed(() => {
      return files.value.filter(f => f.status === 'processing').length
    })
    
    const totalChunks = computed(() => {
      return Object.values(fileChunks.value).reduce((sum, count) => sum + count, 0)
    })
    
    const normalizeModelType = (modelType, modelName = '') => {
      if (modelType && modelType !== 'chat') {
        return modelType
      }
    
      const normalizedName = String(modelName).trim().toLowerCase()
    
      if (['rerank', 'bce-reranker', 'gte-rerank'].some(keyword => normalizedName.includes(keyword))) {
        return 'rerank'
      }
    
      if ([
        'embedding',
        'embed',
        'text-embedding',
        'bge-',
        'bge_m3',
        'gte-',
        'm3e',
        'e5-',
        'jina-embeddings'
      ].some(keyword => normalizedName.includes(keyword))) {
        return 'embedding'
      }
    
      if (['vl', 'vision', 'visual', 'multimodal', 'qwen-vl', 'gpt-4o'].some(keyword => normalizedName.includes(keyword))) {
        return 'vlm'
      }
    
      return 'chat'
    }
    
    const embeddingModels = computed(() => {
      return availableModels.value.filter(model => normalizeModelType(model.model_type, model.model_name) === 'embedding')
    })
    
    const selectedEmbeddingModel = computed(() => {
      return embeddingModels.value.find(model => model.id === splitConfig.embedding_model_id) || null
    })
    
    const generateModels = computed(() => {
      return availableModels.value.filter(model => {
        const type = normalizeModelType(model.model_type, model.model_name)
        return type === 'chat' || type === 'vlm'
      })
    })
    
    const getProviderLabel = (provider) => {
      const providerMap = {
        openai: 'OpenAI Compatible',
        minimax: 'MiniMax',
        glm: 'GLM',
        ali: '阿里云百炼'
      }
      return providerMap[provider] || provider
    }
    
    const fetchAllChunks = async () => {
      const allChunks = []
      let page = 1
      let total = 0
    
      do {
        const res = await chunkApi.list(projectId.value, { page, page_size: 100 })
        const items = res.items || res.data || []
        total = res.total || res.pagination?.total || items.length
        allChunks.push(...items)
        page += 1
      } while (allChunks.length < total)
    
      return allChunks
    }
    
    const goToModelSettings = () => {
      splitDialogVisible.value = false
      generateDialogVisible.value = false
      router.push('/models')
    }
    
    const fetchAvailableModels = async () => {
      try {
        const res = await modelApi.list()
        if (Array.isArray(res)) {
          availableModels.value = res
        } else if (res?.data && Array.isArray(res.data)) {
          availableModels.value = res.data
        } else {
          availableModels.value = []
        }
      } catch (error) {
        console.error(error)
        availableModels.value = []
      }
    }
    
    watch(embeddingModels, (models) => {
      if (!models.length) {
        splitConfig.embedding_model_id = ''
        return
      }
    
      if (!models.some(model => model.id === splitConfig.embedding_model_id)) {
        const defaultModel = models.find(model => model.is_default === 'true') || models[0]
        splitConfig.embedding_model_id = defaultModel?.id || ''
      }
    }, { immediate: true })
    
    watch(generateModels, (models) => {
      if (!models.length) {
        generateConfig.model_id = ''
        return
      }
    
      if (!models.some(model => model.id === generateConfig.model_id)) {
        const defaultModel = models.find(model => model.is_default === 'true') || models[0]
        generateConfig.model_id = defaultModel?.id || ''
      }
    }, { immediate: true })
    
    const fetchFiles = async () => {
      const wasInitial = isInitialLoad.value
      loading.value = true
      try {
        const res = await fileApi.list(projectId.value)
        files.value = res || []
        // 获取每个文件的 chunk 数量
        await fetchChunksCount()
      } catch (error) {
        console.error(error)
      } finally {
        loading.value = false
        if (wasInitial) {
          isInitialLoad.value = false
        }
      }
    }
    
    const fetchChunksCount = async () => {
      const counts = {}
      for (const file of files.value) {
        try {
          const res = await chunkApi.list(projectId.value, { file_id: file.id })
          const chunkList = res.items || res || []
          if (chunkList.length > 0) {
            counts[file.id] = chunkList.length
          }
        } catch (e) {
          console.error(e)
        }
      }
      fileChunks.value = counts
    }
    
    const openSplitDialog = () => {
      if (selectedFiles.value.length === 0) {
        ElMessage.warning('请先选择要分割的文件')
        return
      }
      if (!availableModels.value.length) {
        fetchAvailableModels()
      }
      splitDialogVisible.value = true
    }
    
    const handleBatchSplit = async () => {
      if (selectedFiles.value.length === 0) {
        ElMessage.warning('请先选择文件')
        return
      }
      if (splitConfig.method === 'semantic_embedding' && !selectedEmbeddingModel.value) {
        ElMessage.warning('请先选择已配置的 embedding 模型')
        return
      }
      if (splitConfig.method === 'semantic_embedding' && !selectedEmbeddingModel.value?.api_key) {
        ElMessage.warning('当前 embedding 模型缺少 API Key，请先到模型配置补全')
        return
      }
      splitting.value = true
      splitDialogVisible.value = false
    
      const successFiles = []
      const failedFiles = []
    
      try {
        for (const fileId of selectedFiles.value) {
          const file = files.value.find(item => item.id === fileId)
          const payload = {
            file_id: fileId,
            method: splitConfig.method,
            chunk_size: splitConfig.chunk_size,
            overlap: splitConfig.overlap,
            separator: splitConfig.separator,
            similarity_threshold: splitConfig.similarity_threshold,
            min_chunk_size: splitConfig.min_chunk_size,
          }
    
          if (splitConfig.method === 'semantic_embedding' && selectedEmbeddingModel.value) {
            payload.embedding_provider = selectedEmbeddingModel.value.provider
            payload.embedding_api_key = selectedEmbeddingModel.value.api_key
            payload.embedding_base_url = selectedEmbeddingModel.value.api_base
            payload.embedding_model = selectedEmbeddingModel.value.model_name
          }
    
          try {
            await chunkApi.split(projectId.value, payload)
            successFiles.push(file?.filename || fileId)
          } catch (error) {
            console.error(error)
            failedFiles.push({
              name: file?.filename || fileId,
              message: error?.message || '分割失败'
            })
          }
        }
    
        if (successFiles.length && !failedFiles.length) {
          ElMessage.success(`已为 ${successFiles.length} 个文件启动后台分割任务`)
        } else if (successFiles.length && failedFiles.length) {
          ElMessage.warning(`已启动 ${successFiles.length} 个，失败 ${failedFiles.length} 个：${failedFiles[0].name} - ${failedFiles[0].message}`)
        } else if (failedFiles.length) {
          ElMessage.error(`分割失败：${failedFiles[0].name} - ${failedFiles[0].message}`)
          return
        }
    
        // 清除选择
        selectedFiles.value = []
    
        fetchFiles()
      } finally {
        splitting.value = false
      }
    }
    
    const openGenerateDialog = () => {
      if (completedFiles.value === 0) {
        ElMessage.warning('没有已分割的文件可生成')
        return
      }
      if (!availableModels.value.length) {
        fetchAvailableModels()
      }
      generateDialogVisible.value = true
    }
    
    const handleBatchGenerate = async () => {
      if (!generateConfig.model_id) {
        ElMessage.warning('请选择用于生成问答的大语言模型')
        return
      }
    
      generatingQuestions.value = true
      try {
        const allChunks = await fetchAllChunks()
        if (!allChunks.length) {
          ElMessage.warning('当前项目还没有可用文本块')
          return
        }
    
        await questionApi.generate(projectId.value, {
          chunk_ids: allChunks.map(chunk => chunk.id),
          model_id: generateConfig.model_id,
          dirty_data_filter: generateConfig.dirty_data_filter,
          thinking_mode: generateConfig.thinking_mode,
          preset_prompt: generateConfig.preset_prompt,
          count: generateConfig.count
        })
    
        generateDialogVisible.value = false
        ElMessage.success(`已为 ${allChunks.length} 个文本块启动后台问答生成任务`)
      } catch (error) {
        console.error(error)
        ElMessage.error(error?.message || '问答生成启动失败')
      } finally {
        generatingQuestions.value = false
      }
    }
    
    // Chunk Preview Methods
    const openChunkPreview = async (file) => {
      previewFile.value = file
      previewSearch.value = ''
      previewFilter.value = 'all'
      previewJumpInput.value = ''
      selectedPreviewChunkId.value = ''
      chunkPreviewVisible.value = true
      await fetchPreviewChunks(file.id)
    }
    
    const previewChunksWithIndex = computed(() => {
      return previewChunks.value.map((chunk, index) => ({
        ...chunk,
        displayIndex: index + 1
      }))
    })
    
    const isChunkModified = (chunk) => chunk.editingContent !== chunk.content
    
    const filteredPreviewChunks = computed(() => {
      const keyword = previewSearch.value.trim().toLowerCase()
    
      return previewChunksWithIndex.value.filter(chunk => {
        const matchesFilter = previewFilter.value !== 'modified' || isChunkModified(chunk)
        if (!matchesFilter) return false
        if (!keyword) return true
    
        return String(chunk.displayIndex).includes(keyword) || chunk.content.toLowerCase().includes(keyword) || chunk.editingContent.toLowerCase().includes(keyword)
      })
    })
    
    const activePreviewChunk = computed(() => {
      return previewChunks.value.find(chunk => chunk.id === selectedPreviewChunkId.value) || null
    })
    
    const activePreviewChunkIndex = computed(() => {
      const index = previewChunks.value.findIndex(chunk => chunk.id === selectedPreviewChunkId.value)
      return index === -1 ? 0 : index + 1
    })
    
    const modifiedPreviewCount = computed(() => {
      return previewChunks.value.filter(chunk => isChunkModified(chunk)).length
    })
    
    const deleteDialogTitle = computed(() => {
      if (deleteDialogMode.value === 'chunk') return '删除分片'
      if (deleteDialogMode.value === 'file-chunks') return '删除全部分块'
      return '删除'
    })
    
    const deleteDialogItemName = computed(() => {
      if (deleteDialogMode.value === 'chunk') {
        return `块 ${activePreviewChunkIndex.value || ''}`.trim()
      }
      if (deleteDialogMode.value === 'file-chunks') {
        return deleteDialogTarget.value?.filename || ''
      }
      return ''
    })
    
    const deleteDialogDetail = computed(() => {
      if (deleteDialogMode.value === 'chunk') {
        return '这会移除当前选中的单个文本分片，适用于清理错误切分或无效内容。'
      }
      if (deleteDialogMode.value === 'file-chunks') {
        return '这会清空当前文件已生成的全部分块，但不会删除文件本身。'
      }
      return ''
    })
    
    const deleteDialogWarning = computed(() => {
      if (deleteDialogMode.value === 'chunk') {
        return '删除后不可恢复，和该分片关联的后续内容可能需要重新生成。'
      }
      if (deleteDialogMode.value === 'file-chunks') {
        return '删除后不可恢复，该文件的全部分块将被清空，你需要重新执行分割才能恢复。'
      }
      return ''
    })
    
    const deleteDialogConfirmText = computed(() => {
      if (deleteDialogMode.value === 'chunk') return '确认删除分片'
      if (deleteDialogMode.value === 'file-chunks') return '确认删除全部分块'
      return '确认删除'
    })
    
    const deleteDialogLoading = computed(() => {
      if (deleteDialogMode.value === 'chunk') {
        return !!deleteDialogTarget.value && deletingChunkId.value === deleteDialogTarget.value.id
      }
      if (deleteDialogMode.value === 'file-chunks') {
        return !!deleteDialogTarget.value && deletingFileChunksId.value === deleteDialogTarget.value.id
      }
      return false
    })
    
    const selectPreviewChunk = (chunkId) => {
      selectedPreviewChunkId.value = chunkId
    }
    
    const getChunkSnippet = (chunk) => {
      return (chunk.editingContent || chunk.content || '')
        .replace(/\s+/g, ' ')
        .trim()
        .slice(0, 110) || '空白分片'
    }
    
    const jumpToChunk = () => {
      const index = Number(previewJumpInput.value)
      if (!Number.isInteger(index) || index < 1) {
        ElMessage.warning('请输入有效的块号')
        return
      }
    
      const target = previewChunksWithIndex.value.find(chunk => chunk.displayIndex === index)
      if (!target) {
        ElMessage.warning('未找到对应块号')
        return
      }
    
      if (previewFilter.value === 'modified' && !isChunkModified(target)) {
        previewFilter.value = 'all'
      }
    
      selectedPreviewChunkId.value = target.id
    }
    
    const resetChunk = (chunk) => {
      chunk.editingContent = chunk.content
    }
    
    const openDeleteChunkDialog = (chunk) => {
      deleteDialogMode.value = 'chunk'
      deleteDialogTarget.value = chunk
      deleteDialogVisible.value = true
    }
    
    const openDeleteFileChunksDialog = (file) => {
      deleteDialogMode.value = 'file-chunks'
      deleteDialogTarget.value = file
      deleteDialogVisible.value = true
    }
    
    const fetchPreviewChunks = async (fileId) => {
      previewLoading.value = true
      try {
        const res = await chunkApi.list(projectId.value, { file_id: fileId })
        previewChunks.value = (res.items || res || []).map(c => ({
          ...c,
          editingContent: c.content
        }))
        selectedPreviewChunkId.value = previewChunks.value[0]?.id || ''
      } catch (e) {
        console.error(e)
        ElMessage.error('获取 chunks 失败')
      } finally {
        previewLoading.value = false
      }
    }
    
    const saveChunk = async (chunk) => {
      savingChunks.value = true
      try {
        await chunkApi.update(projectId.value, chunk.id, {
          content: chunk.editingContent
        })
        ElMessage.success('保存成功')
        // Update local state
        chunk.content = chunk.editingContent
      } catch (e) {
        console.error(e)
        ElMessage.error('保存失败')
      } finally {
        savingChunks.value = false
      }
    }
    
    const deleteChunk = async (chunk) => {
      deletingChunkId.value = chunk.id
      try {
        await chunkApi.delete(projectId.value, chunk.id)
        previewChunks.value = previewChunks.value.filter(item => item.id !== chunk.id)
    
        if (previewFile.value?.id) {
          const nextCount = Math.max((fileChunks.value[previewFile.value.id] || 1) - 1, 0)
          if (nextCount > 0) {
            fileChunks.value = {
              ...fileChunks.value,
              [previewFile.value.id]: nextCount
            }
          } else {
            const { [previewFile.value.id]: _, ...rest } = fileChunks.value
            fileChunks.value = rest
          }
        }
    
        ElMessage.success('删除成功')
      } catch (e) {
        console.error(e)
        ElMessage.error('删除失败')
      } finally {
        deletingChunkId.value = ''
        deleteDialogVisible.value = false
        deleteDialogMode.value = ''
        deleteDialogTarget.value = null
      }
    }
    
    const deleteFileChunks = async (file) => {
      deletingFileChunksId.value = file.id
      try {
        const allChunks = []
        let page = 1
        let total = 0
    
        do {
          const res = await chunkApi.list(projectId.value, {
            file_id: file.id,
            page,
            page_size: 100
          })
          const items = res.items || []
          total = res.total || items.length
          allChunks.push(...items)
          page += 1
        } while (allChunks.length < total)
    
        for (const chunk of allChunks) {
          await chunkApi.delete(projectId.value, chunk.id)
        }
    
        const { [file.id]: _, ...rest } = fileChunks.value
        fileChunks.value = rest
    
        if (previewFile.value?.id === file.id) {
          previewChunks.value = []
          selectedPreviewChunkId.value = ''
        }
    
        ElMessage.success(`已删除 ${allChunks.length} 个分块`)
      } catch (e) {
        console.error(e)
        ElMessage.error('删除全部分块失败')
      } finally {
        deletingFileChunksId.value = ''
        deleteDialogVisible.value = false
        deleteDialogMode.value = ''
        deleteDialogTarget.value = null
      }
    }
    
    const confirmDeleteAction = async () => {
      if (!deleteDialogTarget.value) return
    
      if (deleteDialogMode.value === 'chunk') {
        await deleteChunk(deleteDialogTarget.value)
        return
      }
    
      if (deleteDialogMode.value === 'file-chunks') {
        await deleteFileChunks(deleteDialogTarget.value)
      }
    }
    
    watch(filteredPreviewChunks, (chunks) => {
      if (!chunks.length) {
        selectedPreviewChunkId.value = ''
        return
      }
    
      if (!chunks.some(chunk => chunk.id === selectedPreviewChunkId.value)) {
        selectedPreviewChunkId.value = chunks[0].id
      }
    })
    
    const refreshFiles = () => {
      fetchFiles()
    }
    
    const startFilePolling = () => {
      if (filePollingTimer.value) return
      filePollingTimer.value = window.setInterval(() => {
        fetchFiles()
      }, 3000)
    }
    
    const stopFilePolling = () => {
      if (!filePollingTimer.value) return
      window.clearInterval(filePollingTimer.value)
      filePollingTimer.value = null
    }
    
    const formatSize = (bytes) => {
      if (!bytes) return '0 B'
      const units = ['B', 'KB', 'MB', 'GB']
      let i = 0
      while (bytes >= 1024 && i < units.length - 1) {
        bytes /= 1024
        i++
      }
      return `${bytes.toFixed(1)} ${units[i]}`
    }
    
    const getFileBg = (type) => {
      const colors = {
        pdf: '#ef4444',
        docx: '#3b82f6',
        xlsx: '#22c55e',
        csv: '#f59e0b',
        md: '#8b5cf6',
        txt: '#6b7280',
        epub: '#ec4899'
      }
      return colors[type] || '#6b7280'
    }
    
    const getFileIcon = (type) => {
      const icons = {
        pdf: 'Document',
        docx: 'Document',
        xlsx: 'Grid',
        csv: 'Grid',
        md: 'Document',
        txt: 'Document',
        epub: 'Book'
      }
      return icons[type] || 'Document'
    }
    
    onMounted(() => {
      fetchAvailableModels()
      fetchFiles()
    })
    
    watch(processingCount, (count) => {
      if (count > 0) {
        startFilePolling()
      } else {
        stopFilePolling()
      }
    }, { immediate: true })
    
    onUnmounted(() => {
      stopFilePolling()
    })

    return {
      router,
      route,
      projectId,
      loading,
      splitting,
      files,
      filterStatus,
      fileChunks,
      isInitialLoad,
      availableModels,
      filePollingTimer,
      generateDialogVisible,
      generatingQuestions,
      DEFAULT_GENERATE_PROMPT,
      selectedFiles,
      splitDialogVisible,
      chunkPreviewVisible,
      previewFile,
      previewChunks,
      previewLoading,
      savingChunks,
      deletingChunkId,
      deletingFileChunksId,
      deleteDialogVisible,
      deleteDialogMode,
      deleteDialogTarget,
      previewSearch,
      previewFilter,
      previewJumpInput,
      selectedPreviewChunkId,
      isAllSelected,
      selectedCount,
      filteredFiles,
      toggleSelectAll,
      toggleSelect,
      isSelected,
      clearSelection,
      splitConfig,
      generateConfig,
      methods,
      completedFiles,
      processingCount,
      totalChunks,
      normalizeModelType,
      embeddingModels,
      selectedEmbeddingModel,
      generateModels,
      getProviderLabel,
      fetchAllChunks,
      goToModelSettings,
      fetchAvailableModels,
      fetchFiles,
      fetchChunksCount,
      openSplitDialog,
      handleBatchSplit,
      openGenerateDialog,
      handleBatchGenerate,
      openChunkPreview,
      previewChunksWithIndex,
      isChunkModified,
      filteredPreviewChunks,
      activePreviewChunk,
      activePreviewChunkIndex,
      modifiedPreviewCount,
      deleteDialogTitle,
      deleteDialogItemName,
      deleteDialogDetail,
      deleteDialogWarning,
      deleteDialogConfirmText,
      deleteDialogLoading,
      selectPreviewChunk,
      getChunkSnippet,
      jumpToChunk,
      resetChunk,
      openDeleteChunkDialog,
      openDeleteFileChunksDialog,
      fetchPreviewChunks,
      saveChunk,
      deleteChunk,
      deleteFileChunks,
      confirmDeleteAction,
      refreshFiles,
      startFilePolling,
      stopFilePolling,
      formatSize,
      getFileBg,
      getFileIcon
    }
  }
})
