<script lang="ts" setup>
import {
  computed,
  nextTick,
  onBeforeUnmount,
  onMounted,
  reactive,
  ref,
  shallowRef,
  toRefs
} from 'vue'
import { getData } from '@/api/chart'
import { ChartLibraryType } from '@/views/chart/components/js/panel/types'
import { G2PlotChartView } from '@/views/chart/components/js/panel/types/impl/g2plot'
import { L7PlotChartView } from '@/views/chart/components/js/panel/types/impl/l7plot'
import chartViewManager from '@/views/chart/components/js/panel'
import { useAppStoreWithOut } from '@/store/modules/app'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import ViewTrackBar from '@/components/visualization/ViewTrackBar.vue'
import { storeToRefs } from 'pinia'
import { parseJson } from '@/views/chart/components/js/util'
import { defaultsDeep, cloneDeep } from 'lodash-es'
import ChartError from '@/views/chart/components/views/components/ChartError.vue'
import { BASE_VIEW_CONFIG } from '../../editor/util/chart'
import { customAttrTrans, customStyleTrans, recursionTransObj } from '@/utils/canvasStyle'
import { deepCopy, isMobile } from '@/utils/utils'
import { isDashboard, trackBarStyleCheck } from '@/utils/canvasUtils'
import { useEmitt } from '@/hooks/web/useEmitt'
import { L7ChartView } from '@/views/chart/components/js/panel/types/impl/l7'
import { useI18n } from '@/hooks/web/useI18n'
import { ExportImage, Scale, Fullscreen, Control, Scene, TileLayer } from '@antv/l7'
import { GaodeMap } from '@antv/l7-maps';
//三维导入
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js' // 控制器
const { t } = useI18n()
const dvMainStore = dvMainStoreWithOut()
const { nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc, embeddedCallBack, inMobile } =
  storeToRefs(dvMainStore)
const { emitter } = useEmitt()
const props = defineProps({
  element: {
    type: Object,
    default() {
      return {
        propValue: null
      }
    }
  },
  view: {
    type: Object,
    default() {
      return {
        propValue: null
      }
    }
  },
  showPosition: {
    type: String,
    required: false,
    default: 'canvas'
  },
  scale: {
    type: Number,
    required: false,
    default: 1
  },
  terminal: {
    type: String,
    default: 'pc'
  },
  //图表渲染id后缀
  suffixId: {
    type: String,
    required: false,
    default: 'common'
  },
  fontFamily: {
    type: String,
    required: false,
    default: 'inherit'
  }
})

const emit = defineEmits([
  'onPointClick',
  'onChartClick',
  'onDrillFilters',
  'onJumpClick',
  'resetLoading'
])

const g2TypeSeries1 = ['bidirectional-bar']
const g2TypeSeries0 = ['bar-range']
const g2TypeTree = ['circle-packing']

const { view, showPosition, scale, terminal, suffixId } = toRefs(props)

const isError = ref(false)
const errMsg = ref('')
const linkageActiveHistory = ref(false)

const dataVMobile = !isDashboard() && isMobile()

const state = reactive({
  trackBarStyle: {
    position: 'absolute',
    left: '50px',
    top: '50px'
  },
  trackBarStyleMobile: {
    position: 'absolute',
    left: '50px',
    top: '50px'
  },
  linkageActiveParam: null,
  pointParam: null,
  data: { fields: [] }, // 图表数据
  satelliteVisible: false, // 新增卫星图层状态
})
let chartData = shallowRef<Partial<Chart['data']>>({
  fields: []
})
// 添加普通变量存储Three.js对象
let threeScene: THREE.Scene | null = null;
let threeRenderer: THREE.WebGLRenderer | null = null;
let threeCamera: THREE.PerspectiveCamera | null = null;
let model: THREE.Object3D | null = null;
const containerId = 'container-' + showPosition.value + '-' + view.value.id + '-' + suffixId.value
const viewTrack = ref(null)

