<script setup>
import { ref, unref, onMounted, onUnmounted, computed, watch } from 'vue';
import { useMessage, NInput, NSwitch, NPopover, NScrollbar, NUpload, NTooltip, NProgress } from 'naive-ui';
import { useUserStore } from '@/stores/modules/userStore';
import { baseURL } from '@/utils/request';
import { getFormatYesterDay } from '@/utils/format';
import { helperApi } from '@/api/helper';
import { TheArchival } from "@/components"
import SvgIcon from '@/components/SvgIcon';

import 'load-awesome/css/ball-running-dots.min.css';

const props = defineProps({
  activeItem: {
    type: Object,
    default: () => ({})
  }
});

const emit = defineEmits(['onClick', 'onEnter']);

const MAX_NUM = 5;

const useStore = useUserStore();

const modelLoading = defineModel('loading');
const switchStatus = defineModel('switch');

const message = useMessage();

const inpVal = ref('');
const inpRef = ref(null);
const isFocusState = ref(false);

const isOpen = ref(false);
const highlightedIndex = ref(0);
const selectedOption = ref(null);
const helperList = ref([]);

const popoverTriggerRef = ref(null);
const popoverInnerRef = ref(null);
const scrollRef = ref(null);

const uploadFileList = ref([]);
const uploadLoading = ref(false);

const agentOptions = computed(() => helperList.value.filter(({ tools }) => tools));
const lastFileListIndex = computed(() => uploadFileList.value.length == 0 ? 0 : uploadFileList.value.length - 1);

const focusInput = _ => isFocusState.value = true;
const blurInput = _ => isFocusState.value = false;

watch(inpVal, (curVal) => {
  if (curVal === "@" && curVal.length === 1) {
    if ( !unref(agentOptions).length ) {
      return message.warning('当前未配置智能体');
    }
    if ( modelLoading.value ) {
      return message.warning('当前对话进行中');
    }
    isOpen.value = true;
  } else {
    isOpen.value = false;
  }
})

watch(() => props.activeItem, (curVal) => {
  selectedOption.value = curVal?.tools ? curVal :  null;
})

const handleInpFocus = () => {
  inpRef.value?.focus();
}

const commonEmitEvent = (eventName) => {
  const val = unref(inpVal);
  const len = val.trim().length;
  if ( !len ) {
    return message.warning('请输入您的问题或需求');
  }

  if ( len > 2000 ) {
    return message.warning('问题限制2000个字以内');
  }

  if ( modelLoading.value ) {
    return message.warning('当前对话进行中');
  }

  if ( uploadLoading.value ) {
    return message.warning('文件上传中，请稍后');
  }

  emit(eventName, { showVal: val,  question: val, selectedOption: selectedOption.value || {}, uploadFileList: uploadFileList.value });

  inpVal.value = '';
  uploadFileList.value = [];
}

// 回车事件
const handleInpEnter = (event) => {
  if (event.key === 'Enter' && !event.shiftKey && inpVal.value) {
    event.preventDefault();
    commonEmitEvent('onEnter');
    inpRef.value?.blur();
  }
}

// 点击事件
const handleBtnClick = () => {
  commonEmitEvent("onClick");
}

const clearInpVal = () => {
  inpVal.value = '';
}

// 键盘上键无限滚动
const scrollKeyUp = (index) => {
  const itemLength = agentOptions.value.length;
  if ( itemLength - MAX_NUM > index ) {
    scrollRef.value.scrollBy({
      top: -40 ,
      behavior: 'smooth'
    })
  }
  if ( index == itemLength - 1 ) {
    scrollRef.value.scrollTo({
      top: itemLength * 40,
      behavior: 'smooth'
    })
  }
}

// 键盘下键无限滚动
const scrollKeyDown = (index) => {
  if ( index >= MAX_NUM ) {
    scrollRef.value.scrollBy({
      top: 40,
      behavior: 'smooth'
    })
  } 
  if ( index == 0 ) {
    scrollRef.value.scrollTo({
      top: 0,
      behavior: 'smooth'
    })
  }
}

