<template>
  <div class="ai-chat">
    <h3 class="ai-chat-title">预览与调试</h3>
    <div class="ai-chat-header">
      <div class="ai-chat-header-info">
        <div class="logo">
          <img :src="answerSetting.info?.imgRelUrl || '/images/def_agent.svg'" alt=""/>
        </div>
        <div class="info flex-direction-column justify-center">
          <div class="info-title">{{ answerSetting.info?.name }}</div>
          <div class="info-sub-title">{{ answerSetting.info?.applicationDesc }}</div>
        </div>
      </div>
      <div class="ai-chat-header-tips" v-if="answerSetting.info?.opening || (questionsList && questionsList.length)">
        <div class="title pointer">{{ answerSetting.info?.opening }}</div>
        <div class="tag pointer" v-for="item in questionsList" :key="item.uuid" @click="questionText = item.name">
          {{ item.name }}
        </div>
      </div>
    </div>
    <el-scrollbar ref="scrollDiv" @scroll="handleScrollTop">
      <div ref="dialogScrollbar" class="ai-chat-box">
        <div class="ai-chat-content">
          <ul>
            <li v-for="(item, index) in questionList" :key="index">
              <!--问-->
              <div class="question">
                <div class="content-wrapper" style="margin-right: 8px">
                  <div class="content">{{ item.question.content }}</div>
                </div>
                <div class="avatar">
                  <img src="@/assets/user-icon.svg" alt="" />
                </div>
              </div>
              <!--答-->
              <div class="answer">
                <div class="avatar"><img :src="answerSetting.info?.imgRelUrl || '/images/def_agent.svg'" alt="" /></div>
                <div class="content-wrapper" style="margin-left: 8px">
                  <div class="content-loading" v-if="item.answer.status === 'init'">
                    <RotateLoading />AI正在生成回答
                  </div>
                  <div class="content-loading" v-if="item.answer.status === 'error'">
                    Ai对话异常,请稍后再试!
                  </div>
                  <MdPreview v-else ref="editorRef" editorId="preview-only" :modelValue="item.answer.content"
                    :key="index" class="maxkb-md" />
                  <!--底部操作按钮-->
                  <div class="flex-between" v-if="item.answer.status === 'done'">
                    <span class="el-text el-text--info ml-4"> 以上内容为 AI生成，不代表开发者立场</span>
                    <!--重新回答-->
                    <el-tooltip effect="dark" content="重新回答" placement="top">
                      <el-button text @click="handelRegeneration(item)">
                        <el-icon>
                          <RefreshRight />
                        </el-icon>
                      </el-button>
                    </el-tooltip>
                  </div>
                </div>
              </div>
            </li>
          </ul>
          <!--Popover 弹出框 start-->
          <CreatePopover />
          <!--Popover 弹出框 end-->
        </div>
      </div>
    </el-scrollbar>
    <div class="ai-chat-footer-box flex-between">
      <div class="ai-chat-footer-delete flex-center">
        <lz-svg-icon icon-class="shanchu2" @click="handleClear" :style="{ 'fontSize': '28px', color: '#333' }" />
      </div>
      <div class="ai-chat-footer flex" :class="{ 'active-focus': isFocus }">
        <div class="flex align-center">
          <!--上传文件 -->
          <el-tooltip effect="dark" content="上传文件：支持PDF/Word/PPT/txt等，最大50MB" placement="top">
            <el-upload 
              class="avatar-uploader" 
              action="/dada/base/anyone/file/upload"
              accept=".pdf,.docx,.pptx,.txt"
              :show-file-list="false" 
              :on-success="handleAvatarSuccess" 
              :before-upload="beforeAvatarUpload" 
              :headers="getHeaders()" 
              :data="{
                bizType: 'DOC'
              }" 
            >
              <lz-svg-icon icon-class="lianjie" :style="{ 'fontSize': '18px', color: '#333' }" />
            </el-upload>
          </el-tooltip>
        </div>
        <!-- 输入消息-->
        <div class="w-full">
          <div v-if="fileList.length" class="flex-wrap gap-2 p-8-12">
            <el-tag v-for="item in fileList" :key="item.path" closable type="primary"  @close="handleClose(item)">
              {{ item.originalFileName }}
            </el-tag>
          </div>
          <el-input 
            type="textarea" 
            v-model="questionText" 
            :rows="3" 
            :autosize="{ minRows: 1, maxRows: 3 }"
            placeholder="请使用文字描述您的需求" 
            resize="none" 
            class="no-shadow" 
            @focus="isFocus = true" 
            @blur="isFocus = false" 
            @keydown.enter.exact.prevent="handleSendMsg"
            @keydown.shift.enter.exact.prevent="insertNewLine"
          />
        </div>
        <div class="flex align-center">
          <!-- 发送消息 -->
          <div :class="['button', loading ? 'btn-loading' : '']" @click="handleSendMsg">
            <img src="@/assets/webapp/13.svg" alt="" />
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, nextTick, watch, computed } from 'vue'
import { MsgError, MsgSuccess, MsgWarning } from '@/utils/message'
import { aiChat } from '@/api/finyxbot'
import { chatResponseToText } from '@/request/fetchWithAbort'
import RotateLoading from '../../../chat/components/RotateLoading.vue'
import useStore from '@/stores'
import type { UploadProps } from 'element-plus'
import { getHeaders } from '@/request/http'
import { newCreateSession, save16 } from '@/servers/finyx/api/zhinengtiduihuajilu'
import CreatePopover from '@/views/chat/components/CreatePopover.vue'

