<script setup lang="ts">
import EventCard from './components/EventCard.vue'
import PasswordCard from './components/PasswordCard.vue'
import FeatureUpdateCard from './components/FeatureUpdateCard.vue'
import { useNotificationMessage } from '@/stores/modules/notificationMessage'
import { cloneDeep } from 'lodash'

const notificationMsgStore = useNotificationMessage()
const props = withDefaults(
  defineProps<{
    data: any
    isObserver?: boolean // 是否开启监听
    updateReadCardsOnChange?: boolean // 是否在数据变化时请求接口更新已读卡片
  }>(),
  {
    isObserver: true,
    updateReadCardsOnChange: true
  }
)

const pageData = ref<any[]>([])

const emit = defineEmits<{ seeAll: []; hasCardRead: []; viewMore: []; jumpTracking: [] }>()
const handleSeeAll = () => {
  emit('seeAll')
}

// 创建一个新的 IntersectionObserver 实例
const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach((entry) => {
      const cardId = entry.target?.dataset?.cardId
      if (entry.isIntersecting) {
        // 将卡片设置为已经展示
        notificationMsgStore.setReadCardMap(cardId)
        const index = pageData.value.findIndex((item) => item.info.id === cardId)
        if (index > -1) {
          //  在1秒钟后将消息卡片设置为已读
          setTimeout(() => {
            pageData.value[index].info.isRead = true
            emit('hasCardRead')
          }, 400)
        }
      }
    })
  },
  {
    // 配置选项
    root: null, // 使用视窗作为根元素
    threshold: 0.1 // 当至少10%的元素进入视图时触发回调
  }
)
const curPageAllCards = ref<any>([])
// 监听元素是否在可视区域内
const watchCards = () => {
  curPageAllCards.value = document?.querySelectorAll('.notification-message-card')
  curPageAllCards.value.forEach((card: any) => {
    // const index = notificationMsgStore.notificationMsgList.indexOf(card.dataset.cardId)
    // index < 0 &&
    if (card.dataset.cardIsread === 'false' && card.dataset.cardId) {
      notificationMsgStore.concatNotificationMsgList([card.dataset.cardId])

      observer.observe(card)
    }
  })
}

const clearReadData = (data) => {
  const curData = data || []
  // 将当前页面剩余未读消息id从监听列表中移除
  const idsToRemove = curData.map((item: any) => item.info.id)
  notificationMsgStore.removeNotificationMsgList(idsToRemove)

  // 清除当前页面的所有卡片的监听
  curPageAllCards.value.forEach((card: any) => {
    observer.unobserve(card)
  })
}

const compareIdsInArrays = (arr1, arr2) => {
  // 如果两个数组长度不同，则它们不可能有相同的id集合
  if (arr1.length !== arr2.length) {
    return false
  }

  // 提取两个数组中的所有有效id并转换为Set
  const ids1 = new Set(arr1.filter((item) => item.info && item.info.id).map((item) => item.info.id))
  const ids2 = new Set(arr2.filter((item) => item.info && item.info.id).map((item) => item.info.id))

  // 比较两个Set的大小是否相同
  if (ids1.size !== ids2.size) {
    return false
  }

  // 检查ids1中的每个id是否都存在于ids2中
  for (let id of ids1) {
    if (!ids2.has(id)) {
      return false
    }
  }

  return true
}

if (props.isObserver) {
  watch(
    () => props.data,
    (newData, oldData) => {
      // 因为当父组件中数据已读未读状态变化时，也会触发props.data变化，此时不需要更新页面数据，根据id是否相等来判断这种情况
      if (compareIdsInArrays(oldData || [], newData || [])) return

      pageData.value = cloneDeep(newData)
      // 先清除旧数据中的卡片监听
      clearReadData(oldData)

      // 请求接口将旧数据中的新已读卡片上传服务器
      props.data.updateReadCardsOnChange && notificationMsgStore.markMessageAsRead()

      // 重新监听新数据中的卡片
      nextTick(() => {
        watchCards()
      })
    },
    {
      immediate: true,
      deep: true
    }
  )
}

// 定时将消息卡片未读的置为已读，五分钟一次
let timer = null
onMounted(() => {
  if (props.isObserver) {
    timer = setInterval(() => {
      notificationMsgStore.markMessageAsRead()
    }, 300000)
  }
})
onUnmounted(() => {
  if (props.isObserver) {
    notificationMsgStore.markMessageAsRead()
    clearReadData(pageData.value)
    clearInterval(timer)
  }
})

const handleViewMore = () => {
  emit('viewMore')
}
</script>

<template>
  <div
    class="notification-message-card"
    :data-card-id="item.info.id"
    :data-card-isread="item.info.isRead"
    v-for="item in pageData"
    :key="item.info.id || Math.random()"
  >
    <EventCard
      @seeAll="handleSeeAll"
      @jump-tracking="emit('jumpTracking')"
      v-if="item.notificationType === 'event'"
      :data="item.info"
    />
    <PasswordCard v-else-if="item.notificationType === 'password'" :data="item.info" />
    <FeatureUpdateCard
      @view-more="handleViewMore"
      v-else-if="item.notificationType === 'feature'"
      :data="item.info"
    />
    <slot></slot>
  </div>
</template>

<style lang="scss" scoped></style>
