import * as THREE from 'three'
import FlowModel from './flow'
import CarModel from './car'

import { bus } from '@/views/3DModel/state'
import TrafficModel from './traffic'
import EventModel from './event'

import { amtMount } from './center'

import LFT_1 from '../lines/LFT_1'
import LFT_2 from '../lines/LFT_2'
import LFT_3 from '../lines/LFT_3'
import RGT_1 from '../lines/RGT_1'
import RGT_2 from '../lines/RGT_2'
import RGT_3 from '../lines/RGT_3'

import { cars } from '@/views/3DModel/_state'

export default class Tunnel {

  context = null // 环境
  models = null // 模型库

  direct = null // 方向
  miles = 0 // 隧道长
  start = 0 // 起点桩号
  end = 0 // 终点桩号
  
  cars = [] // 路面车流
  events = [] // 路面事件
  points = [] // 隧道点阵
  curves = [] // 轨迹引导线
  roamCurve = null

  flow = null // 车流模型
  traffic = null // 事件流模型

  constructor(context, models, configs: { [propName: string]: any }) {

    const avls = ['direct', 'miles', 'points', 'start', 'end']

    this.context = context
    this.models = models

    avls.forEach(key => {
      if (configs[key] || configs[key] === 0) {
        this[key] = configs[key]
      }
    })

    const tennelConfigs = {
      start: this.start,
      end: this.end,
      miles: this.miles
    }

    // 车流初始化
    this.flow = new FlowModel({
      mode: 'online',
      direct: this.direct,
      tunnel: tennelConfigs
    })

    // 事件流初始化
    this.traffic = new TrafficModel({
      direct: this.direct,
      tunnel: tennelConfigs
    })

    if (this.direct === 0) {
      this.curves = [
        this.createCurve(this.context.scene, LFT_1),
        this.createCurve(this.context.scene, LFT_3)
      ]
      this.roamCurve = this.createCurve(this.context.scene, LFT_2.reverse())
    } else {
      this.curves = [
        this.createCurve(this.context.scene, RGT_1),
        this.createCurve(this.context.scene, RGT_3)
      ]
      this.roamCurve = this.createCurve(this.context.scene, RGT_2)
    }

    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'visible') {
        this.cars.forEach(item => {
          item.car.remove(item.car_plate)
          context.scene.remove(item.car)
        })
        this.cars = []
      }
    })

  }

  createCurve (scene, points) {

    const curve = new THREE.CatmullRomCurve3(points.map(item => {
      const { x, y, z } = item
      return new THREE.Vector3(x, y, z)
    }))


    curve.curveType = 'chordal'
    const geoPoints = curve.getPoints(5000)
    const line = new THREE.Line(
      new THREE.BufferGeometry().setFromPoints(geoPoints),
      // new THREE.LineBasicMaterial({ color: 0x00ff00, opacity: 1, transparent: false })
      new THREE.LineBasicMaterial({ color: 0x00ff00, opacity: 0, transparent: true })
    )
    
    scene.add(line)

    return curve


  }

  // 开启车流
  startFlows () {

    // 车流更新
    this.flow.start(() => {

      this.flowUpdate()

      cars.value.splice(this.direct, 1, this.cars.map(item => {
        return {
          ...item.infos,
          over_miles: item.over_miles,
          distance: item.distance,
          stopFollow: (...args) => {
            item.stopFollow(...args)
          }
        }
      }))

    })

    // this.flow.mook(() => {
    //   this.flowUpdate()
    // })

    // 场景更新
    amtMount((delay) => {
      this.cars.forEach(xcar => {
        if (!xcar.over_miles) {
          xcar.run(delay)
        }
      })
    })

  }

  stopFlows () {
    this.flow.close()
  }

  // 开启事件流
  startEventFlows () {

    this.traffic.start(() => {
      this.trafficUpdate()
      bus.emit('event-update')
    })
    
  }

  // 关闭事件流
  stopEventFlows () {
    this.traffic.close()
  }

  // 数据帧更新
  flowUpdate () {

    const flowCars = this.flow.exportCars()

    // 公继变量集
    const tunnelCtx = {
      // model: this.models.car,
      models: this.models,
      scene: this.context.scene,
      direct: this.direct,
      curves: this.curves,
      miles: this.miles,
      start: this.start,
      end: this.end
    }

    const newMap = Object.fromEntries(flowCars.map(item => {
      return [item.id, true]
    }))

    const oldMap = Object.fromEntries(this.cars.map(item => {
      return [item.infos.id, true]
    }))

    // 新增
    const newCars = flowCars.filter(item => !oldMap[item.id])
    const oldCars = flowCars.filter(item => oldMap[item.id]) // this.cars.filter(item => newMap[item.infos.id]).map(item => item.infos.id)

    newCars.forEach(xcar => {
      this.cars.push(new CarModel(this.context, {
        ...tunnelCtx,
        infos: { ...xcar, direct: this.direct }
      }))
    })

    this.cars.forEach(item => {

      if (item.over_miles) {
        item.camera ? item.stopFollow() : this.context.scene.remove(item.car)
      } else if (oldCars.some(item1 => item1.id === item.infos.id)) {
        const xCar = oldCars.find(item2 => item2.id === item.infos.id)
        item.update(xCar)
      }

    })
    
  }

  // 事件更新
  trafficUpdate () {

    const events = this.traffic.exportEvents()

    // 公继变量集
    const tunnelCtx = {
      // model: this.models.car,
      models: this.models,
      scene: this.context.scene,
      direct: this.direct,
      curves: this.curves,
      miles: this.miles,
      start: this.start,
      end: this.end
    }

    const oldMap = Object.fromEntries(this.events.map(item => {
      return [item.infos.id, item]
    }))

    const newMap = Object.fromEntries(events.map(item => {
      return [item.id, item]
    }))

    // 新增
    const newEvents = events.filter(item => !oldMap[item.id])

    // 完结
    const completes = this.events.filter(item => !newMap[item.infos.id])
    completes.forEach(item => item.clean())

    this.events = this.events.filter(item => newMap[item.infos.id])

    newEvents.forEach(item => {
      this.events.push(new EventModel(tunnelCtx, item))
    })

  }

}