const clearLinkage = () => {
  linkageActiveHistory.value = false
  try {
    myChart?.setState('active', () => true, false)
    myChart?.setState('inactive', () => true, false)
    myChart?.setState('selected', () => true, false)
  } catch (e) {
    console.warn('clearLinkage error')
  }
}
const reDrawView = () => {
  linkageActiveHistory.value = false
  myChart?.render()
}
const linkageActivePre = () => {
  if (linkageActiveHistory.value) {
    reDrawView()
  }
  nextTick(() => {
    linkageActive()
  })
}
const linkageActive = () => {
  linkageActiveHistory.value = true
  myChart?.setState('active', param => {
    if (Array.isArray(param)) {
      return false
    } else {
      if (checkSelected(param)) {
        return true
      }
    }
  })
  myChart?.setState('inactive', param => {
    if (Array.isArray(param)) {
      return false
    } else {
      if (!checkSelected(param)) {
        return true
      }
    }
  })
}
const checkSelected = param => {
  if (g2TypeSeries1.includes(view.value.type)) {
    return state.linkageActiveParam.name === param.field
  } else if (g2TypeSeries0.includes(view.value.type)) {
    return state.linkageActiveParam.category === param.category
  } else if (g2TypeTree.includes(view.value.type)) {
    if (
      param.path?.startsWith(state.linkageActiveParam.name) ||
      state.linkageActiveParam.name === t('commons.all')
    ) {
      return true
    }
    return state.linkageActiveParam.name === param.name
  } else {
    return (
      (state.linkageActiveParam.name === param.name ||
        (state.linkageActiveParam.name === 'NO_DATA' && !param.name)) &&
      state.linkageActiveParam.category === param.category
    )
  }
}

const calcData = async (view, callback) => {
  if (view.tableId || view['dataFrom'] === 'template') {
    isError.value = false
    const v = JSON.parse(JSON.stringify(view))
    getData(v)
      .then(async res => {
        if (res.code && res.code !== 0) {
          isError.value = true
          errMsg.value = res.msg
          callback?.()
        } else {
          chartData.value = res?.data as Partial<Chart['data']>
          emit('onDrillFilters', res?.drillFilters)
          if (!res?.drillFilters?.length) {
            dynamicAreaId.value = ''
            scope = null
          } else {
            const extra = view.chartExtRequest?.drill?.[res?.drillFilters?.length - 1].extra
            dynamicAreaId.value = extra?.adcode + ''
            scope = extra?.scope
            // 地图
            const map = parseJson(view.customAttr)?.map
            if (map) {
              let areaId = map.id
              country.value = areaId.slice(0, 3)
            }
            if (!dynamicAreaId.value?.startsWith(country.value)) {
              if (country.value === 'cus') {
                dynamicAreaId.value = '156' + dynamicAreaId.value
              } else {
                dynamicAreaId.value = country.value + dynamicAreaId.value
              }
            }
          }
          dvMainStore.setViewDataDetails(view.id, res)
          if (!res.drill && !res.chartExtRequest?.linkageFilters?.length) {
            dvMainStore.setViewOriginData(view.id, chartData.value)
            emitter.emit('chart-data-change')
          }
          await renderChart(res, callback)
        }
      })
      .catch(() => {
        callback?.()
      })
  } else {
    if (['bubble-map', 'map', 'flow-map', 'heat-map'].includes(view.type)) {
      await renderChart(view, callback)
    }
    callback?.()
  }
}
let curView
const renderChart = async (view, callback?) => {
  if (!view) {
    return
  }
  curView = view
  // view 为引用对象 需要存库 view.data 直接赋值会导致保存不必要的数据
  // 与默认图表对象合并，方便增加配置项
  const chart = deepCopy({
    ...defaultsDeep(view, cloneDeep(BASE_VIEW_CONFIG)),
    data: chartData.value,
    ...(props.fontFamily && props.fontFamily !== 'inherit' ? { fontFamily: props.fontFamily } : {})
  })
  const chartView = chartViewManager.getChartView(view.render, view.type)
  recursionTransObj(customAttrTrans, chart.customAttr, scale.value, terminal.value)
  recursionTransObj(customStyleTrans, chart.customStyle, scale.value, terminal.value)
  switch (chartView.library) {
    case ChartLibraryType.L7_PLOT:
      await renderL7Plot(chart, chartView as L7PlotChartView<any, any>, callback)
      break
    case ChartLibraryType.L7:
      await renderL7(chart, chartView as L7ChartView<any, any>, callback)
      break
    case ChartLibraryType.G2_PLOT:
      await renderG2Plot(chart, chartView as G2PlotChartView<any, any>)
      callback?.()
      break
    default:
      break
  }
}
let myChart = null
let g2Timer: number
const renderG2Plot = async (chart, chartView: G2PlotChartView<any, any>) => {
  g2Timer && clearTimeout(g2Timer)
  g2Timer = setTimeout(async () => {
    try {
      myChart?.destroy()
      myChart = await chartView.drawChart({
        chartObj: myChart,
        container: containerId,
        chart: chart,
        scale: 1,
        action,
        quadrantDefaultBaseline
      })
      myChart?.render()
      if (linkageActiveHistory.value) {
        linkageActive()
      }
    } catch (e) {
      console.error('renderG2Plot error', e)
    }
  }, 300)
}

