import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js'
import { DIRECTIONS } from '@/config/dict'
import { amtMount } from './models/center'
import { createApp } from 'vue'

// 加载器
export const modelLoader = (url) => {

  const dracoloader = new DRACOLoader()
  dracoloader.setDecoderPath('/draco/')

  const loader = new GLTFLoader()
  loader.setDRACOLoader(dracoloader)

  return new Promise(resolve => {
    loader.load(url, e => {
      resolve(e)
    }, undefined, err => {
      resolve(false)
    })
  })

}

export const carFormate = (xcar) => {

  const {
    carId, carMilestone, carPlate, inTunnelTime, tunnelId, retainedMinutesTime,
    isFocusMark, roadNo, speed, vehicleType, isDangerous, originDistance
  } = xcar

  const direct = DIRECTIONS.find(item => item.key === tunnelId)?.value

  return {
    id: carId,
    plate: carPlate,
    time: inTunnelTime,
    milestone: carMilestone,
    lanex: roadNo,
    speed,
    type: vehicleType,
    focused: isFocusMark,
    danger: isDangerous,
    tunnelx: tunnelId,
    direct,
    distance: originDistance,
    remain: retainedMinutesTime
  }

}

export const cameraFormate = (xcamera) => {

  const {
    id, cameraIndexCode, pileNumber, progress, section
  } = xcamera

  return {
    id, 
    progress,
    pileNumber,
    section,
    cameraIndexCode
  }

}

export const eventFormate = (xevent) => {

  const {
    id,
    carInfoList,
    milestone,
    eventRoadNo,
    tunnelId,
    eventType,
    eventSituation,
    retainedTime,
    eventSource
  } = xevent

  return {
    id, 
    cars: carInfoList.map(({ carId, carPlate, vehicleType }) => {
      return { id: carId, plate: carPlate, type: vehicleType  }
    }),
    infotext: eventSituation,
    direct: tunnelId === 'xl_tunnel_up' ? 0 : 1,
    location: +milestone,
    lanex: +eventRoadNo,
    trafficType: carInfoList.length,
    eventType: eventType,
    remain: retainedTime,
    source: eventSource
  }

}

export const newCamera = (...args) => {

  const camera = new THREE.PerspectiveCamera(...args)
  camera.setLook = (x, y, z) => {
    camera.look = { x, y, z }
    camera.lookAt(x, y, z)
  }

  return camera

}

export const modelPlay = (xmodel) => {

  const mixer = new THREE.AnimationMixer(xmodel)
  xmodel.animations.forEach(clip => {
    const action = mixer.clipAction(clip)
    action.play()
  })

  const key = amtMount(delay => {
    mixer.update(delay)
  })

  return key

}

// 判断点是否在曲线上

export const getClosetPoint = (line, dline, point) => {

  let min = null
  let closest = null
  let direct = null
  let progress = null
  const maxPec = 1000

  for (let i = 0; i < maxPec; i++) {

    const xpt = line.getPointAt(i / maxPec)

    const vpt = (new THREE.Vector3()).copy(xpt)
    vpt.y += 60

    const distance = vpt.distanceTo(point)

    if (min === null || distance < min) {
      min = distance
      closest = xpt
      direct = dline.getPointAt(i / maxPec)
      progress = i / maxPec
    }

  }

  return { min, point: closest, direct, progress }
 
}

// 构建二维模型
export const create2DModel = (str, innerCall) => {

  const label = document.querySelector(str)
  innerCall && innerCall(label)
  const cloneEl = label.cloneNode(true)
  cloneEl.style.pointerEvents = 'auto'
  return new CSS2DObject(cloneEl)

}

// 构建二维模型
export const build2DModel = (e: {
  vm: any, // vue 组件对象
  key: string, // 模型 id 前缀
  id: string, // 模型 id
  contentStr: string // 容器层
}) => {
  
  const xvm = createApp(e.vm)
  const xdiv = document.createElement('div')
  const idstr = e.key + e.id.slice(-6)
  xdiv.setAttribute('id', idstr)

  const space = document.querySelector('.doms-2d ' + e.contentStr)
  space.appendChild(xdiv)
  const instance = xvm.mount('#' + idstr)
  const model = new CSS2DObject(xdiv)

  return {
    instance, model
  }

}