// 组件
import CameraPlayer from '../../Doms2d/CameraPlayer.vue'
import VideoPopup from '@/components/Video/install'
import EventPop from '../../Doms2d/EventPop.vue'

// 模块
import * as TWEEN from '@tweenjs/tween.js'
import * as THREE from 'three'

// 工具函数
import { createApp } from 'vue'
import { setControls, getDistance, getClosetPoint } from './helper'
import { amtMount, amtRemove } from '../models/center'
import { sceneCheck, bus, cameraCtrls, carTracked, tracked, locate } from '@/views/3DModel/_state'
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js'

// 静态资源
import { POINT_START, POINT_END, POINT_SCANE } from '../points'

let env = {}

// 视角设置
const viewReset = (key) => {

  if (!sceneCheck('locate')) {
    return
  }

  const context = env.getContext()

  setControls('delete', env)

  const { pos, direct } = [POINT_SCANE, POINT_END, POINT_START][key]

  context.camera.position.copy(pos)
  context.camera.setLook(direct.x, direct.y, direct.z)
  context.scene.add(context.camera)

  setControls('add', env, new THREE.Vector3(direct.x, direct.y, direct.z))

}

// 铭牌类型切换
const plateChange = (type) => {

  const cars = env.getTunnles().map(item => item.cars).flat()
  cars.forEach(xCar => {
    xCar.vm_instance.typeChange(type)
  })

}

// 道路摄像机初始化
const cameraInit = () => {

  const context = env.getContext()
  const cameras = env.getCameras()

  cameras.forEach(item => {

    const ins = createApp(CameraPlayer)
    const domContainer = document.querySelector('.doms-2d')
    ins.use(VideoPopup)

    // 实例挂载
    const divContent = document.createElement('div')
    divContent.setAttribute('id', `camera-${item.infos.id.slice(-6)}`)
    domContainer.appendChild(divContent)
    item.vm_instance = ins.mount(divContent)
    
    // 2d 模型构建
    item.player2d = new CSS2DObject(divContent)
    item.camera.add(item.player2d)
    // item.player2d.position.x -= 100

    const playFrame = item.player2d.element.querySelector('.frame')
    playFrame.setAttribute('id', item.infos.id)
    item.vm_instance.cameraInit(item)

    // 事件模拟
    const playTrigger = item.player2d.element.querySelector('.no-play')
    const fullScreenTrigger = item.player2d.element.querySelector('.full-screen')

    playTrigger.addEventListener('pointerdown', () => {
      playTrigger.click()
    })

    fullScreenTrigger.addEventListener('pointerdown', () => {
      fullScreenTrigger.click()
    })

   
  })

  // 视角远近控制
  cameraCtrls.orgDistance = getDistance(env)
  context.controls.addEventListener('change', () => {

    cameraCtrls.scale = (cameraCtrls.orgDistance / getDistance(env)).toFixed(2)
    const mode = cameraCtrls.scale >= 9 ? 'view' : 'icon'
    cameras.forEach(item => {
      item.vm_instance.modeChange(mode)
    })
    
  })
  
}

// 添加事件虚拟节点
const addEventPoint = (item) => {

  const ins = createApp(EventPop)
  const domContainer = document.querySelector('.event-doms')

  // 实例挂载
  const divContent = document.createElement('div')
  divContent.setAttribute('id', `event-${item.infos.id.slice(-6)}`)
  domContainer.appendChild(divContent)
  item.vm_instance = ins.mount(divContent)

  // 2d 模型构建
  item.sign2d = new CSS2DObject(divContent)
  item.event.add(item.sign2d)
  item.vm_instance.eventInit(item.infos)

  const popTrigger = item.sign2d.element.querySelector('.event-tip')
  popTrigger.addEventListener('pointerdown', e => {
    popTrigger.click()
  })

}

// 事件挂载
const eventRender = () => {

  const events = env.getTunnles().map(item => item.events).flat()

  events.forEach(item => {
    if (!item.vm_instance) {
      addEventPoint(item)
    }
  })

}

// 车辆追踪
const carTracking = (xCar) => {
  if (!sceneCheck('track')) {
    return
  }

  const cars = env.getCars()
  const context = env.getContext()

  if (carTracked.value) {
    carTracked.value.stopFollow('change')
  }

  const newCar = cars.find(item => item.infos.id === xCar.id)

  if (newCar && !newCar.over_miles) {
    setControls('delete', env)
    newCar.follow(context.camera)
    tracked.value = xCar.id

  } else {
    context.camera.position.set(-25, 15, 0)
    context.camera.setLook(50, 10, 0)
    ElMessage.warning('车辆已驶离隧道！')
  }
}

// 相机飞行
const cameraTravel = ( { start, target, call, duration, amt } = { duration: 2000, amt: 'InOut' }) => {

  let resolve = null
  const runningPms = new Promise(e => resolve = e)

  const tween = new TWEEN.Tween(start)
    .easing(TWEEN.Easing.generatePow(2).InOut)
    .to(target, duration)
  
  tween.onUpdate(e => {
    call(e)
  })

  const key = amtMount(() => {
    tween.update()
  })

  tween.onComplete(() => {
    amtRemove(key)
    resolve()
  })

  tween.start()
  
  return runningPms

}