const dynamicAreaId = ref('')
const country = ref('')
const appStore = useAppStoreWithOut()
const chartContainer = ref<HTMLElement>(null)
let scope
let mapTimer: number
const renderL7Plot = async (chart: ChartObj, chartView: L7PlotChartView<any, any>, callback) => {
  const map = parseJson(chart.customAttr).map
  let areaId = map.id
  country.value = areaId.slice(0, 3)
  if (dynamicAreaId.value) {
    // 世界下钻到国家，切换路径
    if (country.value === '000' && dynamicAreaId.value.startsWith('000')) {
      country.value = dynamicAreaId.value.slice(3)
      areaId = country.value
    } else {
      areaId = dynamicAreaId.value
    }
  }
  mapTimer && clearTimeout(mapTimer)
  mapTimer = setTimeout(async () => {
    myChart?.destroy()
    if (chartContainer.value) {
      chartContainer.value.textContent = ''
    }
    myChart = await chartView.drawChart({
      chartObj: myChart,
      container: containerId,
      chart,
      areaId,
      action,
      scope
    })
    callback?.()
    emit('resetLoading')
  }, 500)
}
// let satelliteLayer: any = null;

class SatelliteControl extends Control {
  protected onAdd() {
    // debugger
    const btn = document.createElement('button');
    btn.className = 'l7-control-button l7-satellite-control';
    btn.innerHTML = '卫星';
    // btn.title = '切换到卫星视图';
    btn.style.backgroundColor = '#000';
    btn.style.color = '#fff';
    btn.style.padding = '2px';
    btn.style.borderRadius = '4px';
    btn.style.cursor = 'pointer'
    btn.style.fontSize = '11px';
    let scene = myChart.getScene()
    console.log('scene', scene)
    // 创建高德卫星图层
    let satelliteLayer = new window.AMap.TileLayer.Satellite();
    let isSatelliteVisible = false;
    console.log('12345677', satelliteLayer);
    btn.onclick = () => {
      // console.log('12345677',isSatelliteVisible);
      isSatelliteVisible = !isSatelliteVisible;
      if (isSatelliteVisible) {
        // 使用 scene.addLayer 方法添加卫星图层
        btn.style.backgroundColor = '#409eff';
        scene.map.add(satelliteLayer)
      } else {
        // 使用 scene.removeLayer 方法移除卫星图层
        btn.style.backgroundColor = '#000';
        scene.map.remove(satelliteLayer)

      }
    };
    // // 确保地图加载完成
    // scene.on('loaded', () => {
    //   console.log('地图加载完成');

    // });

    return btn;
  }
}
let mapL7Timer: any
let scaleControl: Scale | null = null // 存储比例尺实例
let fullscreenControl
let satelliteControlInstance = null; // 用于存储卫星控件实例
const renderL7 = async (chart: ChartObj, chartView: L7ChartView<any, any>, callback) => {
  mapL7Timer && clearTimeout(mapL7Timer);
  mapL7Timer = setTimeout(async () => {
    myChart = await chartView.drawChart({
      chartObj: myChart,
      container: containerId,
      chart: chart,
      action
    });

    // 清除已有比例尺 
    if (!scaleControl) {
      scaleControl = new Scale({
        position: 'bottomleft',
        imperial: false
      });
      myChart.getScene()?.addControl(scaleControl);
    }
    // 添加全屏控件
    if (fullscreenControl) {

    } else {
      fullscreenControl = new Fullscreen({
        position: 'bottomright',
      });
      myChart.getScene()?.addControl(fullscreenControl, 'bottomright');
    }
    // ====== 使用高德地图原生API实现卫星图层切换 ======
    // 添加控件到地图
    // 移除之前的卫星控件（如果存在）
    if (!satelliteControlInstance) {
      // 添加新的卫星控件到地图
      satelliteControlInstance = new SatelliteControl({ position: 'bottomright' });
      myChart.getScene()?.addControl(satelliteControlInstance);
    }
    // ====== 修复完成 ======

    myChart?.render();
    callback?.();
    emit('resetLoading');
  }, 500);
};
const pointClickTrans = () => {
  if (embeddedCallBack.value === 'yes') {
    trackClick('pointClick')
  }
}

