<script setup lang="ts">
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { onBeforeRouteLeave } from 'vue-router'
import { Button, Spin, message } from 'ant-design-vue'
import { AppContainerBox } from '@/components/AppContainerBox'
import { AppSubMenuTitle } from '@/components/AppSubMenuTitle'
import { AppSubMenuList } from '@/components/AppSubMenuList'
import { AppConversationDefault } from '@/components/AppConversationDefault'
import { SubMenuActionEnum } from '@/components/AppSubMenuList/index.d'
import type { SubMenuItem } from '@/components/AppSubMenuList/index.d'

import { AppTextarea } from '@/components/AppTextarea'
import { AppMessage } from '@/components/AppMessage'
import type { MessageItem } from '@/components/AppMessage/index.d'
import { useMessageStore } from '@/store/moules/messageStore/index'
import { MessageStatusEnum, MessageTypeEnum } from '@/enums/messageEnum'
import { addMessage, conversationList, historyMessage, removeMessage, updateMessage } from '@/api/base/message'
import { useMqtt } from '@/hooks/useMqtt'
import { useMessage } from '@/hooks/useMessage'

const { createConfirm } = useMessage()

const messageStore = useMessageStore()

const sendBtnLoading = ref(false)
const subMenuActiveIndex = ref(0) // 当前会话索引
const subMenuActionIndex = ref(-1) // 会话操作索引
const subMenuList = ref<SubMenuItem[]>([])
const subMenuInputValue = ref<string>('')
const appMessage = ref()
const messageList = computed(() => messageStore.getMessageList)
const messageStatus = computed(() => messageStore.getMessageStatus)
const conversationData = computed(() => messageStore.getConversationData)
const historyMessageParams = ref({
  conversationId: '',
  current: 1,
  size: 10,
  total: 0,
})

const conversationDefaultShow = ref(false)
const appMessageShow = ref(true)
const spinning = ref(true)

watch(
  () => messageStatus.value,
  (val) => {
    if (val === MessageStatusEnum.END) {
      sendBtnLoading.value = false
    }
  },
)

/**
 * @description: 点击会话操作项
 */
function handlesubMenuActionIndex(type: SubMenuActionEnum, item: SubMenuItem, index: number) {
  subMenuActionIndex.value = index
  if (type === SubMenuActionEnum.EDIT) {
    subMenuList.value.forEach((item) => {
      item.actionType = SubMenuActionEnum.NOT
    })
    subMenuList.value[index].actionType = SubMenuActionEnum.EDIT
    subMenuInputValue.value = item.title
  }

  if (type === SubMenuActionEnum.DELETE) {
    createConfirm({
      title: '删除',
      content: `确定要删除${item.title}会话吗？`,
      iconType: 'warning',
      onOk: () => {
        removeMessage(item.id).then(() => {
          message.success('删除成功')
          getConversationList()
        })
      },
    })
  }
}

/**
 * @description: 切换会话
 */
async function handleSubMenuChange(index: number) {
  if (messageStatus.value !== MessageStatusEnum.END) {
    message.warn('请先结束对话')
    return
  }
  subMenuActiveIndex.value = index
  historyMessageParams.value.current = 1
  historyMessageParams.value.total = 0
  messageStore.setConversationData(subMenuList.value[subMenuActiveIndex.value])
  messageStore.setMessageClear()
  useMqtt().end()
  useMqtt().connect()
  getHistoryMessage()

  // 因为会话切换时滚动底部有问题，所以重新加载下
  appMessageShow.value = false
  setTimeout(() => {
    appMessageShow.value = true
  }, 0)
}

/**
 * @description: 发送消息
 */
async function handleSend(value: string) {
  sendBtnLoading.value = true
  conversationDefaultShow.value = false
  if (!conversationData.value) {
    return
  }

  if (subMenuActiveIndex.value === -1) {
    try {
      await addMessage({ title: '新的对话' })
      await getConversationList()
      await nextTick()
      useMqtt().sendMessage(conversationData.value.roleId, conversationData.value.id, value)
    }
    catch (error) {
      message.error('新建对话失败，请稍后重试！')
    }
  }
  else {
    useMqtt().sendMessage(conversationData.value.roleId, conversationData.value.id, value)
  }
}

/**
 * @description: 获取会话列表
 */
async function getConversationList() {
  const res = await conversationList()
  res.forEach((item: SubMenuItem) => {
    item.actionType = SubMenuActionEnum.NOT
  })
  subMenuList.value = res
  subMenuActiveIndex.value = 0
  if (subMenuList.value.length) {
    await handleSubMenuChange(0)
  }
}

