<template>
  <mt-preview ref="MtPreviewRef" @on-event-call-back="onEventCallBack" />
</template>
<script setup lang="ts">
import { WebtopoProjectApi, parseWebtopoDataModel } from '@/api/pms/maotu'
import { IotDeviceApi } from '@/api/pms/device'
import type { IExportJson } from '@/components/mt-edit/components/types'
import { MtPreview } from '@/export'
import { ElMessage } from 'element-plus'
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()
const router = useRouter()
const MtPreviewRef = ref<InstanceType<typeof MtPreview>>()
const previewData = ref<IExportJson>()
const pollingTimer = ref<number>()
const polling = ref(false)

const getProjectId = () => {
  const id = Number(route.params.id)
  return Number.isFinite(id) && id > 0 ? id : undefined
}

type DevicePointData = {
  identifier?: string
  value?: unknown
  unit?: string
}

const setPreviewData = async (dataModel: unknown) => {
  if (!dataModel) {
    return
  }

  previewData.value = dataModel as IExportJson
  await nextTick()
  MtPreviewRef.value?.setImportJson(previewData.value)
}

const getDeviceBindItems = () => {
  const previewItems = previewData.value?.pages?.length
    ? previewData.value.pages.flatMap((page) => page.json)
    : previewData.value?.json || []

  return previewItems.flatMap((item) =>
    (item.deviceBinds || [])
      .filter((bind) => bind.deviceId && bind.deviceProp && bind.nodeProp)
      .map((bind) => ({
        itemId: item.id,
        deviceId: bind.deviceId!,
        deviceProp: bind.deviceProp!,
        nodeProp: bind.nodeProp!
      }))
  )
}

const formatDevicePointValue = (item: DevicePointData) => {
  if (!item.unit) {
    return item.value
  }
  return `${item.value ?? ''} ${item.unit}`
}

const refreshDeviceBindValues = async () => {
  if (polling.value) {
    return
  }

  const bindItems = getDeviceBindItems()
  const deviceIds = Array.from(new Set(bindItems.map((item) => item.deviceId)))
  if (!bindItems.length || !deviceIds.length) {
    return
  }

  polling.value = true
  try {
    const deviceDataList = await Promise.all(
      deviceIds.map(async (deviceId) => {
        const data = ((await IotDeviceApi.getIotDeviceTds(deviceId)) || []) as DevicePointData[]
        return { deviceId, data }
      })
    )
    const valueMap = new Map<string, unknown>()
    deviceDataList.forEach(({ deviceId, data }) => {
      data.forEach((item) => {
        if (item.identifier) {
          valueMap.set(`${deviceId}:${item.identifier}`, formatDevicePointValue(item))
        }
      })
    })

    MtPreviewRef.value?.setItemAttrs(
      bindItems
        .filter((item) => valueMap.has(`${item.deviceId}:${item.deviceProp}`))
        .map((item) => ({
          id: item.itemId,
          key: item.nodeProp,
          val: valueMap.get(`${item.deviceId}:${item.deviceProp}`)
        }))
    )
  } finally {
    polling.value = false
  }
}

const startDeviceBindPolling = () => {
  if (pollingTimer.value) {
    clearInterval(pollingTimer.value)
  }

  refreshDeviceBindValues()
  pollingTimer.value = window.setInterval(refreshDeviceBindValues, 5000)
}

const stopDeviceBindPolling = () => {
  if (pollingTimer.value) {
    clearInterval(pollingTimer.value)
    pollingTimer.value = undefined
  }
}

const loadProject = async () => {
  stopDeviceBindPolling()
  const id = getProjectId()
  if (!id) {
    const exportJson = sessionStorage.getItem('exportJson')
    await setPreviewData(parseWebtopoDataModel(exportJson))
    startDeviceBindPolling()
    return
  }

  try {
    const data = await WebtopoProjectApi.getWebtopoProject(id)
    if (data?.dataModelParseError) {
      ElMessage.error(data.dataModelParseError)
      return
    }
    await setPreviewData(data?.dataModel)
    startDeviceBindPolling()
  } catch {
    // ElMessage.error('拓扑数据加载失败')
  }
}

const onEventCallBack = (type: string, item_id: string, targetProjectId?: number) => {
  console.log(type, item_id)

  if (type == 'test-dialog') {
    ElMessage.success(`获取到了id:${item_id}`)
  } else if (type == 'openWebtopo' && targetProjectId) {
    const routeInfo = router.resolve(`/maotu/preview/${targetProjectId}`)
    window.open(routeInfo.href, '_blank')
  }
}

onMounted(() => {
  loadProject()
})

watch(
  () => route.params.id,
  () => {
    loadProject()
  }
)

onUnmounted(() => {
  stopDeviceBindPolling()
})
</script>
