<template>
  <div class="flex flex-col w-full h-full">
    <ScrollContainer id="scrollRef" ref="scrollRef">
      <div class="p-26px">
        <MessageGroup
          v-for="(item, i) in dataSources"
          :key="i"
          :arr="item"
        ></MessageGroup>
      </div>
    </ScrollContainer>
    <div class="p-18px">
      <div class="border border-[#414548]">
        <div class="border-b border-[#414548] h-74px flex items-center px-25px">
          <SvgIcon
            @click="handleRefresh"
            name="refresh"
            class="text-white text-26px cursor-pointer mr-28px"
          ></SvgIcon>
          <SvgIcon
            @click="handleStop"
            name="stop"
            class="text-white text-26px cursor-pointer mr-28px"
          ></SvgIcon>
          <div class="flex-1 text-right text-22px">
              剩余字数:{{ surplus }}
            </div>
        </div>
        <van-field
          ref="inputRef"
          class="cu-field-msg !text-white"
          type="textarea"
          placeholder="请输入内容"
          :rows="3"
          v-model="inputValue"
          :border="false"
          @pressEnter="handleEnter"
        />
        <div class="border-t border-[#414548] pb-10px px-14px">
          <div class="flex items-end my-14px">
            <div class="flex">
              <div class="text-[#EC4B4B] text-18px">*</div>
              <div class="opacity-40 text-21px">
                可支持的格式：.doc、.docx、.pdf（小于20M）
              </div>
            </div>
          </div>
          <div class="flex items-center">
            <van-button
              @click="handleClear"
              type="primary"
              class="!rounded-2px !h-53px !bg-[#414548] !mr-14px border-[#414548] text-white !border-none text-22px"
            >
              <template #icon>
                <SvgIcon name="delete" class="text-25px mr-13px" />
              </template>
              清除</van-button
            >
            <UploadComp @change="handleFileChange">
              <van-button
                type="primary"
                class="!rounded-2px !h-53px !mr-14px border-[#414548] text-white !border-none !text-22px !leading-53px"
              >
                <template #icon>
                  <SvgIcon name="cloud-upload" class="text-25px mr-13px" />
                </template>
                上传</van-button
              >
            </UploadComp>
            <div class="flex-1"></div>
            <van-button
              @click="handleSubmit"
              type="primary"
              class="!rounded-2px !h-53px border-[#414548] text-white !border-none !text-22px"
            >
              <template #icon>
                <SvgIcon name="generated" class="text-25px mr-13px" />
              </template>
              生成</van-button
            >
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>
import MessageGroup from './components/message-group.vue'
import {
  ref,
  computed,
  onMounted,
  nextTick,
  onBeforeMount,
  getCurrentInstance,
} from 'vue'
import ScrollContainer from '@/components/ScrollContainer/index.vue'
import http from '@/io/request'
import { v4 as uuidv4 } from 'uuid'
import { useRoute } from 'vue-router'
import { useChat } from '@/stores'
import UploadComp from './components/upload-comp.vue'
import extractTextFromPDF from '@/utils/pdfUtils.js'
import extractDocxText from '@/utils/docxUtils.js'
import { getFileInfo } from '@/utils/fileUtils.js'
import { showToast } from 'vant'
import { useAuthModal } from '@/stores/authModal'
import { useUserInfo } from '@/stores/userInfo'
const userInfo = useUserInfo()

const isLogin = computed(() => {
  return !!userInfo.userData?.id ?? false
})

const surplus = computed(() => {
  const { words_count=0 ,words_used = 0} = userInfo.userData?.equity ?? {}
  return words_count - words_used
})

const authModal = useAuthModal()

const { proxy } = getCurrentInstance()

let controller = new AbortController()

const inputRef = ref(null)

const route = useRoute()

const { uuid } = route.params

const chatStore = useChat()

const scrollRef = ref(null)

const loading = ref(false)

const inputValue = ref('')

const fileLoading = ref(false)

const currentChart = computed(() => chatStore.getCurrentChat)