// 事件定位
const eventLocate = async (evt, orgDirect) => {

  if (!sceneCheck('locate')) {
    return
  }

  const context = env.getContext()
  const tunnnels = env.getTunnles()

  const direct = evt.tunnelId === 'xl_tunnel_down' ? 1 : 0
  const tunnel = tunnnels[direct]

  const orgPos = context.camera.position
  // const orgDirect = context.controls.target

  const progress = (direct ? (evt.milestone - tunnel.start) : (tunnel.end - evt.milestone)) / tunnel.miles

  if (!progress || progress > 1 || progress < 0) {
    return ElMessage.warning('数据错误！')
  }

  const tagPos = tunnel.roamCurve.getPointAt(progress)

  // 阶段1 视角进入入轨点
  const start = getClosetPoint(tunnel.roamCurve, tunnel.curves[1], orgPos)

  // console.log('min: ', start.min)

  if (start.min > 1.5) { // 非命中状态
    await cameraTravel({
      start: {
        point:  { ...orgPos },
        direct: { ...orgDirect }
      },
      target: {
        point:  { ...start.point, y: start.point.y + 60 },
        direct: { ...start.direct }
      },
      duration: 2000,
      call ({ point, direct, rate }) {
        context.camera.position.copy(new THREE.Vector3(point.x, point.y, point.z))
        context.camera.setLook(direct.x, direct.y, direct.z)
      },
      amt: 'In'
    })
  }

  // 阶段2 巡航

  const dps = Math.abs(progress - start.progress) // 位距百分比

  // 过滤重复点击
  if (dps > 0.001) {
    await cameraTravel({
      start: { rate: start.progress, x: 0 },
      target: { rate: progress, x: 1 },
      duration: 1000 * (dps / 0.1),
      call ({ rate, x }) {

        const xpoint = tunnel.roamCurve.getPointAt(rate)
        const xdirect = tunnel.curves[1].getPointAt(rate)
  
        context.camera.position.copy(new THREE.Vector3(xpoint.x, xpoint.y + 60, xpoint.z))
        context.camera.setLook(xdirect.x, xdirect.y, xdirect.z)
  
      },
      amt: 'Out'
    })
  }
  

}

// 事件定位 — 简
const strictLocate = (evt) => {

  const context = env.getContext()
  const tunnnels = env.getTunnles()

  const dy = 60
  const dz = 10

  const direct = evt.tunnelId === 'xl_tunnel_down' ? 1 : 0
  const tunnel = tunnnels[direct]

  const orgPos = context.camera.position
  const orgDirect = context.controls.target

  const progress = (direct ? (evt.milestone - tunnel.start) : (tunnel.end - evt.milestone)) / tunnel.miles


  if (!progress || progress > 1 || progress < 0) {
    return ElMessage.warning('数据错误！')
  }

  const xpoint = tunnel.roamCurve.getPointAt(progress)
  const xdirect = tunnel.curves[1].getPointAt(progress)

  context.camera.position.copy(new THREE.Vector3(xpoint.x, xpoint.y + dy, xpoint.z + dz))
  context.camera.setLook(xdirect.x, xdirect.y, xdirect.z + dz)

  const target = new THREE.Vector3(xdirect.x, xdirect.y, xdirect.z + dz)

  if (context.controls) {
    context.controls.target = target
  } else {
    setControls('add', env, target) 
  }

  eventSelect(evt, true)
  
}

// 特殊选中处理
const eventSelect = (evt, show) => {

  const tunnnels = env.getTunnles()
  const direct = evt.tunnelId === 'xl_tunnel_down' ? 1 : 0
  const tunnel = tunnnels[direct]
  const evtMatch = tunnel.events.find(item => item.infos.id === evt.id)

  if (evtMatch) {
    evtMatch.vm_instance.setSelect(show)
  } else {

  }

  if (!show) {
    viewReset(1)
  }
  
}

// 车辆类型筛选
const typeSelect = (e) => {

  const tunnelx = env.getTunnles()[e.direct]
  tunnelx.cars.forEach(item => {
    item.vm_instance.focusChange(e.type)
  })

}

// 初始化
const useController = (provides) => {

  env = { ...provides }

  cameraInit()

  // 模式切换
  bus.on('view-reset', direct => {
    viewReset(direct)
  })

  // 车辆标签类型切换
  bus.on('plate-change', type => {
    plateChange(type)
  })

  // 实时事件
  bus.on('event-update', () => {
    eventRender()
  })

  // 车辆追踪
  bus.on('3d-track', xCar => {
    carTracking(xCar)
  })

  // 事件定位
  bus.on('event-locate', async xEvent => {
    strictLocate(xEvent)
  })

  // 取消事件标注
  bus.on('event-unselect', evt => {
    eventSelect(evt, false)
  })

  // 车辆类型筛选
  bus.on('focus-change', e => {
    typeSelect(e)
  })

}

export {

  useController

}