// 键盘事件
const handleKeyDown = (event) => {
  const len = unref(agentOptions).length;
  if ( !isOpen.value ) return;
  switch (event.key) {
    case 'ArrowUp':
      event.preventDefault();
      highlightedIndex.value = (unref(highlightedIndex) - 1 + len) % len;
      scrollKeyUp(unref(highlightedIndex), 1)
      break;
    case 'ArrowDown':
      event.preventDefault();
      highlightedIndex.value = (unref(highlightedIndex) + 1) % len;
      scrollKeyDown(unref(highlightedIndex))
      break;
    case 'Enter':
      event.preventDefault();
      selectOption(unref(highlightedIndex));
      break;
    default:
      break;
  }
}

const formatFileItem = (file) => {
  const { name } = file;
  return {
    name: name.substring(0, name.lastIndexOf('.')),
    url: "",
    size: (file.file.size / 1024).toFixed(2) + "KB",
    suffix: name.substring( name.lastIndexOf('.') + 1 ).toUpperCase(),
    originSuffix:name.substring( name.lastIndexOf('.') )
  }
}

// 处理点击空白处关闭
const closePopoverOutside =(event) => {
  if (!isOpen.value) return; 
  const triggerResult = popoverTriggerRef.value.contains(event.target);
  const innerResult = popoverInnerRef.value.contains(event.target);
  isOpen.value = triggerResult || innerResult;
}

// 选中选项
const selectOption = (index) => {
  selectedOption.value = agentOptions.value[index];
  highlightedIndex.value = index;
  isOpen.value = false;
  inpVal.value = selectedOption.value.content;
}

const beforeUpload = ({ file }) => {

  if (( file.file?.size / ( 1024 * 1024 ) ) > 5) {
    message.warning("文件大小超过5MB，请重新选择");
    return false;
  }

  const index = unref(lastFileListIndex);
  
  uploadFileList.value[index] = {
    ...formatFileItem(file),
    percentage: 0
  }

  uploadLoading.value = true

  return true;
}

// 上传文件
const handleUploadChange = ({ file }) => {

  if (file.status === 'uploading') {
    uploadFileList.value[lastFileListIndex.value].percentage = file.percentage;
  }
}

// 文件上传完成
const handleFinish = ({ file, event }) => {

  try {

    const res = JSON.parse( (event?.target).response );

    if ( res.code == 200 ) {
      uploadFileList.value[lastFileListIndex.value] = {
        ...uploadFileList.value[lastFileListIndex.value],
        url: res.data,
      }
      uploadLoading.value = false
    }

  } catch (error) {
    console.log("上传完成, 但是存在错误", error);
  }

}

// 上传失败
const handleUploadError = (error) => {
  uploadLoading.value = false;
}

// 删除文件
const onRemoveFile = (i) => {
  // uploadFileList.value.splice(i, 1);
  uploadFileList.value = [];
}

const clearFileList = () => {
  uploadFileList.value = [];
}

onMounted(async () => {
  const { data } = await helperApi.getHelperList();
  
  const result = getFormatYesterDay(data)

  helperList.value = result;
  document.addEventListener('keydown', handleKeyDown);
  document.addEventListener('click', closePopoverOutside);
})

onUnmounted(() => {
  document.removeEventListener('keydown', handleKeyDown);
  document.removeEventListener('click', closePopoverOutside);
})

defineExpose({
  clearFileList,
  clearInpVal,
  handleInpFocus,
  inpVal,
})