async function handleFileChange(file) {
  if (!isLogin.value) {
    authModal.setAuthModalType('login')
    authModal.showAuthModal()
    return
  }

  if (!userInfo.userData?.equity?.pdf) return showToast('上传文件权限未开通')

  if (fileLoading.value) return
  fileLoading.value = true
  try {
    const valid = validateFile(file)
    if (!valid) return
    const info = getFileInfo(file)
    let result = ''
    if (info.extension === 'docx' || info.extension === 'doc') {
      result = await extractDocxText(file)
    } else if (info.extension === 'pdf') {
      result = await extractTextFromPDF(file)
    }
    if (!result || result.trim() == '') return showToast('文件内容为空')
    onConversation('next', info, result)
  } catch (error) {
    showToast(error.message)
  } finally {
    fileLoading.value = false
  }
}

function validateFile(file) {
  const allowedExtensions = ['doc', 'docx', 'pdf']
  const maxFileSize = 20 * 1024 * 1024 // 20MB

  const fileExtension = getFileExtension(file.name)
  const fileSize = file.size

  if (fileSize === 0) {
    throw new Error('文件内容为空')
  }

  if (!allowedExtensions.includes(fileExtension)) {
    throw new Error('文件格式无效')
  }

  if (fileSize > maxFileSize) {
    throw new Error('文件大小超出限制')
  }

  return true
}

function getFileExtension(fileName) {
  const parts = fileName.split('.')
  return parts[parts.length - 1].toLowerCase()
}

const conversationList = computed(() => {
  return chatStore.getCurrentChat.filter((item) => {
    const key = Object.keys(item)[0]
    const value = item[key]
    return !value.inversion
  })
})

const conversationUserList = computed(() => {
  return chatStore.getCurrentChat.filter((item) => {
    const key = Object.keys(item)[0]
    const value = item[key]
    return value.inversion
  })
})

const dataSources = computed(() => {
  const arr = chatStore.getCurrentChat
  return groupDataByParentId(arr)
})

function groupDataByParentId(data) {
  return data.reduce((groupedData, item) => {
    const itemId = Object.keys(item)[0]
    const itemData = item[itemId]

    if (itemData.parent_id === '') {
      groupedData[itemId] = []
    } else {
      const parentItemId = itemData.parent_id
      groupedData[parentItemId] = groupedData[parentItemId] || []
      groupedData[parentItemId].push(itemData)
    }

    return groupedData
  }, {})
}

function handleRefresh() {
  if (currentChart.value.length && !loading.value) onConversation('variant')
}

function handleStop() {
  if (loading.value) {
    controller.abort()
    loading.value = false
  }
}

function handleClear() {
  inputValue.value = ''
}

function handleSubmit() {
  onConversation()
}

