<script setup lang="ts">
import { findNewComponentFromList } from '@/custom-component/component-list' // 左侧列表数据
import { computed, nextTick, onMounted, reactive, ref, toRefs, onBeforeUnmount, watch } from 'vue'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import { storeToRefs } from 'pinia'
import eventBus from '../../utils/eventBus'
import { guid } from '@/views/visualized/data/dataset/form/util.js'
import elementResizeDetectorMaker from 'element-resize-detector'
import { getCanvasStyle, syncShapeItemStyle } from '@/utils/style'
import { adaptCurThemeCommonStyle } from '@/utils/canvasStyle'
import CanvasCore from '@/components/data-visualization/canvas/CanvasCore.vue'
import { isMainCanvas, isDashboard } from '@/utils/canvasUtils'

// change-begin
const props = defineProps({
  canvasStyleData: {
    type: Object,
    required: true
  },
  componentData: {
    type: Array,
    required: true
  },
  canvasViewInfo: {
    type: Object,
    required: true
  },
  canvasId: {
    type: String,
    required: false,
    default: 'canvas-main'
  },
  canvasActive: {
    type: Boolean,
    default: true
  },
  outerScale: {
    type: Number,
    required: false,
    default: 1
  },
  // 仪表板字体
  fontFamily: {
    type: String,
    required: false,
    default: 'inherit'
  },
  // 画布位置
  canvasPosition: {
    type: String,
    required: false,
    default: 'main'
  }
})
const { canvasStyleData, componentData, canvasViewInfo, canvasId, canvasActive, canvasPosition } =
  toRefs(props)
const domId = ref('de-canvas-' + canvasId.value)
// change-end

const dvMainStore = dvMainStoreWithOut()
const snapshotStore = snapshotStoreWithOut()
const { pcMatrixCount, curOriginThemes, mobileInPc } = storeToRefs(dvMainStore)
const canvasOut = ref(null)
const canvasInner = ref(null)
const canvasInitStatus = ref(false)
const scaleWidth = ref(100)
const scaleHeight = ref(100)
const scaleMin = ref(100)

const state = reactive({
  screenWidth: 1920,
  screenHeight: 1080,
  curScrollTop: 0
})

//仪表板矩阵信息适配，
const baseWidth = ref(0)
const baseHeight = ref(0)
const renderState = ref(false) // 仪表板默认
const baseMarginLeft = ref(0)
const baseMarginTop = ref(0)
const cyGridster = ref(null)
const editDomId = ref('edit-' + canvasId.value)

const editStyle = computed(() => {
  if (canvasStyleData.value && isMainCanvas(canvasId.value)) {
    return {
      ...getCanvasStyle(canvasStyleData.value)
    }
  } else {
    return {}
  }
})

// 通过实时监听的方式直接添加组件
const handleNewFromCanvasMain = newComponentInfo => {
  const { componentName, innerType, staticMap } = newComponentInfo
  if (componentName) {
    const component = findNewComponentFromList(componentName, innerType, curOriginThemes, staticMap)
    syncShapeItemStyle(component, baseWidth.value, baseHeight.value)
    component.id = guid()
    component.y = undefined
    component.x = cyGridster.value.findPositionX(component)
    dvMainStore.addComponent({
      component: component,
      index: undefined
    })
    adaptCurThemeCommonStyle(component)
    nextTick(() => {
      cyGridster.value.addItemBox(component) //在适当的时候初始化布局组件
      nextTick(() => {
        scrollTo(component.y)
      })
    })
    snapshotStore.recordSnapshotCacheWithPositionChange('renderChart', component.id)
  }
}

const handleDrop = e => {
  if (isMainCanvas(canvasId.value)) {
    e.preventDefault()
    e.stopPropagation()
    const addComponent = cyGridster.value.getMoveItem()
    // 当前isShow =  true 则确定已经移入画布中
    addComponent.isShow = true
    syncShapeItemStyle(addComponent, baseWidth.value, baseHeight.value)
    cyGridster.value.handleMouseUp(e, addComponent, componentData.value.length - 1)
    snapshotStore.recordSnapshotCacheWithPositionChange('renderChart', addComponent.id)
  }
}

const handleDragOver = e => {
  if (isMainCanvas(canvasId.value)) {
    e.preventDefault()
    e.dataTransfer.dropEffect = 'copy'
    cyGridster.value.handleDragOver(e)
  }
}

const handleMouseDown = e => {
  if (isMainCanvas(canvasId.value)) {
    e.stopPropagation()
    dvMainStore.setClickComponentStatus(false)
    dvMainStore.setInEditorStatus(true)
    dvMainStore.setCurComponent({ component: null, index: null })
  }
}

const canvasInitImmediately = () => {
  cyGridster.value.canvasInit()
}

const canvasInit = (isFistLoad = true) => {
  if (canvasActive.value || canvasPosition.value === 'tab') {
    renderState.value = true
    setTimeout(function () {
      if (canvasOut.value) {
        dashboardCanvasSizeInit()
        nextTick(() => {
          cyGridster.value.canvasInit() //在适当的时候初始化布局组件
          cyGridster.value.afterInitOk(function () {
            renderState.value = false
          })
        })
      }
      // afterInit
      dvMainStore.setDataPrepareState(true)
      if (isMainCanvas(canvasId.value) && isFistLoad) {
        snapshotStore.recordSnapshotCache('renderChart')
      }
    }, 500)
  }
}

