<template>
  <div class="chat">
    <div class="chat-msg" ref="ref_chatMsg">
      <template v-for="(item, index) in state.chats">
        <template v-if="item.type === 'ask'">
          <askCom :item="item"/>
        </template>
        <template v-else>
          <answerCom
            :item="item"
            :goodMap="state.goodMap"
            :badMap="state.badMap"
            @onGood="onGood"
            @onBad="onBad"
            @onNormal="onNormal"
          />
        </template>
      </template>
    </div>
    <div class="chat-input">
      <div class="chat-input-block" v-loading="state.loading">
        <div class="chat-input-block-main">
          <div class="chat-input-block-main-auto" ref="ref_auto">
            <div class="chat-input-block-main-auto-list">
              <template v-for="item in state.autoList">
                <div class="chat-input-block-main-auto-item __hover" @click="setText(item)">{{ item }}</div>
              </template>
            </div>
          </div>
          <textarea
            ref="ref_text"
            placeholder="请输入您的问题"
            :rows="1"
            v-model="state.text"/>
        </div>
        <div class="chat-input-block-operations">
          <div class="cibo-audio">
            <audioCom @onLoading="onLoading" @onAudio="onAudio"/>
          </div>
          <div class="cibo-split"/>
          <el-tooltip content="发送" placement="top">
            <div class="cibo-send __hover" @click="onSend">
              <img src="@/views/smart-ask-answer/assistant/imgs/send.png"/>
            </div>
          </el-tooltip>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {computed, getCurrentInstance, onMounted, reactive, ref, watch} from "vue";
import askCom from './component/ask/index.vue';
import answerCom from './component/answer/index.vue';
import audioCom from './component/audio/index.vue'
import {get, post, ssePost} from './dify/base'
import {useRouter} from "vue-router";
import {YMDHms} from "@/utils/czr-util";
import {updateFeedback} from "@/views/smart-ask-answer/assistant/dify/share";
import {cmsAiQueryQuestionReclist} from "@/views/smart-ask-answer/assistant/cms/api";

const emit = defineEmits(['getText'])
const router = useRouter()
const state: any = reactive({
  text: '',
  loading: false,
  params: {
    response_mode: "streaming",
    conversation_id: "",
    files: [],
    query: "",
    inputs: {},
    parent_message_id: null
  },
  chats: [
    {
      type: 'answer',
      welcome: true,
    },
  ],
  goodMap: new Map(),
  badMap: new Map(),
  autoList: []
})
const ref_text = ref()
const ref_chatMsg = ref()
const ref_auto = ref()
const onSend = () => {
  state.loading = true
  state.params.query = state.text + ''
  emit('getText', state.params.query)
  state.text = ''
  const ask = {
    type: 'ask',
    content: state.params.query + ''
  }
  state.chats.push(ask)
  const answer = reactive({
    type: 'answer',
    content: '',
    messageId: ''
  })
  state.chats.push(answer)
  ssePost(`/installed-apps/${window.czrConfig.dify.appId}/chat-messages`, {
    body: state.params,
  }, {
    onData: (message: string, isFirstMessage: boolean, { conversationId: newConversationId, messageId, taskId }: any) => {
      answer.content += message
      ref_chatMsg.value.scrollTo({
        top: ref_chatMsg.value.scrollHeight,
        behavior: 'smooth'
      });
    },
    onFile(file) {
    },
    onThought(thought) {
    },
    onMessageEnd: (messageEnd) => {
      if (!state.params.conversation_id) {
        state.params.conversation_id = messageEnd.conversation_id
        post(`/installed-apps/${window.czrConfig.dify.appId}/conversations/${state.params.conversation_id}/name`, {body: {auto_generate: false, name: YMDHms(new Date())}})
      }
      answer.messageId = messageEnd.message_id
      state.params.parent_message_id = messageEnd.message_id
      state.loading = false
    },
    onMessageReplace: (messageReplace) => {
    },
    onError() {
    },
    onWorkflowStarted: ({ workflow_run_id, task_id }) => {
    },
    onWorkflowFinished: ({ data: workflowFinishedData }) => {
    },
    onIterationStart: ({ data: iterationStartedData }) => {
    },
    onIterationFinish: ({ data: iterationFinishedData }) => {
    },
    onNodeStarted: ({ data: nodeStartedData }) => {
    },
    onNodeFinished: ({ data: nodeFinishedData }) => {
    },
    onTTSChunk: (messageId: string, audio: string) => {
    },
    onTTSEnd: (messageId: string, audio: string) => {
    },
  })
}
const onLoading = () => {
  state.loading = true
}
const onAudio = (text) => {
  state.text += text
  state.loading = false
}
const initChat = () => {
  get(`/installed-apps/${window.czrConfig.dify.appId}/parameters`).then((res: any) => {
    if (res.opening_statement) {
      state.chats = [
        {
          type: 'answer',
          welcome: true,
        },
      ]
    }
  })
}
const setText = (text: string) => {
  state.text = text
}
const onGood = (item) => {
  updateFeedback({
    url: `/messages/${item.messageId}/feedbacks`,
    body: {rating: 'like'},
  }, true, window.czrConfig.dify.appId).then((res: any) => {
    if (res.result === 'success') {
      state.goodMap.set(item.messageId, item)
    }
  })
}
const onBad = (item) => {
  updateFeedback({
    url: `/messages/${item.messageId}/feedbacks`,
    body: {rating: 'dislike'},
  }, true, window.czrConfig.dify.appId).then((res: any) => {
    if (res.result === 'success') {
      state.badMap.set(item.messageId, item)
    }
  })
}
const onNormal = (item) => {
  updateFeedback({
    url: `/messages/${item.messageId}/feedbacks`,
    body: {rating: null},
  }, true, window.czrConfig.dify.appId).then((res: any) => {
    if (res.result === 'success') {
      state.badMap.delete(item.messageId)
      state.goodMap.delete(item.messageId)
    }
  })
}
const initTextHandle = () => {
  let debounceTimer;
  const DEBOUNCE_TIME = 300;
  const textarea = ref_text.value
  const floatingDiv = ref_auto.value

  textarea.addEventListener('input', (e) => {
    textarea.style.height = 'auto';
    textarea.style.height = Math.min(textarea.scrollHeight + 2, 200) + 'px';
    clearTimeout(debounceTimer);
    floatingDiv.style.display = 'none';
    if (e.target.value) {
      debounceTimer = setTimeout(() => {
        updateFloatingDivPosition(e.target);
      }, DEBOUNCE_TIME)
    } else {
      floatingDiv.style.display = 'none';
    }
  });

  textarea.addEventListener('blur', function() {
    setTimeout(() => {
      floatingDiv.style.display = 'none';
    }, 200);
  });

  textarea.addEventListener('focus', function(e) {
    floatingDiv.style.maxWidth = (textarea.clientWidth + 32) + 'px';
    if (e.target.value) {
      updateFloatingDivPosition(e.target);
      floatingDiv.style.display = 'flex';
    }
  });

  const updateFloatingDivPosition = (t) => {
    floatingDiv.style.visibility = 'hidden';
    floatingDiv.style.display = 'flex';
    const params1 = {
      data: {
        pageIndex: 1,
        pageSize: 10,
        condition: {
          questionContent: t.value
        }
      }
    }
    cmsAiQueryQuestionReclist(params1).then(res => {
      state.autoList = res?.data?.list.map(v => v.questionContent) || []
      if (state.autoList.length > 0) {
        setTimeout(() => {
          floatingDiv.style.top = (-floatingDiv.clientHeight - 2 - 20) + 'px';
          floatingDiv.style.visibility = 'visible';
        }, 10)
      }
    })
  }
}
onMounted(() => {
  initChat()
  initTextHandle()
})
defineExpose({setText})
</script>

