<script lang="ts" setup>
import { watch, onMounted, ref, nextTick } from 'vue'
import { NDropdown, NCheckbox } from 'naive-ui'
import { Loading, MoreThree, ToTop } from '@icon-park/vue-next'
import { bus } from '@/utils/event-bus'
import { useDialogueStore } from '@/store'
import { formatTime, parseTime } from '@/utils/datetime'
import { clipboard, htmlDecode, clipboardImage } from '@/utils/common'
import { downloadImage } from '@/utils/functions'
import { MessageComponents, ForwardableMessageType } from '@/constant/message'
import { useMenu } from './menu'
import SkipBottom from './SkipBottom.vue'
import { ITalkRecord } from '@/types/chat'
import { EditorConst } from '@/constant/event-bus'
import { useInject, useTalkRecord, useUtil } from '@/hooks'
import { ExclamationCircleFilled } from '@ant-design/icons-vue'
import { useUserStore } from '@/store'
import RevokeMessage from '@/components/talk/message/RevokeMessage.vue'
import { voiceToText } from '@/api/chat.js'
import {confirmBox} from '@/components/confirm-box/service.js'
const props = defineProps({
  uid: {
    type: Number,
    default: 0
  },
  talk_type: {
    type: Number,
    default: 0
  },
  receiver_id: {
    type: Number,
    default: 0
  },
  index_name: {
    type: String,
    default: ''
  },
  specifiedMsg: {
    type: String,
    default: ''
  }
})

const { loadConfig, records, onLoad, onRefreshLoad, onJumpMessage } = useTalkRecord(props.uid)

const { useMessage } = useUtil()
const { dropdown, showDropdownMenu, closeDropdownMenu } = useMenu()
const { showUserInfoModal } = useInject()
const dialogueStore = useDialogueStore()
const userStore = useUserStore()
// const showUserInfoModal = (uid: number) => {
//   userStore.getUserInfo(uid)
// }
// 置底按钮
const skipBottom = ref(false)
// 是否显示消息时间
const isShowTalkTime = (index: number, datetime: string) => {
  if (datetime == undefined) {
    return false
  }

  if (records.value[index].is_revoke == 1) {
    return false
  }

  datetime = datetime.replace(/-/g, '/')
  let time = Math.floor(Date.parse(datetime) / 1000)
  let currTime = Math.floor(new Date().getTime() / 1000)

  // 当前时间5分钟内时间不显示
  if (currTime - time < 300) return false

  // 判断是否是最后一条消息,最后一条消息默认显示时间
  if (index == records.value.length - 1) {
    return true
  }

  let nextDate = records.value[index + 1].created_at.replace(/-/g, '/')

  return !(
    parseTime(new Date(datetime), '{y}-{m}-{d} {h}:{i}') ==
    parseTime(new Date(nextDate), '{y}-{m}-{d} {h}:{i}')
  )
}

// 窗口滚动事件
const onPanelScroll = (e: any) => {
  if (e.target.scrollTop == 0) {
    onRefreshLoad()
  }

  const height = e.target.scrollTop + e.target.clientHeight

  skipBottom.value = height < e.target.scrollHeight - 200
  if (!skipBottom.value && dialogueStore.unreadBubble) {
    dialogueStore.setUnreadBubble(0)
  }

  // 检测是否到达底部
  if (skipBottom.value == false) {
    let len = dialogueStore.records.length

    if (len > 100) {
      // 为了优化数据过多页面卡顿,页面最多只显示100条数据
      // 目前没有用虚拟列表只能这么干
      dialogueStore.records.splice(0, len - 100)

      let minSequence = 0
      dialogueStore.records.forEach((item: ITalkRecord) => {
        if (minSequence == 0 || item.sequence < minSequence) {
          minSequence = item.sequence
        }
      })

      loadConfig.cursor = minSequence
      loadConfig.status = 1
    }
  }
}

// 复制文本信息
const onCopyText = (data: ITalkRecord) => {
  if (data.msg_type == 1) {
    if (data.extra.content && data.extra.content.length > 0) {
      return clipboard(htmlDecode(data.extra.content), () => useMessage.success('复制成功'))
    }
  }

  if (data.extra?.url) {
    return clipboardImage(data.extra.url, () => {
      useMessage.success('复制成功')
    })
  }
}

// 删除对话消息
const onDeleteTalk = (data: ITalkRecord) => {
  dialogueStore.ApiDeleteRecord([data.msg_id])
}