/**
 * @description: 获取历史对话记录
 */
async function getHistoryMessage() {
  if (!conversationData.value) {
    return
  }
  spinning.value = true
  historyMessageParams.value.conversationId = conversationData.value.id
  const res = await historyMessage(historyMessageParams.value)
  spinning.value = false
  if (!res || !res.records || !res.records.length) {
    return
  }
  res.records.forEach((item: any) => {
    const itemData: MessageItem = {
      messageType: item.roleType === MessageTypeEnum.USER ? MessageTypeEnum.USER : MessageTypeEnum.AI,
      content: item.messageContent,
      time: item.messageTime,
      avatar: '',
      messageStatus: MessageStatusEnum.END,
    }
    historyMessageParams.value.total = res.total
    messageStore.setMessageUnshiftItem(itemData)
  })

  conversationDefaultShow.value = false
}

/**
 * @description: 滚动监听
 */
async function onScrollTop(scrollTop: number) {
  if (scrollTop !== 0) {
    return
  }

  if (historyMessageParams.value.current * historyMessageParams.value.size > historyMessageParams.value.total) {
    return
  }

  if (historyMessageParams.value.current < historyMessageParams.value.total) {
    historyMessageParams.value.current++
    await getHistoryMessage()

    // 无缝滚动
    appMessage.value.seamlessScrollToTop()
  }
}

/**
 * @description: 重新回答
 */
function reloadMessage() {
  if (!conversationData.value) {
    return
  }
  const question = messageList.value[messageList.value.length - 2]?.content
  useMqtt().sendMessage(conversationData.value.roleId, conversationData.value.id, question)
}

/**
 * @description: 点击新建会话按钮
 */
function handleAddMessage() {
  conversationDefaultShow.value = true
  subMenuActiveIndex.value = -1
}

// 下面是子菜单操作项
function handleSubMenuInputAffirm(index: number, item: SubMenuItem, inputValue: string) {
  updateMessage({ ...item, title: inputValue }).then(() => {
    message.success('修改成功')
    subMenuList.value[index].title = inputValue
    subMenuList.value[index].actionType = SubMenuActionEnum.NOT
  })
}
function handleSubMenuInputClose(index: number) {
  subMenuList.value[index].actionType = SubMenuActionEnum.NOT
}
function handleSubMenuInputBlur(index: number, item: SubMenuItem, inputValue: string) {
  subMenuActionIndex.value = -1
  handleSubMenuInputAffirm(index, item, inputValue)
}

onMounted(() => {
  getConversationList()
})

onUnmounted(() => {
  useMqtt().end()
})

// 路由离开时的操作
onBeforeRouteLeave(() => {
  if (messageStatus.value !== MessageStatusEnum.END) {
    message.warn('请先结束对话')
    return false
  }
})
</script>

<template>
  <AppContainerBox>
    <template #subMenu>
      <!-- 标题 -->
      <AppSubMenuTitle></AppSubMenuTitle>

      <!-- 按钮 -->
      <div class="px-5 mb-5">
        <Button type="primary" class="w-full" @click="handleAddMessage">
          新建会话
        </Button>
      </div>

      <!-- 会话列表 -->
      <AppSubMenuList
        v-model:input-value="subMenuInputValue"
        :list="subMenuList"
        :active-index="subMenuActiveIndex"
        :action-index="subMenuActionIndex"
        @change="handleSubMenuChange"
        @handle-action="handlesubMenuActionIndex"
        @input-affirm="handleSubMenuInputAffirm"
        @input-close="handleSubMenuInputClose"
        @input-blur="handleSubMenuInputBlur"
      >
      </AppSubMenuList>
    </template>
    <template #content>
      <Spin :spinning="spinning" wrapper-class-name="app-content-spin">
        <!-- 默认导语 -->
        <AppConversationDefault
          v-if="conversationDefaultShow"
          height="calc(100% - 120px)"
        >
        </AppConversationDefault>

        <!-- 消息列表 -->
        <AppMessage
          v-if="!conversationDefaultShow && appMessageShow"
          ref="appMessage"
          class="pl-27 pr-5"
          :list="messageList"
          @on-scroll-top="onScrollTop"
          @reload-message="reloadMessage"
        >
        </AppMessage>
      </Spin>

      <!-- 发送框 -->
      <AppTextarea
        class="pl-52 pr-32 mt-10"
        :btn-loading="sendBtnLoading"
        @send="handleSend"
      ></AppTextarea>
    </template>
  </AppContainerBox>
</template>

<style lang="scss" scoped>

</style>