</script>
<template>
  <NPopover
    trigger="hover"
    width="trigger"
    display-directive="show"
    content-style="padding: 0;"
    :show-arrow="false"
    :show="isOpen"
  >
    <template #trigger>
      <div class="popover-trigger" ref="popoverTriggerRef">
        <div class="chat-inp-outer border-[1px]" :class="[{ 'border-[#2454FF]': isFocusState }]">
          <ul class="chat-tools-inner py-[10px] px-[10px] bg-[#fcfcfc]" v-show="selectedOption">
            <li class="tools-tips space-x-[10px]">
              <span>与</span>            
              <p class="agent-name space-x-[5px]" @click="isOpen = true">
                <img src="https://static.fuxicarbon.com/userupload/db77ffe0cef843278a23b0d2db9505fa.png" alt="">
                <span>{{ selectedOption?.title }}</span>
              </p>
              <span>对话中</span>
            </li>
            <li class="tools-close" @click="selectedOption = null">
              <SvgIcon name="chat-icon-close-btn"></SvgIcon>
            </li>
          </ul>

          <ul class="file-list-wrapper" v-show="uploadFileList.length">
            <li class="file-item space-x-[14px]" v-for="(item, index) in uploadFileList" :key="index">
              <div class="file-icon"></div>
              <div class="file-info">
                <p class="title">{{ item.name }}</p>
                <p class="info space-x-[8px]">
                  <span class="suffix">{{ item.suffix }}</span>
                  <span class="size">{{ item.size }}</span>
                </p>
              </div>
              <span class="close" @click="onRemoveFile(i)" v-show="item.percentage == 100 && !uploadLoading">x</span>
              <div class="file-progress" v-if="uploadLoading">
                <NProgress
                  type="line"
                  color="#3153f5"
                  :percentage="item.percentage"
                  :show-indicator="false"
                  :height="3"
                ></NProgress>
              </div>
            </li>
          </ul>

          <div class="chat-inp-inner">
            <div class="inp-wrapper flex-1" @click="handleInpFocus">
              <div class="upload-inner">
                <NUpload
                  accept=".doc, .docx, .pdf, .txt"
                  :disabled="uploadLoading"
                  :show-file-list="false"
                  :action="baseURL + '/qiniuyun/upLoadImage'"
                  :headers="{
                    'Authorization': 'Bearer' + useStore.token,
                  }"
                  @on-error="handleUploadError"
                  @change="handleUploadChange"
                  @finish="handleFinish"
                  @before-upload="beforeUpload"
                >
                  <NTooltip trigger="hover">
                    <template #trigger>
                      <div class="upload-file-button"></div>
                    </template>
                    <span class="text-[12px]">支持上传文件（每次一个, 大小5MB以内）接受.doc、.docx、.pdf、.txt等格式的文件</span>
                  </NTooltip>
                </NUpload>
              </div>
              <NInput 
                class="flex-1"
                ref="inpRef" 
                type="textarea" 
                size="medium"
                placeholder="输入@，召唤智能体"
                v-model:value="inpVal" 
                :autosize="{ minRows: 1, maxRows: 5 }"
                @focus="focusInput"
                @blur="blurInput"
                @keypress="handleInpEnter"
              />
            </div>
            <div class="submit-btn">
              <button class="btn bg-[#1A2029] hover:bg-[#3C4148]" @click="handleBtnClick">
                <SvgIcon name="tool-send-plane" size="22" v-show="!modelLoading"></SvgIcon>
                <div style="color: #fff" class="la-ball-running-dots la-sm" v-show="modelLoading">
                  <div v-for="item in 5" :key="item"></div>
                </div>
              </button>
            </div>
          </div>
        </div>
        <div class="switch-inner pt-[8px] flex justify-between items-center">
          <div class="space-x-[6px]">
            <NSwitch size="small" v-model:value="switchStatus"></NSwitch>
            <span class="text-[12px] text-[#9E9E9E]">使用deepseek R1</span>
          </div>
          <div>
            <TheArchival></TheArchival>
          </div>
        </div>
        <div class="masking-inner text-center text-[#2454FF]"></div>
      </div>
    </template>
  
    <div class="popover-inner" ref="popoverInnerRef">
      <div class="header">
        <span>选择智能体</span>
        <p class="tools-close" @click="isOpen = false">
          <SvgIcon name="chat-icon-close-btn"></SvgIcon>
        </p>
      </div>
      <NScrollbar style="max-height: 200px;" ref="scrollRef" trigger="none">
        <div class="item" v-for="item, index in agentOptions" :class="['item', { active: highlightedIndex === index }]" @click="selectOption(index)">
          <p class="icon">
            <img :src="item.banner" alt="">
          </p>
          <p class="ml-[10px] space-x-[5px] text">
            <span class="text-[15px]">{{item.title}}</span>
            <!-- <span class="text-[#888] text-[14px]">这里可以补充个描述</span> -->
          </p>
        </div>
      </NScrollbar>
    </div>
  </NPopover>