const { dada, answerSetting } = useStore()

type AnswerStatus = 'init' | 'pending' | 'done' | 'error'

interface ChatMessage {
  question: {
    content: string
  }
  answer: {
    id?: string
    createdTime?: string
    content: string
    status?: AnswerStatus
  }
}

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

/** 滚动 */
const scrollDiv = ref<HTMLElement | null | any>(null)
const dialogScrollbar = ref<HTMLElement | null | any>(null)
const scorll = ref<boolean>(true) // 是否允许滚动
const scrollTop = ref(0) // 滚动条距离最上面的高度

const questionList = ref<ChatMessage[]>([])
const questionText = ref('')
const loading = ref(false)
const isFocus = ref(false)
const fileList = ref<any>([])  // 文件列表

const editorRef = ref<any>(null)
const messages = ref<any>([])
const getParamsData = ref<any>({})
const sessionId = ref<any>('')

const questionsList = computed(() => { 
  return answerSetting.info.questions?.filter((item) => item.name !== '')
})

/** 获取最大高度 */
const getMaxHeight = () => {
  if (dialogScrollbar.value && scrollDiv.value?.wrapRef) {
    return dialogScrollbar.value.scrollHeight - scrollDiv.value.wrapRef.offsetHeight
  }
  return 0
}

/** 上传文件-删除 */
const handleClose = (item: any) => {
  fileList.value = fileList.value.filter((i: any) => i.path !== item.path)
}

/** 上传文件-成功 */
const handleAvatarSuccess: UploadProps['onSuccess'] = (
  response
) => {
  const {originalFileName, path} = response.data;
  fileList.value.push({ originalFileName, path })
  MsgSuccess('上传成功')
}

/**上传前格式检测 */
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
   // 支持的文件类型
  const allowedTypes = [
    // PDF
    'application/pdf',
    // Word文档
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
    // PPT
    'application/vnd.ms-powerpoint', // .ppt
    'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
    // 文本文件
    'text/plain', // .txt
  ];
  if (!allowedTypes.includes(rawFile.type)) {
    MsgError('仅支持PDF/Word/PPT/txt等格式');
    return false
  }
  // 检查文件大小 (50MB)
  if (rawFile.size / 1024 / 1024 > 50) {
    MsgError('最大支持50MB!');
    return false;
  }
  return true
}

/**
* 滚动滚动条到最上面
* @param $event
*/
const handleScrollTop = ($event: any) => {
  scrollTop.value = $event.scrollTop
  if (
    dialogScrollbar.value.scrollHeight - (scrollTop.value + scrollDiv.value.wrapRef.offsetHeight) <=
    80
  ) {
    scorll.value = true
  } else {
    scorll.value = false
  }
}

/**
 * 处理跟随滚动条
 */
const handleScroll = () => {
  if (scrollDiv.value) {
    // 内部高度小于外部高度 就需要出滚动条
    if (scrollDiv.value.wrapRef.offsetHeight < dialogScrollbar.value.scrollHeight) {
      // 如果当前滚动条距离最下面的距离在 规定距离 滚动条就跟随
      if (scorll.value) {
        scrollDiv.value.setScrollTop(getMaxHeight())
      }
    }
  }
}

/** 清空 */
const handleClear = () => {
  questionList.value = []
  questionText.value = ''
  fileList.value = []
  messages.value = []
}

/** 重新生成 */
const handelRegeneration = (item: any) => {
  console.log('重新生成', item)
  if(loading.value) {
    return
  }
  questionText.value = item.question.content
  handleSendMsg();
}

