<script setup lang="ts">
import {
  WebtopoProjectApi,
  type WebtopoProjectDetailVO,
  type WebtopoProjectUpdateReqVO
} from '@/api/pms/maotu'
import type { IExportJson } from '@/components/mt-edit/components/types'
import { useGenThumbnail } from '@/components/mt-edit/composables/thumbnail'
import { MtEdit } from '@/export'
import { Canvg } from 'canvg'
import html2canvas from 'html2canvas'
import { ElMessage } from 'element-plus'
import { nextTick, onMounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import DeviceBindPanel from './components/DeviceBindPanel.vue'
const route = useRoute()
const router = useRouter()
const MtEditRef = ref<InstanceType<typeof MtEdit>>()
const projectDetail = ref<WebtopoProjectDetailVO>()
const saveLoading = ref(false)
const dataModelParseError = ref('')

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

const getLinkedDeviceIds = (detail: WebtopoProjectDetailVO) => {
  return detail.linkedDeviceIds || detail.linkedDevices?.map((item) => item.id) || []
}

const loadProject = async () => {
  const id = getProjectId()
  if (!id) {
    return
  }

  try {
    const data = await WebtopoProjectApi.getWebtopoProject(id)
    projectDetail.value = data
    dataModelParseError.value = data?.dataModelParseError || ''

    if (dataModelParseError.value) {
      ElMessage.error(dataModelParseError.value)
      return
    }

    if (data?.dataModel) {
      await nextTick()
      MtEditRef.value?.setImportJson(data.dataModel as IExportJson)
    }
  } catch {
    ElMessage.error('拓扑数据加载失败')
  }
}

const resetAndLoadProject = async () => {
  await nextTick()
  MtEditRef.value?.reset()
  projectDetail.value = undefined
  dataModelParseError.value = ''
  await loadProject()
}

const genThumbnailDataUrl = async (canvasId = 'mtCanvasArea') => {
  const el = document.querySelector<HTMLElement>(`#${canvasId}`)
  if (!el) {
    ElMessage.error('没有找到canvas元素,请检查！')
    return projectDetail.value?.thumbnail
  }

  const shouldRemoveSvgNodes: HTMLCanvasElement[] = []
  const svgElements = document.body.querySelectorAll<HTMLElement>(`#${canvasId} .mt-line-render`)

  for (const item of svgElements) {
    const svg = item.outerHTML.trim()
    const canvas = document.createElement('canvas')
    canvas.width = item.getBoundingClientRect().width
    canvas.height = item.getBoundingClientRect().height
    const ctx = canvas.getContext('2d')
    const v = Canvg.fromString(ctx!, svg)
    await v.render()

    if (item.style.position) {
      canvas.style.position += item.style.position
      canvas.style.left += item.style.left
      canvas.style.top += item.style.top
    }

    item.parentNode!.appendChild(canvas)
    shouldRemoveSvgNodes.push(canvas)
  }

  try {
    const width = el.offsetWidth
    const height = el.offsetHeight
    const canvas = await html2canvas(el, {
      useCORS: true,
      scale: 2,
      width,
      height,
      allowTaint: true,
      windowHeight: height,
      logging: false,
      ignoreElements: (element) => element.classList.contains('mt-line-render')
    })

    return canvas.toDataURL('image/png')
  } finally {
    shouldRemoveSvgNodes.forEach((item) => item.remove())
  }
}

const onPreviewClick = (exportJson: IExportJson) => {
  sessionStorage.setItem('exportJson', JSON.stringify(exportJson))
  const routeUrl = router.resolve({
    name: 'MaotuPreview'
  })
  window.open(routeUrl.href, '_blank')
}
const onSaveClick = async (dataModel: IExportJson) => {
  const detail = projectDetail.value
  if (!detail?.id) {
    ElMessage.error('项目信息不存在，无法保存')
    return
  }
  if (dataModelParseError.value) {
    ElMessage.error('拓扑数据格式错误，修复后才能保存')
    return
  }

  try {
    saveLoading.value = true
    const thumbnail = await genThumbnailDataUrl()
    const data: WebtopoProjectUpdateReqVO = {
      id: detail.id,
      projectName: detail.projectName,
      linkedDeviceIds: getLinkedDeviceIds(detail),
      remark: detail.remark,
      thumbnail,
      dataModel: JSON.stringify(dataModel)
    }

    await WebtopoProjectApi.updateWebtopoProject(data)
    projectDetail.value = {
      ...detail,
      thumbnail,
      dataModel: JSON.stringify(dataModel)
    }
    ElMessage.success('更新成功')
  } finally {
    saveLoading.value = false
  }
}
const onReturnClick = () => {
  router.go(-1)
}
const onThumbnailClick = () => {
  useGenThumbnail()
}

onMounted(() => {
  resetAndLoadProject()
})

watch(() => route.params.id, resetAndLoadProject)
</script>

<template>
  <div
    v-loading="saveLoading"
    element-loading-text="正在生成缩略图并保存，请稍候"
    class="w-1/1 h-100vh">
    <mt-edit
      ref="MtEditRef"
      :use-thumbnail="true"
      :save-loading="saveLoading"
      @on-preview-click="onPreviewClick"
      @on-return-click="onReturnClick"
      @on-save-click="onSaveClick"
      @on-thumbnail-click="onThumbnailClick">
      <template #deviceBind="{ item }">
        <DeviceBindPanel :item="item" :devices="projectDetail?.linkedDevices || []" />
      </template>
    </mt-edit>
  </div>
</template>

<style scoped></style>