// 撤销对话消息
const onRevokeTalk = (data: ITalkRecord) => {
  dialogueStore.ApiRevokeRecord(data.msg_id)
}

// 多选事件
const onMultiSelect = (data: ITalkRecord) => {
  dialogueStore.updateDialogueRecord({
    msg_id: data.msg_id,
    isCheck: true
  })

  dialogueStore.isOpenMultiSelect = true
}

const onDownloadFile = (data: ITalkRecord) => {
  if (data.msg_type == 3) {
    return downloadImage(data.extra.url, `${data.msg_id}.${data.extra.suffix}`)
  }

  if (data.msg_type == 4) {
    return useMessage.info('音频暂不支持下载!')
  }

  return useMessage.info('视频暂不支持下载!')
}

const onQuoteMessage = (data: ITalkRecord) => {
  let item = {
    id: data.msg_id,
    title: `${data.nickname} ${data.created_at}`,
    describe: '',
    image: ''
  }

  switch (data.msg_type) {
    case 1:
      item.describe = data?.extra?.content
      break // 文本消息
    case 2:
      item.describe = '[代码消息]'
      break // 代码消息
    case 3:
      item.image = data.extra.url
      break // 图片文件
    case 4:
      item.describe = '[语音文件]'
      break // 语音文件
    case 5:
      item.describe = '[视频文件]'
      break // 视频文件
    case 6:
      item.describe = '[其它文件]'
      break // 其它文件
    case 7:
      item.describe = '[位置消息]'
      break // 位置消息
    case 8:
      item.describe = '[名片消息]'
      break // 名片消息
    case 9:
      item.describe = '[转发消息]'
      break // 转发消息
    case 10:
      item.describe = '[登录消息]'
      break // 登录消息
    case 11:
      item.describe = '[投票消息]'
      break // 投票消息
    case 12:
      item.describe = '[图文消息]'
      break // 图文消息
  }

  bus.emit('editor:quote', item)
}

const onCollectImage = (data: ITalkRecord) => {
  if (data.msg_type == 3) {
    dialogueStore.ApiCollectImage({
      msg_id: data.msg_id
    })
  }
}

const onClickNickname = (data: ITalkRecord) => {
  bus.emit(EditorConst.Mention, {
    id: data.user_id,
    value: data.nickname
  })
}

// 会话列表右键显示菜单
const onContextMenu = (e: any, item: ITalkRecord) => {
  console.log('item',item)
  if (!dialogueStore.isShowEditor || dialogueStore.isOpenMultiSelect) {
    return e.preventDefault()
  }

  showDropdownMenu(e, props.uid, item)

  e.preventDefault()
}

const onConvertText = async (data: ITalkRecord) => {
  console.log('data', data)
  data.is_convert_text = 1
  const res = await voiceToText({ msgId: data.msg_id, voiceUrl: data.extra.url })
  if (res.code == 200) {
    data.extra.content = res.data.convText
  }
}
const onloseConvertText = (data: ITalkRecord) => {
  data.is_convert_text = 0
}
const evnets = {
  copy: onCopyText,
  revoke: onRevokeTalk,
  delete: onDeleteTalk,
  multiSelect: onMultiSelect,
  download: onDownloadFile,
  quote: onQuoteMessage,
  collect: onCollectImage,
  convertText: onConvertText,
  closeConvertText: onloseConvertText
}

// 会话列表右键菜单回调事件
const onContextMenuHandle = (key: string) => {
  // 触发事件
  evnets[key] && evnets[key](dropdown.item)
  closeDropdownMenu()
}

const onRowClick = (item: ITalkRecord) => {
  if (dialogueStore.isOpenMultiSelect) {
    if (ForwardableMessageType.includes(item.msg_type)) {
      item.isCheck = !item.isCheck
    } else {
      useMessage.info('此类消息不支持转发')
    }
  }
}

const lastParams = ref('')

// 监听整个 props 对象的变化
watch(
  () => props,
  async (newProps) => {
    await nextTick()
    let specialParams = undefined
    console.error(newProps, 'newProps')
    if (newProps.specifiedMsg) {
      try {
        const parsed = JSON.parse(decodeURIComponent(newProps.specifiedMsg))
        // 只有会话id和参数都匹配才进入特殊模式
        if (parsed.talk_type === newProps.talk_type && parsed.receiver_id === newProps.receiver_id) {
          specialParams = parsed
        }
      } catch (e) {}
    }
    onLoad(
      {
        receiver_id: newProps.receiver_id,
        talk_type: newProps.talk_type,
        limit: 30
      },
      specialParams ? { specifiedMsg: specialParams } : undefined
    )
  },
  { immediate: true, deep: true }
)