// Shift+Enter换行
const insertNewLine = () => {
  const textarea = document.querySelector('.ai-chat-footer .el-textarea__inner') as HTMLTextAreaElement
  if (textarea) {
    const start = textarea.selectionStart
    const end = textarea.selectionEnd
    const text = questionText.value
    questionText.value = text.substring(0, start) + '\n' + text.substring(end)
    
    // 将光标移动到插入的换行符之后
    nextTick(() => {
      textarea.selectionStart = start + 1
      textarea.selectionEnd = start + 1
    })
  }
}

const handleSendMsg = () => {
  if (loading.value || !questionText.value.trim()) return

  loading.value = true

  questionList.value.push({
    question: {
      content: questionText.value
    },
    answer: {
      content: '',
      status: 'init'
    }
  })

  sendMsg(questionText.value)

  nextTick(() => {
    questionText.value = ''
    fileList.value = []
    scorll.value = true
    handleScroll()
  })
}

/** 获取会话SessionId */
const getSessionId = async () => { 
  if(sessionId.value && sessionId.value !== '') {
    return sessionId.value
  }
  const params: any = { applicationId: props.id }
  const res = await newCreateSession(params)
  sessionId.value = res;
  return res;   
}
/** 获取参数 */
const getParams = async(content: any) => {
  getParamsData.value = {}
  const itemMsg: any = { 
    "role": "user", 
    "type": "text",
    "content": content,
    "file_path": null,
    "files": null,
    "timestamp": `${new Date().getTime()}`
  }
  if (fileList.value.length) {
    itemMsg.type = 'file'
    itemMsg.files = fileList.value.map((item: any) => ({file: item.originalFileName, path: item.path}))
  }
  messages.value.push(itemMsg)
  const sessionId = await getSessionId()
  const params: any = {
    "session_id": sessionId,            // 会话id
    "user_id": dada.id,
    "messages": [
      ...messages.value
    ],
    modelConfiguration:  {
      ... answerSetting.info,
      "name": answerSetting.info?.name, 
      "applicationDesc": answerSetting.info?.applicationDesc, 
      "model": answerSetting.info?.model, 
      "random": `${answerSetting.info?.random}`, 
      "circles": answerSetting.info?.circles, 
      "replayLength": answerSetting.info?.replayLength, 
      "spStatus": answerSetting.info?.spStatus, 
      "showThinkStatus": answerSetting.info?.showThinkStatus, 
      "opening": answerSetting.info?.opening, 
      "reminder": answerSetting.info?.reminder, 
    }
  }
  /** 存储参数 */
  getParamsData.value = {
    applicationId: answerSetting.info?.id, // 智能体编号
    sessionId: sessionId, // 会话编号
    question: content,
    chatType: itemMsg.type, // 	对话类型（text/image/file）
    files: itemMsg.files || [],
  }

  return params
}

/** 发送对话 */
const sendMsg = async(content: string) => {
  const params = await getParams(content)
  aiChat(params)
    .then((response) => {
      chatResponseToText(response, async(status, data: any, allContent: any) => {
        if (status) {
          if (data.type === 'done') {
            setItemStatus('done')
            loading.value = false
            data.content && insertItemContent(allContent)
             // 存储对话记录
            // await saveChat({
            //   ...getParamsData.value,
            //   answer: {
            //     question: allContent,
            //     "applicationId": getParamsData.value.applicationId,
            //     "chatRole": "assistant",
            //     "chatType": getParamsData.value.chatType,
            //     "sessionId": getParamsData.value.sessionId,
            //   }
            // })

          } else if (data.type === 'error') {
            MsgWarning(data.error)
            setItemStatus('error')
            loading.value = false
          } else {
            setItemStatus('pending')
            insertItemContent(allContent)
          }
          // 滚动到底部
          setTimeout(() => {
            handleScroll()
          }, 10)
        }
      })
    })
    .catch((e) => {
      console.log(e)
      MsgWarning('Ai对话异常,请稍后再试!')
      loading.value = false
      setItemStatus('error')
    })
}

/* 存储对话记录 */
const saveChat = (params: any) => { 
  save16(params)
    .then((res: any) => { 
      setItemCreateAnswer(res.id, res.createdTime)
    }).catch((err) => { 
      MsgError(err.message)
    })
} 

/** 设置对话记录的 id 时间 */
const setItemCreateAnswer = (id: any, time: string) => {
  const lastIndex = questionList.value.length - 1
  if (lastIndex >= 0) {
    questionList.value[lastIndex].answer.id = id
    questionList.value[lastIndex].answer.createdTime = time
  }
}