<style lang="scss" scoped>
$scrollRight: 16px;
.chat {
  width: 100%;
  height: 100%;
  padding: 32px calc(32px - $scrollRight) 0 32px;
  background: #FFFFFF;
  border-radius: 16px;
  display: flex;
  flex-direction: column;
  .chat-msg {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding-right: $scrollRight;
  }
  .chat-input {
    width: 100%;
    padding: 24px calc(5px + $scrollRight) 24px 5px;
    .chat-input-block {
      width: 100%;
      height: 100%;
      background: #FFFFFF;
      box-shadow: 0px 8px 16px 0px rgba(210,219,232,0.35);
      border-radius: 16px;
      border: 1px solid #E6E7EE;
      display: flex;
      flex-direction: column;
      padding: 16px;
      .chat-input-block-main {
        position: relative;
        .chat-input-block-main-auto {
          position: absolute;
          padding: 12px 16px;
          background: #FFFFFF;
          box-shadow: 0px 8px 16px 0px rgba(210,219,232,0.35);
          border-radius: 16px;
          border: 1px solid #E6E7EE;
          min-width: 200px;
          display: none;
          max-height: 200px;
          left: -16px;
          overflow: hidden;
          width: max-content;
          .chat-input-block-main-auto-list {
            flex: 1;
            overflow-y: auto;
            .chat-input-block-main-auto-item {
              padding: 6px 0;
              border-bottom: 1px dashed #D8DAE5;
              &:last-child {
                border-bottom: none;
              }
            }
          }
        }
        >textarea {
          width: 100%;
          resize: none;
          border: none;
        }
      }
      .chat-input-block-operations {
        margin-top: 12px;
        display: flex;
        align-items: center;
        justify-content: flex-end;
        .cibo-split {
          width: 1px;
          height: 17px;
          background: #E6E7EE;
        }
        .cibo-audio {
          display: flex;
          align-items: center;
          margin-right: 8px;
        }
        .cibo-send {
          margin-left: 16px;
          width: 32px;
          height: 32px;
          background: #1D64FD;
          border-radius: 50%;
          display: flex;
          align-items: center;
          justify-content: center;
          >img {
            margin-right: 3px;
          }
        }
      }
    }
  }
}
</style>