// onMounted(() => {
  // onLoad({ ...props, limit: 30 })
// })
const retry=(item:any)=>{
  confirmBox({
    content:'确定重发吗'
  }).then(()=>{
    
  })
}
</script>

<template>
  <section class="section">
    <div
      id="imChatPanel"
      class="me-scrollbar me-scrollbar-thumb talk-container"
      @scroll="onPanelScroll($event)"
    >
      <!-- 数据加载状态栏 -->
      <div class="load-toolbar pointer">
        <span v-if="loadConfig.status == 0"> 正在加载数据中 ... </span>
        <span v-else-if="loadConfig.status == 1" @click="onRefreshLoad"> 查看更多消息 ... </span>
        <span v-else class="no-more"> 没有更多消息了 </span>
      </div>

      <div
        class="message-item"
        v-for="(item, index) in records"
        :key="item.msg_id"
        :id="item.msg_id"
      >
        <!-- 系统消息 -->
        <div v-if="item.msg_type >= 1000" class="message-box">
          <component
            :is="MessageComponents[item.msg_type] || 'unknown-message'"
            :extra="item.extra"
            :data="item"
          />
        </div>

        <!-- 撤回消息 -->
        <div v-else-if="item.is_revoke == 1" class="message-box">
          <revoke-message
            :login_uid="uid"
            :data="item"
            :user_id="item.user_id"
            :nickname="item.nickname"
            :talk_type="item.talk_type"
            :datetime="item.created_at"
          />
        </div>

        <div
          v-else
          class="message-box record-box"
          :class="{
            'direction-rt': item.float == 'right',
            'multi-select': dialogueStore.isOpenMultiSelect,
            'multi-select-check': item.isCheck
          }"
        >
          <!-- 多选按钮 -->
          <aside v-if="dialogueStore.isOpenMultiSelect" class="checkbox-column shrink-0">
            <n-checkbox size="small" :checked="item.isCheck" @update:checked="item.isCheck = !item.isCheck" />
          </aside>
          <!-- 头像信息 -->

          <aside class="avatar-column">
            <im-avatar
              class="pointer"
              :src="item.avatar"
              :size="42"
              :username="item.nickname"
              @click="showUserInfoModal(item.erp_user_id, item.user_id)"
            />
          </aside>

          <!-- 主体信息 -->
          <main class="main-column">
            <div class="talk-title">
              <span
                class="nickname pointer"
                v-show="talk_type == 2 && item.float == 'left'"
                @click="onClickNickname(item)"
              >
                <span class="at">@</span>{{ item.nickname }}
              </span>
              <span>{{ parseTime(item.created_at, '{y}/{m}/{d} {h}:{i}') }}</span>
            </div>

            <div
              class="talk-content"
              :class="{ pointer: dialogueStore.isOpenMultiSelect }"
              @click="onRowClick(item)"
            >
              <component
                :is="MessageComponents[item.msg_type] || 'unknown-message'"
                :extra="item.extra"
                :data="item"
                :max-width="true"
                :source="'panel'"
                @contextmenu.prevent="onContextMenu($event, item)"
              />
              <div
                v-if="
                  item.float === 'right' && item.extra.percentage === -1 && item.extra.is_uploading
                "
                class="mr-10px"
              >
                <n-button text style="font-size: 20px;" @click="retry(item)">
                  <n-icon color="#CF3050">
                    <ExclamationCircleFilled />
                  </n-icon>
                </n-button>
              </div>
              <!-- <div class="talk-tools">
                <template v-if="talk_type == 1 && item.float == 'right'">
                  <loading
                    theme="outline"
                    size="19"
                    fill="#000"
                    :strokeWidth="1"
                    class="icon-rotate"
                    v-show="item.send_status == 1"
                  />

                  <span v-show="item.send_status == 1"> 正在发送... </span>
                  <span v-show="item.send_status != 1"> 已送达 </span>
                </template>