const insertItemContent = (content: string) => {
  const lastIndex = questionList.value.length - 1
  if (lastIndex >= 0) {
    questionList.value[lastIndex].answer.content = content
  }
}

const setItemStatus = (status: AnswerStatus) => {
  const lastIndex = questionList.value.length - 1
  if (lastIndex >= 0) {
    questionList.value[lastIndex].answer.status = status
  }
}

watch(questionList, () => {
  handleScroll()
},
  {
    deep: true,
    immediate: true
  })
</script>

<style scoped lang="scss">
.ai-chat {
  padding: 20px;
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
  box-sizing: border-box;

  &-title {
    font-size: 16px;
    margin-bottom: 20px;
  }

  &-header {
    background-color: #fff;

    &-info {
      padding: 9px 12px;
      display: flex;
      border-radius: 8px 8px 0 0;
      background: linear-gradient(90deg, #e7eeff 0%, #daeaff 48%, #daf4ff 100%);

      .logo {
        width: 73px;
        margin-right: 7px;
        img {
          width: 100%;
        }
      }

      .info-title {
        font-weight: 500;
        font-size: 16px;
        color: #191919;
        margin-top: 7px;
        margin-bottom: 4px;
      }

      .info-sub-title {
        font-weight: 400;
        font-size: 12px;
        color: #333333;
        margin-bottom: 4px;
      }

      .info-user {
        font-size: 11px;
        color: #999999;
        display: flex;
        align-items: center;
      }
    }

    &-tips {
      border-radius: 0 0 8px 8px;
      padding: 16px;

      .title {
        font-weight: 500;
        font-size: 14px;
        color: #191919;
        line-height: 17px;
        margin-bottom: 10px;
      }

      .tag {
        padding: 5px 20px;
        background: #e8efff;
        border-radius: 4px;
        font-weight: 400;
        font-size: 12px;
        color: #6489E3;
        line-height: 14px;
        display: inline-block;
        margin: 0 8px 8px 0;
        cursor: pointer;
      }
    }
  }

  &-content {
    flex: 1;
    margin-bottom: 20px;
    padding-top: 20px;

    .question,
    .answer {
      display: flex;
      margin-bottom: 16px; // 增加一些间距

      .avatar {
        margin-top: 8px;
        margin-bottom: 4px;

        img {
          width: 28px;
          height: 28px;
        }
      }

      .content-wrapper {
        flex: 1;
        padding: 12px; // 添加填充
        border-radius: 8px; // 圆角
        background-color: #E2ECFF; // 背景色
        margin-top: 4px; // 与头像的垂直间距

        .content {
          // 内容文本的样式，可以根据需要调整
          font-size: 14px;
          color: #333;
          white-space: pre-wrap;
        }

        .content-loading {
          display: flex;
          align-items: center;
        }
      }
    }

    .question {
      align-items: flex-end; // 问题左对齐

      .content-wrapper {
        width: calc(100% - 28px);
        //   margin-left: 10%;
      }
    }

    .answer {
      align-items: flex-start; // 答案右对齐
      justify-content: flex-end;

      .content-wrapper {
        //   margin-right: 8px; // 与头像的水平间距
        background-color: #fff // 答案使用不同的背景色以示区分;
      }
    }
  }

  &-footer {
    position: relative;
    padding: 8px 12px;
    box-shadow: 0 6px 24px #1f232914;
    background-color: #fff;
    border-radius: 8px;
    border: 1px solid #ffffff;
    box-sizing: border-box;
    transition: all .3s ease;
    width: calc(100% - 62px);

    &-delete {
      border-radius: 8px;
      border: 1px solid #D9D9D9;
      width: 52px;
      height: 52px;
      cursor: pointer;
    }

    .button {
      width: 36px;
      height: 36px;
      background: #3067ef;
      border-radius: 8px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;

      img {
        margin: 0 auto;
      }
    }

    .btn-loading {
      background-color: #999;
    }
  }

}

.ai-chat-footer-box {
  position: relative;
  margin-top: 20px;
}

.ai-chat-footer-box::after {
  background: linear-gradient(0deg, #f3f7f9 0%, rgba(243, 247, 249, 0) 100%);
  content: "";
  position: absolute;
  width: calc(100% - 48px);
  top: -16px;
  left: 24px;
  height: 16px;
}

.active-focus {
  border: 1px solid var(--el-color-primary);
}
</style>