const actionDefault = param => {
  if (param.from === 'map') {
    emitter.emit('map-default-range', param)
  }
  if (param.from === 'word-cloud') {
    emitter.emit('word-cloud-default-data-range', param)
  }
  if (param.from === 'gauge') {
    emitter.emit('gauge-default-data', param)
  }
  if (param.from === 'liquid') {
    emitter.emit('liquid-default-data', param)
  }
}

const action = param => {
  if (param.from) {
    actionDefault(param)
    return
  }
  if (view.value.type === 'map') {
    if (!(param?.data?.data?.quotaList && param?.data?.data?.quotaList.length > 0)) {
      return
    }
  }
  state.pointParam = param.data
  // 点击
  pointClickTrans()
  // 下钻 联动 跳转
  state.linkageActiveParam = {
    category: state.pointParam.data.category ? state.pointParam.data.category : 'NO_DATA',
    name: state.pointParam.data.name ? state.pointParam.data.name : 'NO_DATA'
  }
  if (trackMenu.value.length < 2) {
    // 只有一个事件直接调用
    trackClick(trackMenu.value[0])
  } else {
    // 图表关联多个事件
    const barStyleTemp = {
      left: param.x - 50,
      top: param.y + 10
    }
    trackBarStyleCheck(props.element, barStyleTemp, props.scale, trackMenu.value.length)
    const trackBarX = barStyleTemp.left
    let trackBarY = 50
    state.trackBarStyle.left = barStyleTemp.left + 'px'
    if (curView.type === 'symbolic-map') {
      trackBarY = param.y + 10
      state.trackBarStyle.top = param.y + 10 + 'px'
    } else {
      trackBarY = barStyleTemp.top
      state.trackBarStyle.top = barStyleTemp.top + 'px'
    }
    if (dataVMobile) {
      state.trackBarStyle.left = trackBarX + 40 + 'px'
      state.trackBarStyle.top = trackBarY + 70 + 'px'
    } else {
      state.trackBarStyle.left = trackBarX + 'px'
      state.trackBarStyle.top = trackBarY + 'px'
    }

    viewTrack.value.trackButtonClick()
  }
}

const trackClick = trackAction => {
  const param = state.pointParam
  if (!param?.data?.dimensionList) {
    return
  }
  let checkName = state.pointParam.data.name
  // 对多维度的处理 取第一个
  if (state.pointParam.data.dimensionList.length > 1) {
    checkName = state.pointParam.data.dimensionList[0].id
  }
  // 跳转字段处理
  let jumpName = state.pointParam.data.name
  if (state.pointParam.data.dimensionList.length > 1) {
    const fieldIds = []
    // 优先下钻字段
    if (curView.drill) {
      const curFiled = curView.drillFields[curView.drillFilters.length]
      fieldIds.push(curFiled.id)
    }
    if (curView.type.includes('chart-mix')) {
      chartData.value?.left?.fields?.forEach(field => {
        if (!fieldIds.includes(field.id)) {
          fieldIds.push(field.id)
        }
      })
      chartData.value?.right?.fields?.forEach(field => {
        if (!fieldIds.includes(field.id)) {
          fieldIds.push(field.id)
        }
      })
    } else {
      chartData.value?.fields?.forEach(field => {
        if (!fieldIds.includes(field.id)) {
          fieldIds.push(field.id)
        }
      })
    }
    for (let i = 0; i < fieldIds.length; i++) {
      const id = fieldIds[i]
      const sourceInfo = view.value.id + '#' + id
      if (nowPanelJumpInfo.value[sourceInfo]) {
        jumpName = id
        break
      }
    }
  }
  let quotaList = state.pointParam.data.quotaList
  if (['bar-range'].includes(curView.type)) {
    quotaList = state.pointParam.data.dimensionList
  } else {
    quotaList[0]['value'] = state.pointParam.data.value
  }
  const linkageParam = {
    option: 'linkage',
    name: checkName,
    viewId: view.value.id,
    dimensionList: state.pointParam.data.dimensionList,
    quotaList: quotaList
  }
  const jumpParam = {
    option: 'jump',
    name: jumpName,
    viewId: view.value.id,
    dimensionList: state.pointParam.data.dimensionList,
    quotaList: quotaList
  }

  const clickParams = {
    option: 'pointClick',
    name: checkName,
    viewId: view.value.id,
    dimensionList: state.pointParam.data.dimensionList,
    quotaList: quotaList
  }
  switch (trackAction) {
    case 'pointClick':
      emit('onPointClick', clickParams)
      break
    case 'linkageAndDrill':
      dvMainStore.addViewTrackFilter(linkageParam)
      emit('onChartClick', param)
      break
    case 'drill':
      emit('onChartClick', param)
      break
    case 'linkage':
      linkageActivePre()
      dvMainStore.addViewTrackFilter(linkageParam)
      break
    case 'jump':
      if (mobileInPc.value && !inMobile.value) return
      emit('onJumpClick', jumpParam)
      break
    default:
      break
  }
}