<n-icon class="more-tools pointer" :component="MoreThree" @click="onContextMenu($event, item)" />
</div> -->
            </div>

            <div
              v-if="item.extra.reply"
              class="talk-reply pointer"
              @click="onJumpMessage(item.extra?.reply?.msg_id)"
            >
              <n-icon :component="ToTop" size="14" class="icon-top" />
              <span class="ellipsis">
                回复 {{ item.extra?.reply?.nickname }}:
                {{ item.extra?.reply?.content }}
              </span>
            </div>
          </main>
        </div>

        <div class="datetime" v-show="isShowTalkTime(index, item.created_at)">
          {{ formatTime(item.created_at) }}
        </div>
      </div>
    </div>

    <!-- 置底按钮 -->
    <SkipBottom v-model="skipBottom" />
  </section>

  <!-- 右键菜单 -->
  <n-dropdown
    :show="dropdown.show"
    :x="dropdown.x"
    :y="dropdown.y"
    style="width: 142px;"
    :options="dropdown.options"
    @select="onContextMenuHandle"
    @clickoutside="closeDropdownMenu"
  />
</template>

<style lang="less" scoped>
.section {
  position: relative;
  height: 100%;
  width: 100%;
  overflow: hidden;
}

.talk-container {
  height: 100%;
  width: 100%;
  box-sizing: border-box;
  padding: 10px 15px 30px;
  overflow-y: auto;
  overflow-x: hidden;

  .load-toolbar {
    height: 38px;
    color: #409eff;
    text-align: center;
    line-height: 38px;
    font-size: 13px;

    .no-more {
      color: #b9b3b3;
    }
  }

  .message-item {
    &.border {
      border-radius: 10px;
      border: 1px solid var(--im-primary-color);
    }
  }

  .message-box {
    width: 100%;
    min-height: 30px;
    margin-bottom: 5px;
  }

  .datetime {
    height: 30px;
    line-height: 30px;
    color: #ccc9c9;
    font-size: 12px;
    text-align: center;
    margin: 5px 0;
  }

  .record-box {
    display: flex;
    flex-direction: row;

    .checkbox-column {
      display: flex;
      justify-content: center;
      width: 35px;
      order: 1;
      user-select: none;
      padding-top: 12px;
    }

    .avatar-column {
      width: 47px;
      display: flex;
      align-items: center;
      order: 2;
      user-select: none;
      padding-top: 10px;
      flex-direction: column;
    }

    .main-column {
      flex: 1 auto;
      order: 3;
      position: relative;
      box-sizing: border-box;
      padding: 5px;
      overflow: hidden;
      min-height: 30px;

      .talk-title {
        display: flex;
        align-items: center;
        height: 24px;
        margin-bottom: 2px;
        font-size: 12px;
        user-select: none;
        color: #a7a0a0;
        opacity: 1;

        &.show {
          opacity: 1;
        }

        .nickname {
          color: var(--im-text-color);
          margin-right: 5px;
          font-size: 12px;

          .at {
            display: none;
          }

          &:hover {
            color: var(--im-primary-color);

            .at {
              display: inline-block;
            }
          }
        }

        span {
          transform: scale(0.88);
          transform-origin: left center;
        }
      }

      .talk-content {
        display: flex;
        justify-content: flex-start;
        align-items: flex-end;

        box-sizing: border-box;
        width: 100%;

        .talk-tools {
          display: flex;
          margin: 0 8px;
          color: #a79e9e;
          font-size: 12px;
          user-select: none;
          align-items: center;
          justify-content: space-around;

          .more-tools {
            visibility: hidden;
            margin-left: 5px;
          }
        }
      }

      .talk-reply {
        display: flex;
        align-items: flex-start;
        align-items: center;
        width: fit-content;
        padding: 4px;
        margin-top: 3px;
        margin-right: auto;
        font-size: 12px;
        color: #8f8f8f;
        word-break: break-all;
        background-color: var(--im-message-left-bg-color);
        border-radius: 5px;
        max-width: 300px;
        overflow: hidden;
        user-select: none;

        .icon-top {
          margin-right: 3px;
        }

        .ellipsis {
          display: -webkit-inline-box;
          text-overflow: ellipsis;
          -webkit-line-clamp: 3;
          -webkit-box-orient: vertical;
        }
      }

      &:hover {
        .talk-title {
          opacity: 1;
        }

        .more-tools {
          visibility: visible !important;
        }
      }
    }

    &.direction-rt {
      .avatar-column {
        order: 3;
      }

      .main-column {
        order: 2;

        .talk-title {
          justify-content: flex-end;

          span {
            transform-origin: right center;
          }
        }

        .talk-content {
          flex-direction: row-reverse;
        }

        .talk-reply {
          margin-right: 0;
          margin-left: auto;
        }
      }
    }

    &.multi-select {
      border-radius: 5px;

      &:hover,
      &.multi-select-check {
        background-color: var(--im-active-bg-color);
      }
    }
  }
}
</style>