const canvasSizeInit = () => {
  nextTick(() => {
    if (canvasOut.value) {
      //div容器获取tableBox.value.clientWidth
      dashboardCanvasSizeInit()
      nextTick(() => {
        cyGridster.value.canvasSizeInit() //在适当的时候初始化布局组件
        // 缩放比例变化
        scaleInit()
      })
    }
  })
}

const scaleInit = () => {
  nextTick(() => {
    if (canvasOut.value) {
      //div容器获取tableBox.value.clientWidth
      let canvasWidth = canvasOut.value.clientWidth
      let canvasHeight = canvasOut.value.clientHeight
      scaleWidth.value = Math.floor((canvasWidth * 100) / canvasStyleData.value.width)
      scaleHeight.value = Math.floor((canvasHeight * 100) / canvasStyleData.value.height)
      scaleMin.value = Math.min(scaleWidth.value, scaleHeight.value)
      if (isDashboard() && isMainCanvas(canvasId.value)) {
        const offset = mobileInPc.value ? 4 : 1
        dvMainStore.setCanvasStyleScale(scaleMin.value * offset)
      }
    }
  })
}

const dashboardCanvasSizeInit = () => {
  //div容器获取tableBox.value.clientWidth
  state.screenWidth = canvasOut.value.clientWidth - 4
  state.screenHeight = canvasOut.value.clientHeight
  baseWidth.value = state.screenWidth / pcMatrixCount.value.x
  baseHeight.value = state.screenHeight / pcMatrixCount.value.y
  baseMarginLeft.value = 0
  baseMarginTop.value = 0
  canvasInitStatus.value = true
  if (isMainCanvas(canvasId.value)) {
    dvMainStore.setBashMatrixInfo({
      baseWidth: baseWidth.value,
      baseHeight: baseHeight.value,
      baseMarginLeft: baseMarginLeft.value,
      baseMarginTop: baseMarginTop.value
    })
  }
}
const addItemBox = component => {
  cyGridster.value.addItemBox(component)
}

const moveOutFromTab = component => {
  setTimeout(() => {
    component.canvasId = canvasId.value
    dvMainStore.addComponent({
      component,
      index: undefined,
      isFromGroup: true
    })
    addItemBox(component)
    canvasInit()
  }, 500)
}

// 全局监听按键事件
onMounted(() => {
  window.addEventListener('resize', canvasSizeInit)
  const erd = elementResizeDetectorMaker()
  erd.listenTo(document.getElementById(domId.value), () => {
    canvasSizeInit()
  })
  canvasInit()
  if (isMainCanvas(canvasId.value)) {
    eventBus.on('handleNew', handleNewFromCanvasMain)
    eventBus.on('event-canvas-size-init', canvasSizeInit)
  }
  eventBus.on('moveOutFromTab-' + canvasId.value, moveOutFromTab)
  eventBus.on('matrix-canvasInit', canvasInit)
})

onBeforeUnmount(() => {
  if (isMainCanvas(canvasId.value)) {
    eventBus.off('handleNew', handleNewFromCanvasMain)
    eventBus.off('event-canvas-size-init', canvasSizeInit)
  }
  eventBus.off('moveOutFromTab-' + canvasId.value, moveOutFromTab)
  eventBus.off('matrix-canvasInit', canvasInit)
})

const getBaseMatrixSize = () => {
  return {
    baseWidth: baseWidth.value,
    baseHeight: baseHeight.value
  }
}

const scrollTo = (y = 1) => {
  setTimeout(() => {
    canvasInner.value.scrollTo({
      top: (y - 1) * baseHeight.value,
      behavior: 'smooth'
    })
    cyGridster.value?.watermarkUpdate()
  })
}

const scrollCanvas = () => {
  if (isMainCanvas(canvasId.value)) {
    dvMainStore.mainScrollTop = canvasInner.value.scrollTop
  }
}

watch(
  () => canvasActive.value,
  () => {
    if (canvasActive.value) {
      canvasSizeInit()
    }
  }
)

defineExpose({
  addItemBox,
  canvasInit,
  canvasInitImmediately,
  getBaseMatrixSize
})
</script>

<template>
  <div ref="canvasOut" :id="editDomId" class="content" :class="{ 'render-active': renderState }">
    <canvas-opt-bar
      :canvas-style-data="canvasStyleData"
      :component-data="componentData"
      :canvas-id="canvasId"
    ></canvas-opt-bar>
    <div
      :id="domId"
      ref="canvasInner"
      class="db-canvas"
      :class="{ 'db-canvas-dashboard': !isDashboard() }"
      :style="editStyle"
      @drop="handleDrop"
      @dragover="handleDragOver"
      @mousedown="handleMouseDown"
      @scroll="scrollCanvas"
    >
      <canvas-core
        ref="cyGridster"
        v-if="canvasInitStatus"
        :component-data="componentData"
        :canvas-style-data="canvasStyleData"
        :canvas-view-info="canvasViewInfo"
        :canvas-id="canvasId"
        :base-margin-left="baseMarginLeft"
        :base-margin-top="baseMarginTop"
        :base-width="baseWidth"
        :base-height="baseHeight"
        :font-family="fontFamily"
        @scrollCanvasAdjust="scrollTo"
      ></canvas-core>
    </div>
  </div>
</template>

<style lang="less" scoped>
.db-canvas-dashboard {
  padding: 0 !important;
}
.content {
  width: 100%;
  height: 100%;
  .db-canvas {
    padding: 2px;
    background-size: 100% 100% !important;
    overflow-y: auto;
    width: 100%;
    height: 100%;
  }
  ::-webkit-scrollbar {
    display: none;
  }
}

.render-active {
  opacity: 1;
}
</style>