const trackMenu = computed(() => {
  let trackMenuInfo = []
  // 复用、放大状态的仪表板不进行联动、跳转和下钻的动作
  if (!['multiplexing', 'viewDialog'].includes(showPosition.value)) {
    let linkageCount = 0
    let jumpCount = 0
    if (curView?.type?.includes('chart-mix')) {
      chartData.value?.left?.fields?.forEach(item => {
        const sourceInfo = view.value.id + '#' + item.id
        if (nowPanelTrackInfo.value[sourceInfo]) {
          linkageCount++
        }
        if (nowPanelJumpInfo.value[sourceInfo]) {
          jumpCount++
        }
      })
      chartData.value?.right?.fields?.forEach(item => {
        const sourceInfo = view.value.id + '#' + item.id
        if (nowPanelTrackInfo.value[sourceInfo]) {
          linkageCount++
        }
        if (nowPanelJumpInfo.value[sourceInfo]) {
          jumpCount++
        }
      })
    } else {
      chartData.value?.fields?.forEach(item => {
        const sourceInfo = view.value.id + '#' + item.id
        if (nowPanelTrackInfo.value[sourceInfo]) {
          linkageCount++
        }
        if (nowPanelJumpInfo.value[sourceInfo]) {
          jumpCount++
        }
      })
    }
    jumpCount &&
      view.value?.jumpActive &&
      (!mobileInPc.value || inMobile.value) &&
      trackMenuInfo.push('jump')
    linkageCount && view.value?.linkageActive && trackMenuInfo.push('linkage')
    view.value.drillFields.length && trackMenuInfo.push('drill')
    // 如果同时配置jump linkage drill 切配置联动时同时下钻 在实际只显示两个 '跳转' '联动和下钻'
    if (trackMenuInfo.length === 3 && props.element.actionSelection.linkageActive === 'auto') {
      trackMenuInfo = ['jump', 'linkageAndDrill']
    } else if (
      trackMenuInfo.length === 2 &&
      props.element.actionSelection.linkageActive === 'auto' &&
      !trackMenuInfo.includes('jump')
    ) {
      trackMenuInfo = ['linkageAndDrill']
    }
  }
  return trackMenuInfo
})
const quadrantDefaultBaseline = defaultQuadrant => {
  emitter.emit('quadrant-default-baseline', defaultQuadrant)
}