async function onConversation(action = 'next', file, fileText) {
  let message = inputValue.value || fileText
  if (loading.value) return
  if (!isLogin) {
    authModal.setAuthModalType('login')
    authModal.showAuthModal()
    return
  }

  if ((!message || message.trim() === '') && action == 'next') return

  const params = {
    action: action,
    conversation_id: chatStore.active,
    message: {
      text: message?.substring(0, 4000),
      id: uuidv4(),
      type: (file?.extension === 'doc' ? 'docx' : file?.extension) || 'text',
      fileInfo: file,
    },
  }
  if (action == 'next') {
    const lastContext =
      conversationList.value[conversationList.value.length - 1]
    params.parent_message_id = uuidv4()
    if (lastContext) {
      params.parent_message_id = lastContext[Object.keys(lastContext)[0]]?.id
    }

    chatStore.addChatByUuid(chatStore.active, {
      text: message,
      inversion: true,
      parent_id: params.parent_message_id || '',
      id: params.message.id,
      type: params.message.type,
      fileInfo: file,
    })
    scrollToBottom()
    chatStore.addChatByUuid(chatStore.active, {
      text: '⋯',
      id: uuidv4(),
      parent_id: params.message.id,
      inversion: false,
    })
  }
  if (action == 'variant') {
    const lastUserContext =
      conversationUserList.value[conversationUserList.value.length - 1]
    if (lastUserContext) {
      const obj = lastUserContext[Object.keys(lastUserContext)[0]]
      params.message.text = obj.text?.substring(0, 4000)
      params.message.id = obj.id
      params.parent_message_id = obj.id
    }

    chatStore.addChatByUuid(chatStore.active, {
      text: '⋯',
      id: uuidv4(),
      parent_id: params.parent_message_id,
      inversion: false,
    })
  }

  loading.value = true
  inputValue.value = ''

  scrollToBottom()
  let tempMessage_id = null
  try {
    const fetchChatAPIOnce = async () => {
      await http.post('/api/v1/conversation', params, {
        signal: controller.signal,
        requestBaseUrl: 'chat',
        onDownloadProgress: async ({ event }) => {
          const xhr = event.target
          const { responseText } = xhr
          if (xhr.status == 200) {
            const arr = parseEventMessages(responseText)
            const { conversation_id, message_id } = arr[0]
            tempMessage_id = message_id
            const msg = arr.reduce((acc, item) => {
              return acc + item.text
            }, '')
            chatStore.updateChatByUuid(
              conversation_id,
              chatStore.getCurrentChat.length - 1,
              {
                [message_id]: {
                  conversation_id: conversation_id,
                  id: message_id,
                  text: msg,
                  inversion: false,
                  loading: true,
                  parent_id: params.message.id || '',
                },
              }
            )
            scrollToBottomIfAtBottom()
          }
        },
      })

      chatStore.updateChatSome(chatStore.getCurrentChat.length - 1, {
        loading: false,
      })
      await chatStore.getChat(chatStore.active)
    }

    await fetchChatAPIOnce()
  } catch (error) {
    if (error.message === 'canceled') {
      chatStore.updateChatSome(chatStore.getCurrentChat.length - 1, {
        loading: false,
      })
      return
    }
    const errorMessage = error?.errmsg ?? '好像出错了，请稍后再试。'

    chatStore.updateChatSome(chatStore.getCurrentChat.length - 1, {
      loading: false,
      text: errorMessage,
    })
  } finally {
    loading.value = false
    userInfo.getUserInfo()
  }
}

function parseEventMessages(dataString) {
  const lines = dataString.trim().split('\n')
  const eventMessages = []
  let currentEvent = {}

  for (const line of lines) {
    if (line.startsWith('event:message')) {
      if (Object.keys(currentEvent).length > 0) {
        eventMessages.push(currentEvent)
        currentEvent = {}
      }
    } else if (line.startsWith('data:')) {
      const jsonData = line.substring('data:'.length)
      currentEvent = JSON.parse(jsonData)
    }
  }

  if (Object.keys(currentEvent).length > 0) {
    eventMessages.push(currentEvent)
  }

  return eventMessages
}

function handleEnter(event) {
  if (event.key === 'Enter' && !event.shiftKey) {
    event.preventDefault()
    handleSubmit()
  }
}

function handleDataChange(data) {
  inputValue.value = data
}

onMounted(async () => {
  proxy.$mitt.on('temp-copy', handleDataChange)
  if (inputRef.value) {
    inputRef.value.focus()
  }
  await chatStore.getChat(uuid)
  scrollToBottom()
})

function scrollToBottom() {
  nextTick()
  scrollRef.value.scrollBottom()
}

function scrollToBottomIfAtBottom() {
  nextTick()
  scrollRef.value.scrollToBottomIfAtBottom()
}
</script>
<style lang="scss" scoped>
.scroll-smooth {
  scroll-behavior: smooth;
}
</style>
<style lang="scss">
.cu-field-msg {
  &.van-cell {
    background-color: transparent;
    padding: 14px 18px;
    font-size: 22px;
    placeholder-color: #999999;
  }
  .van-field__control {
    color: white;
  }
}
</style>