</template>

<style scoped lang="scss">
.chat-inp-outer {
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0px 3px 12px 0px #97D3FF40;

  .chat-tools-inner {
    @include flex(x, center, between);

    .tools-tips {
      @include flex(x, center, start);
      color: #666;
      font-size: 14px;
      
      .agent-name {
        @include flex(x, center, start);
        font-weight: bold;
        color: #333;
        cursor: pointer;

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

  .chat-inp-inner {
    position: relative;
    @include flex(x, center, between);
    background: #fff;

    .inp-wrapper {
      @include flex(x, start, center);
      padding: 17px 0px 17px 17px;

      .upload-inner {
        width: 30px;
        height: 30px;
        padding-top: 2px;

        .upload-file-button {
          width: 30px;
          height: 30px;
          background: url("@/assets/svgs/chat/icon-file-default.svg") center center no-repeat;
          cursor: pointer;

          &:hover {
            background: url("@/assets/svgs/chat/icon-file-active.svg") center center no-repeat;
          }
        }
      }
    }

    .submit-btn {
      @include flex(x, center, center);
      width: 84px;

      .btn {
        @include flex(x, center, center);
        width: 50px;
        height: 32px;
        border-radius: 32px;
        transition: all .3s;
      }
    }
  }
  
  .file-list-wrapper {
    padding: 10px;
    padding-bottom: 0px;
    background: #fff;

    .file-item {
      position: relative;
      @include flex(x, center, start);
      width: 30%;
      // height: 52px;
      padding: 10px;
      border-radius: 4px;
      background: #f5f5f5;

      .file-icon {
        flex-shrink: 0;
        width: 36px;
        height: 36px;
        background: url("@/assets/svgs/chat/icon-file.svg") center center no-repeat;
      }

      .file-info {
        flex: 1;
        @include flex(y, start, start);
        font-size: 12px;
        .title {
          width: 170px;
          color: #1a2029;
          text-overflow: ellipsis;
          overflow: hidden;
          word-break: break-all;
          white-space: nowrap;
        }
        .info {
          flex: 1;
          @include flex(x, center, between);
          color: #838a95;
        }
      }

      .file-progress {
        position: absolute;
        left: 0;
        bottom: 0;
        width: 100%;
        margin: 0;
      }

      .close {
        position: absolute;
        top: 0;
        right: 0;
        width: 16px;
        height: 16px;
        border: 1px solid #fff;
        border-radius: 100%;
        transform: translate(40%, -40%);
        background: #c8c8c8;
        font-size: 10px;
        text-align: center;
        line-height: 12px;
        cursor: pointer;
        color: #fff;

        &:hover {
          background: #b7b7b7;
        }
      }
    }
  }
}

.popover-inner {
  .header {
    @include flex(x, center, between);
    padding-bottom: 8px;
    font-size: 14px;
    color: #666;
  }

    .item {
      @include flex(x, center, start);
      padding: 8px 10px;
      cursor: pointer;
      &:hover {
        background: #f0fafe;
      }
      .icon {
        @include flex(x, center, center);
        width: 24px;
        height: 24px;
        border-radius: 100%;
        background: #e9eef8;
        img {
          width: 16px;
          height: 16px;
        }
      }
      .text {
        text-align: left;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
      }
    }
    .active {
      background: #f0fafe;
    }
  }

.tools-close {
  @include flex(x, center, center);
  width: 28px;
  height: 28px;
  border-radius: 6px;
  background: #fff;
  cursor: pointer;
  &:hover {
    background: #e9eef8;
  }
}

.masking-inner {
  position: absolute;
  top: -30px;
  left: 0;
  width: 100%;
  height: 30px;
  background: linear-gradient(180deg, rgba(232, 241, 250, 0) 0%, #E7F0FA 95%);
}


</style>