const canvas2Picture = (pictureData, online) => {
  const mapDom = document.getElementById(containerId)
  const childNodeList = mapDom.querySelectorAll('.l7-scene')
  if (childNodeList?.length) {
    childNodeList.forEach(child => {
      child['style'].display = 'none'
    })
  }
  if (online) {
    const canvasContainerList = mapDom.querySelectorAll('.amap-maps')
    canvasContainerList?.forEach(canvasContainer => {
      canvasContainer['style'].display = 'none'
    })
  }
  const imgDom = document.createElement('img')
  imgDom.style.width = '100%'
  imgDom.style.height = '100%'
  imgDom.style.position = 'absolute'
  imgDom.style.objectFit = 'cover'
  imgDom.style['z-index'] = '2'
  imgDom.classList.add('prepare-picture-img')
  imgDom.src = pictureData
  mapDom.appendChild(imgDom)
}
const preparePicture = id => {
  if (id !== curView.id) {
    return
  }
  const chartView = chartViewManager.getChartView(curView.render, curView.type)
  if (chartView.library === ChartLibraryType.L7_PLOT) {
    myChart
      .getScene()
      .exportMap('png')
      .then(res => canvas2Picture(res, false))
  } else if (chartView.library === ChartLibraryType.L7) {
    const scene = myChart.getScene()
    const zoom = new ExportImage({
      onExport: (base64: string) => {
        canvas2Picture(base64, true)
      }
    })
    scene.addControl(zoom)
    zoom.hide()
    zoom.getImage().then(res => {
      canvas2Picture(res, true)
    })
  }
}
const unPreparePicture = id => {
  if (id !== curView.id) {
    return
  }
  const chartView = chartViewManager.getChartView(curView.render, curView.type)
  if (chartView.library === ChartLibraryType.L7_PLOT || chartView.library === ChartLibraryType.L7) {
    const mapDom = document.getElementById(containerId)
    const childNodeList = mapDom.querySelectorAll('.l7-scene')
    if (childNodeList?.length) {
      childNodeList.forEach(child => {
        child['style'].display = 'block'
      })
    }
    const imgDomList = mapDom.querySelectorAll('.prepare-picture-img')
    imgDomList?.forEach(child => {
      child.remove()
    })
    const canvasContainerList = mapDom.querySelectorAll('.amap-maps')
    canvasContainerList?.forEach(canvasContainer => {
      canvasContainer['style'].display = 'block'
    })
  }
}
defineExpose({
  calcData,
  renderChart,
  trackMenu,
  clearLinkage
})

//三维 three.js 实现方法
// 新增方法 - 初始化 Three.js
const initThree = (container: HTMLElement) => {
  // 创建场景
  threeScene = new THREE.Scene();

  // 创建相机
  threeCamera = new THREE.PerspectiveCamera(
    75,
    container.clientWidth / container.clientHeight,
    0.1,
    1000
  );
  threeCamera.position.z = 5;

  // 创建渲染器
  threeRenderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
  threeRenderer.setSize(container.clientWidth, container.clientHeight);
  // 设置关键样式
  threeRenderer.domElement.style.position = 'absolute';
  threeRenderer.domElement.style.top = '0';
  threeRenderer.domElement.style.left = '0';
  threeRenderer.domElement.style.zIndex = '1'; // 确保在地图之上
  container.appendChild(threeRenderer.domElement);


  // 添加光源
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
  threeScene.add(ambientLight);

  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  directionalLight.position.set(10, 10, 10);
  threeScene.add(directionalLight);
};
// 新增方法 - 加载模型
const loadModel = (filePath: string) => {
  const loader = new GLTFLoader();
  const dracoLoader = new DRACOLoader()
  dracoLoader.setDecoderPath('./static/js/')
  dracoLoader.setDecoderConfig({ type: 'js' })
  loader.setDRACOLoader(dracoLoader)

  // 确保地图场景存在
  if (!myChart?.getScene()) {
    console.warn('地图场景尚未初始化，延迟加载模型');
    // 延迟重试
    setTimeout(() => loadModel(filePath), 500);
    return;
  }

  const scene = myChart.getScene();

  // 检查场景是否已加载
  if (scene.loaded) {
    // 场景已加载，直接加载模型
    loadModelInternal(loader, filePath);
  } else {
    // 添加一次性事件监听器
    const loadedHandler = () => {
      scene.off('loaded', loadedHandler); // 移除监听器
      loadModelInternal(loader, filePath);
    };
    scene.on('loaded', loadedHandler);
  }
};

// 内部加载方法
const loadModelInternal = (loader, filePath) => {
  loader.load(
    filePath,
    (gltf) => {
      console.log('Model loaded successfully:', gltf);
      model = gltf.scene;
      threeScene?.add(model);
      // animate();
      placeModelByLngLat(116.3974, 39.9093); // 直接调用放置方法
    },
    (progress) => {
      console.log('Loading progress:', progress);
    },
    (error) => {
      console.error('模型加载失败:', error);
    }
  );
};
// 新增方法 - 根据经纬度放置模型
const placeModelByLngLat = (lng: number, lat: number) => {
  debugger
  if (!model || !myChart?.getScene()) {
    console.warn('模型或地图场景未初始化');
    return;
  }

  const scene = myChart.getScene();
  console.log('地图场景状态:', scene);

  try {
    const containerPoint = scene.lngLatToContainer([lng, lat]);
    console.log('容器坐标:', containerPoint);

    const container = document.getElementById(containerId);
    if (!container) {
      console.error('容器元素未找到');
      return;
    }

    // 转换为Three.js的标准化设备坐标
    const x = (containerPoint.x / container.clientWidth) * 2 - 1;
    const y = -(containerPoint.y / container.clientHeight) * 2 + 1;

    console.log('Three.js坐标:', { x, y });

    // 更新模型位置
    model.position.set(x * 5, y * 5, 0);

    // 确保相机看向模型
    if (threeCamera) {
      threeCamera.lookAt(model.position);
      console.log('相机已调整朝向模型');
    }
  } catch (e) {
    console.error('坐标转换错误:', e);
  }
};
// 动画循环
const animate = () => {
  requestAnimationFrame(animate);
  if (threeRenderer && threeScene && threeCamera) {
    threeRenderer.render(threeScene, threeCamera);
  }
};
let resizeObserver
const TOLERANCE = 0.01
const RESIZE_MONITOR_CHARTS = ['map', 'bubble-map', 'flow-map', 'heat-map']
onMounted(() => {
  const containerDom = document.getElementById(containerId)
  const { offsetWidth, offsetHeight } = containerDom
  const preSize = [offsetWidth, offsetHeight]
  resizeObserver = new ResizeObserver(([entry] = []) => {
    if (!RESIZE_MONITOR_CHARTS.includes(view.value.type)) {
      return
    }
    const [size] = entry.borderBoxSize || []
    const widthOffsetPercent = (size.inlineSize - preSize[0]) / preSize[0]
    const heightOffsetPercent = (size.blockSize - preSize[1]) / preSize[1]
    if (Math.abs(widthOffsetPercent) < TOLERANCE && Math.abs(heightOffsetPercent) < TOLERANCE) {
      return
    }
    if (myChart && preSize[1] > 1) {
      renderChart(curView)
    }
    preSize[0] = size.inlineSize
    preSize[1] = size.blockSize
  })
  resizeObserver.observe(containerDom)
  useEmitt({ name: 'l7-prepare-picture', callback: preparePicture })
  useEmitt({ name: 'l7-unprepare-picture', callback: unPreparePicture })
  // 初始化 Three.js
  // const container = document.getElementById(containerId);
  // if (container) {
  //   initThree(container);
  //   // 加载模型（替换为实际路径）
  //   // loadModel(`./static/3DModel/Camera1.glb`); 
  //   // loadModel('static/3DModel/scene.glb');

  // }
})
onBeforeUnmount(() => {
  try {
    myChart?.destroy()
    resizeObserver?.disconnect()
  } catch (e) {
    console.warn(e)
  }
  if (threeRenderer) {
    threeRenderer.dispose();
  }
})
</script>

<template>
  <div class="canvas-area">
    <view-track-bar ref="viewTrack" :track-menu="trackMenu" :font-family="fontFamily" :is-data-v-mobile="dataVMobile"
      class="track-bar" :style="state.trackBarStyle" @trackClick="trackClick" />
    <div v-if="!isError" ref="chartContainer" class="canvas-content" :id="containerId"></div>
    <chart-error v-else :err-msg="errMsg" />
  </div>
</template>

<style lang="less" scoped>
.canvas-area {
  position: relative;
  width: 100%;
  height: 100%;
  z-index: 0;

  .canvas-content {
    width: 100% !important;
    height: 100% !important;

    :deep(.g2-tooltip) {
      position: fixed !important;
    }
  }
}

:deep(.l7-button-control) {
  background-color: #000000 !important;
}

:deep(.l7-button-control:not(:disabled):hover) {
  background-color: #000000d5 !important;
}

:deep(.l7-button-control .l7-iconfont) {
  fill: #fff !important;
  color: #fff !important;
}
:deep(.l7-control-zoom){
  position:fixed !important;
  right: 0px;
  bottom: 65px;
}
:deep(.l7-control-button){
  position:fixed !important;
  right: 0px;
  bottom: 35px;
}
// :deep(.l7-button-control){
//   position:fixed;
//   right: 0px;
//   bottom: 0px;
// }

// :deep(.l7-control-container .l7-top) {
//   top: auto !important;
//   bottom: 133px !important;

// }</style>
