import * as turf from '@turf/turf';
import DataUtils from '../utils/DataUtils';
import GeogUtils from '../utils/GeogUtils';
import VerifyUtils from '../utils/VerifyUtils';
import MapProvider from '../geog/MapProvider';
import GeoJsonProvider from '../geog/GeoJsonProvider';
import SimpleMarkerLayer from './SimpleMarkerLayer';
import SimpleLineLayer from './SimpleLineLayer';
import mapboxgl from "@cgcs2000/mapbox-gl";
import Tooltip from "@src/map/components/map25d/tooltip/index"; //@csk 实际项目中具体开发

/**
 * 轨迹追踪图层
 * @alias TrackingLayer
 *
 * @summary <用于轨迹图层加载>
 */
export default class TrackingLayer {
  /**
   * 构造函数
   * @param {Object} options -图层选项
   */
  constructor(options) {
    /**
     * 地图对象
     * @type {Object}
     */
    this._map = options.map;

    /**
     * 地图组件
     * @type {Object}
     */
    this._mapRef = options.mapRef;

    /**
     * 最小缩放层级
     * @type {Number}
     */
    this._minzoom = DataUtils.default(options.minzoom, 10);

    /**
     * 追踪图标ID
     * @type {String}
     */
    this._icon = DataUtils.default(options.icon, 'busi_animate');

    /**
     * 帧率
     * @type {Number}
     */
    this._frameRate = DataUtils.default(options.frameRate, 24);
    this._defaultFrameRate = this._frameRate;

    /**
     * 提示框属性
     * @type {Object}
     */
    this._tooltip = DataUtils.default(options.tooltip, undefined);

    this._timer = null; // 定时器

    this._lineWidth = 4.5; // 线宽
    this._routeColor = '#4169E1'; // 路线颜色
    this._trailColor = '#2E8B57'; // 追踪颜色

    // 右箭头图标
    this._arrowIcon = 'busi_arrow';
    // 起终点图标
    this._startSpotIcon = 'busi_spotstart';
    this._endSpotIcon = 'busi_spotend';
    // 巡查点图标
    this._patrolDotIcon = 'busi_patrol';
    this._patroledDotIcon = 'busi_patrolgreen';
    this._patrolReportIcon = 'busi_patrolred';

    this._playing = false;
    this._counter = 0;
    this._steps = 0;
    this._aLength = 0;

    /** 要素集 **/
    this._fc = GeoJsonProvider.getEmptyFC(); // 路线数据
    this._realFeature = GeoJsonProvider.getEmptyFeature('LineString'); // 实际路线
    this._trailFC = GeoJsonProvider.getEmptyFC();   // 追踪数据
    this._animateFC = GeoJsonProvider.getEmptyFC(); // 动画点数据
    this._patrolFC = GeoJsonProvider.getEmptyFC(); // 巡查点数据

    /** 数据源/图层 **/
    this._sourceId = 'tracking_route'; // 路线数据源
    this._trailSourceId = this._sourceId + '-trail';
    this._trailGisSourceId = this._sourceId + '-trailgis';
    this._arrowSourceId = this._sourceId + '-arrow';
    this._animateSourceId = this._sourceId + '-animate';
    this._patrolSourceId = this._sourceId + '-point'; // 巡查点数据源ID
    this._trailTimeSourceId = this._sourceId + '-time'; // 轨迹时间点

    this._layerId = this._sourceId;
    this._trailLayerId = this._trailSourceId;
    this._trailGisLayerId = this._trailGisSourceId;
    this._arrowLayerId = this._arrowSourceId;
    this._animateLayerId = this._animateSourceId;
    this._patrolLayerId = this._patrolSourceId; // 巡查点图层ID
    this._trailTimeLayerId = this._trailTimeSourceId; // 轨迹时间点

    /** 图层对象 **/
    this._routeLayer = null;   // 路线图层
    this._trailLayer = null;   // 追踪图层
    this._trailGisLayer = null;   // 轨迹追踪图层
    this._arrowLayer = null;   // 箭头图层
    this._animateLayer = null; // 动画点图层
    this._patrolLayer = null; // 巡查点图层
    this._trailTimeLayer = null; // 巡查点图层

    this.popupList = [], // 通用提示框
    // 初始化图层
    this._initLayers();
  }

  /** 公有方法 **/
  /**
   * 设置图标
   * @param {String} id -图标ID
   */
  setIcon(id) {
    this._icon = id;
    // 更新图标
    if (this._animateLayer.hasLayer()) {
      this._animateLayer.setLayoutProperty('icon-image', this._icon)
    }
  }

  /**
   * 设置帧率
   * @param {Number} fr -帧率
   */
  setFrameRate(fr) {
    this._frameRate = fr;
    this._defaultFrameRate = fr;
  }

  /**
   * 设置数据
   * @param {Object} data -轨迹GeoJSON要素/要素集
   * @param {Object} patrolData -巡检点GeoJSON要素/要素集
   * @param {Boolean} jump -是否调至地图(无动画)
   */
  setData(data, patrolData = null, jump = false) {
    this._counter = 0;
    this._steps = 0;
    this._aLength = 0;

    this._patrolFC.features = [];
    if (patrolData) {
      // 初始化巡查点数据
      this._initPatrolData(patrolData);
    }

    // 初始化路线数据
    //this._initRouteData(data);
    this._setRouteData(data);
    this._setTrackData(data);
    this._setTrackTimeData(data);

    // 缩放至要素集
    const map = this._map;
    if (patrolData) {
      MapProvider.zoomToFeatures(map, this._patrolFC, 16, jump);
    } else {
      MapProvider.zoomToFeatures(map, this._fc, 16, jump);
    }
  }

  /**
   * 播放
   */
  play() {
    if (!this._playing) {
      this._playing = true;

      this._animate();
    }
  }

  /**
   * 倍速播放
   * @param {Number} multiple -倍数
   */
  playMultiply(multiple = 1) {
    this._frameRate = this._defaultFrameRate * multiple;
  }

  /**
   * 暂停
   */
  pause() {
    this._playing = false;
    this._animate();
  }

  /**
   * 停止
   */
  stop() {
    this._playing = false;
    this._counter = 0;

    this._animate();
  }

  /**
   * 移除图层
   */
  removeLayer() {
    // 动画点
    this._animateLayer.removeLayer();
    this._animateLayer.removeSource();
    // 箭头
    this._arrowLayer.removeLayer();
    this._arrowLayer.removeSource();

    // 轨迹线
    this._trailLayer.removeLayer();
    this._trailLayer.removeSource();

     // 轨迹线
     this._trailGisLayer.removeLayer();
     this._trailGisLayer.removeSource();
    // 路线
    this._routeLayer.removeLayer();
    this._routeLayer.removeSource();

    // 巡查点
    if (this._patrolLayer) {
      this._patrolLayer.removeLayer();
      this._patrolLayer.removeSource();
    }
    //轨迹时间点
    this._trailTimeLayer.removeLayer();
    this._trailTimeLayer.removeSource();

    this._fc.features = [];
    this._realFeature.geometry.coordinates = [];
    this._trailFC.features = [];
    this._animateFC.features = [];
    this._patrolFC.features = [];

    // 清空弹出框
    this._clearPopups();
  }

  /**
   * 显示/隐藏图层
   * @param {Boolean} show -是否显示
   */
  showLayer(show = true) {
    this._animateLayer.showLayer(show);
    this._arrowLayer.showLayer(show);
    this._trailLayer.showLayer(show);
    this._trailGisLayer.showLayer(show);
    this._routeLayer.showLayer(show);
    this._trailTimeLayer.showLayer(show);

    // 巡查点
    if (this._patrolLayer) {
      this._patrolLayer.showLayer(show);
    }
  }

  /** 私有方法 **/
  /**
   * 初始化图层
   */
  _initLayers() {
    const map = this._map;
    const minZoom = this._minzoom;

    // 初始化路线图层
    this._routeLayer = new SimpleLineLayer({
      map: map,
      minzoom: minZoom,
      metrics: true,
      color: this._routeColor,
      width: this._lineWidth,
      opacity: 0.95,
      fixed: true,
      sourceId: this._sourceId,
      layerId: this._layerId
    });

    // 初始化追踪图层
    this._trailLayer = new SimpleLineLayer({
      map: map,
      minzoom: minZoom,
      metrics: true,
      color: this._trailColor,
      width: this._lineWidth,
      opacity: 0.75,
      fixed: true,
      sourceId: this._trailSourceId,
      layerId: this._trailLayerId
    });

    // 初始化箭头点图层
    this._arrowLayer = new SimpleMarkerLayer({
      map: map,
      minzoom: minZoom,
      icon: this._arrowIcon,
      sourceId: this._arrowSourceId,
      layerId: this._arrowLayerId
    });
    // 设置自定义样式
    const spacingExpress = [
      'step',
      ['zoom'],
      30,
      minZoom + 4,
      75
    ];
    this._arrowLayer.setLayoutProperty('symbol-placement', 'line');
    this._arrowLayer.setLayoutProperty('symbol-spacing', spacingExpress);

    // 初始化动画点图层
    this._animateLayer = new SimpleMarkerLayer({
      map: map,
      minzoom: minZoom,
      icon: {
        type: 'categorical',
        property: 'type',
        stops: [
          ['start', this._startSpotIcon],
          ['end', this._endSpotIcon],
          ['ani', this._icon]
        ],
        default: this._icon
      },
      size: [
        'step', ['zoom'], 0.75,
        minZoom + 4, 1.0
      ],
      sourceId: this._animateSourceId,
      layerId: this._animateLayerId
    });

     // 初始化巡查轨迹（三分钟的轨迹）图层
     this._trailGisLayer = new SimpleLineLayer({
      map: map,
      minzoom: minZoom,
      metrics: true,
      color: '#FF4500',
      width: this._lineWidth,
      opacity: 0.75,
      fixed: true,
      sourceId: this._trailGisSourceId,
      layerId: this._trailGisLayerId
    });
    // 初始化巡查时间图层
    this._trailTimeLayer = new SimpleMarkerLayer({
      map: this._map,
      minzoom: minZoom,
      icon: this._patroledDotIcon,
      size: [
        'step', ['zoom'],
        0.5,
        minZoom + 4, 0.75,
        minZoom + 7, 1.0
      ],
      sourceId: this._trailTimeSourceId,
      layerId: this._trailTimeLayerId
    });
    //设置自定义样式
    this._animateLayer.setLayoutProperty('icon-rotation-alignment', 'viewport');
    this._animateLayer.setLayoutProperty('icon-rotate', ['get', 'bearing']);
  }

  /**
   * 初始化路线数据
   * @param {Object} data -GeoJSON要素/要素集
   */
  _initRouteData(data) {
    this._fc.features = [];
    this._realFeature.geometry.coordinates = [];
    this._trailFC.features = [];
    this._animateFC.features = [];

    let feature = null;
    if (VerifyUtils.isGeoJsonFC(data)) {
      feature = data.features[0];
    } else if (VerifyUtils.isGeoJsonFeature(data)) {
      feature = data;
    }
    if (!feature) return;

    let geomType = feature.geometry.type.toLowerCase();
    if (geomType !== 'linestring' && geomType !== 'multilinestring') return;

    if (geomType === 'multilinestring') {
      // 获取折线要素
      feature = GeoJsonProvider.getLineStringFeature(feature.geometry.coordinates[0], feature.properties);
    }
    this._fc.features = [ feature ];

    const coordinates = feature.geometry.coordinates;
    this._aLength = coordinates.length;

    // 重置路线
    let realFeature = this._resetRoute(feature);
    this._steps = realFeature.geometry.coordinates.length;
    this._realFeature = realFeature;

    // 追踪要素集
    this._trailFC.features = [ GeoJsonProvider.getEmptyFeature('LineString') ];

    // 路线起止点
    const startAniFea = GeoJsonProvider.getPointFeature(coordinates[0], {type: 'start'});
    const endAniFea = GeoJsonProvider.getPointFeature(coordinates[coordinates.length - 1], {type: 'end'});
    const aniFea = GeoJsonProvider.getEmptyFeature('Point');
    // 动画点要素集
    this._animateFC.features = [ startAniFea, endAniFea, aniFea ];

    // 更新数据
    this._routeLayer.setData(this._fc);
    this._arrowLayer.setData(this._fc);
    this._trailLayer.setData(this._trailFC);
    this._animateLayer.setData(this._animateFC);
  }

  /**
   * 设置路线数据
   * @param {Array} data -轨迹点数据
   */
  _setRouteData(data) {
    this._fc.features = [];
    this._realFeature.geometry.coordinates = [];
    this._trailFC.features = [];
    this._animateFC.features = [];

    if (VerifyUtils.isArray(data)) {
      const pointFC = GeoJsonProvider.data2PointFC(data);
      this._fc.features = pointFC.features;
    }
    if (!this._fc.features.length) return;

    // 轨迹点数组转折线
    const coordinates = data.map((point) => {
      return [point.lng || point.longitude, point.lat || point.latitude];
    });
    // 路线要素
    let routeFeature = GeoJsonProvider.getLineStringFeature(coordinates);

    let geomType = routeFeature.geometry.type.toLowerCase();
    if (geomType !== 'linestring' && geomType !== 'multilinestring') return;

    if (geomType === 'multilinestring') {
      // 获取折线要素
      routeFeature = GeoJsonProvider.getLineStringFeature(feature.geometry.coordinates[0], feature.properties);
    }

    // 实际路线
    this._steps = routeFeature.geometry.coordinates.length;
    this._realFeature = routeFeature;
    const fealFC = GeoJsonProvider.getEmptyFC();
    fealFC.features = [ routeFeature ];

    // 追踪要素集
    this._trailFC.features = [ GeoJsonProvider.getEmptyFeature('LineString') ];

    // 路线起止点
    const startAniFea = GeoJsonProvider.getPointFeature(coordinates[0], {type: 'start'});
    const endAniFea = GeoJsonProvider.getPointFeature(coordinates[coordinates.length - 1], {type: 'end'});
    const aniFea = GeoJsonProvider.getEmptyFeature('Point');
    // 动画点要素集
    this._animateFC.features = [ startAniFea, endAniFea, aniFea ];

    // 更新数据
    this._routeLayer.setData(fealFC);
    this._arrowLayer.setData(fealFC);
    this._trailLayer.setData(this._trailFC);
    this._animateLayer.setData(this._animateFC);
  }

  /**
   * 设置巡查轨迹-三分钟内
   * @param {Array} data -轨迹点数据
   */
  _setTrackData(data) {
    // 定义时间间隔，单位为毫秒
    var interval = 3 * 60 * 1000;

    // 定义结果数组
    var result = [];

    // 对数据进行排序，按照创建日期升序排序
    data.sort(function (a, b) {
      //return new Date(a.createDate) - new Date(b.createDate);
      return new Date(a.receivetime) - new Date(b.receivetime);
    });

    // 遍历数据对象
    for (var i = 0; i < data.length; i++) {
      var currentObj = data[i];
      //var currentDate = new Date(currentObj.createDate);
      var currentDate = new Date(currentObj.receivetime);

      // 查找当前对象在哪个数组中
      var found = false;
      for (var j = 0; j < result.length; j++) {
        var arr = result[j];
        var lastObj = arr[arr.length - 1];
        //var lastDate = new Date(lastObj.createDate);
        var lastDate = new Date(lastObj.receivetime);

        // 如果当前对象的时间与最后一个对象的时间间隔小于等于指定的时间间隔，则将当前对象放入该数组中
        if (currentDate - lastDate <= interval) {
          arr.push(currentObj);
          found = true;
          break;
        }
      }

      // 如果当前对象没有找到合适的数组，则创建一个新的数组，并将当前对象放入其中
      if (!found) {
        result.push([currentObj]);
      }
    }
    // 轨迹点数组转折线
    const transformedData = result.map((subArray) => {
      return subArray.map((point) => {
        return [point.lng || point.longitude, point.lat || point.latitude];
      });
    });
    // 获取折线要素
    let routeGisFeature = GeoJsonProvider.getMultiLineStringFeature(transformedData);

    const fealFC = GeoJsonProvider.getEmptyFC();
    fealFC.features = [routeGisFeature];
    this._trailGisLayer.setData(fealFC);
  }

  /**
   * 设置巡查轨迹-起点终点日期
   * @param {Array} data -轨迹点数据
   */
  _setTrackTimeData(data) {
    // 定义时间间隔，单位为毫秒
    var interval = 3 * 60 * 1000;

    // 定义结果数组
    var result = [];

    // 对数据进行排序，按照创建日期升序排序
    data.sort(function (a, b) {
      //return new Date(a.createDate) - new Date(b.createDate);
      return new Date(a.receivetime) - new Date(b.receivetime);
    });

    // 遍历数据对象
    for (var i = 0; i < data.length; i++) {
      var currentObj = data[i];
      //var currentDate = new Date(currentObj.createDate);
      let currentDate = new Date(currentObj.receivetime);

      // 查找当前对象在哪个数组中
      var found = false;
      for (var j = 0; j < result.length; j++) {
        var arr = result[j];
        var lastObj = arr[arr.length - 1];
        //var lastDate = new Date(lastObj.createDate);
        let lastDate = new Date(lastObj.receivetime);

        // 如果当前对象的时间与最后一个对象的时间间隔小于等于指定的时间间隔，则将当前对象放入该数组中
        if (currentDate - lastDate <= interval) {
          arr.push(currentObj);
          found = true;
          break;
        }
      }

      // 如果当前对象没有找到合适的数组，则创建一个新的数组，并将当前对象放入其中
      if (!found) {
        result.push([currentObj]);
      }
    }

    const map = this._map;

    // 清空弹窗框
    this._clearPopups();

    let mdata = this.extractFirstAndLastObjects(result);
    mdata.forEach((item) => {
      //let text = item.createDate;
      let text = item.receivetime;
      if (text) {
        if (text.indexOf('T') > 0) {
          text = DataUtils.formatDt(text, 'yyyy-MM-dd hh:mm:ss');
        }
        const lonLat = [Number(item.lng || item.longitude), Number(item.lat || item.latitude)];

        // 创建提示框
        const tooltip = new mapboxgl.Popup({
          className: "tooltip-custom",
          closeButton: false,
          closeOnClick: true,
          maxWidth: "none",
        });
        // 创建工具提示框
        const popup = new Tooltip({
          map: map,
          tooltip: tooltip
        });
        popup.show(lonLat, {
          theme: 'light',
          text: text
        });

        // 添加到弹出框列表
        this.popupList.push(popup);
      }
    });

    this._trailTimeLayer.setData(mdata);
  }

  /**
   * 获取子数组，第一个和最后一个对象
   */
  extractFirstAndLastObjects(data) {
    var extracteds = [];

    for (var i = 0; i < data.length; i++) {
      var firstObject = data[i][0]; // 提取当前子数组的第一个对象的属性
      var lastObject = data[i][data[i].length - 1]; // 提取当前子数组的最后一个对象属性

      extracteds.push(firstObject, lastObject); // 将提取的属性添加到结果数组中
    }

    return extracteds;
  }

  /**
   * 初始化巡查点数据
   * @param {Object} data -GeoJSON要素/要素集
   */
  _initPatrolData(data) {
    this._patrolFC.features = data.features;

    if (!this._patrolLayer) {
      const minZoom = this._minzoom;

      // 初始化巡查点图层
      this._patrolLayer = new SimpleMarkerLayer({
        map: this._map,
        minzoom: minZoom,
        icon: {
          type: 'categorical',
          property: 'status',
          stops: [
            ['1', this._patroledDotIcon],
            ['2', this._patrolReportIcon]
          ],
          default: this._patrolDotIcon
        },
        size: [
          'step', ['zoom'],
          0.5,
          minZoom + 4, 0.75,
          minZoom + 7, 1.0
        ],
        sourceId: this._patrolSourceId,
        layerId: this._patrolLayerId
      });
    }

    this._patrolLayer.setData(this._patrolFC);
  }

  /**
   * 重置路线
   * @param {Object} routeFeature -路线要素
   */
  _resetRoute(routeFeature) {
    let coordinates = [];

    let routeDistance = turf.lineDistance(routeFeature);
    // 设置相机路线点数
    let nstep = parseInt(routeDistance * 250);

    var nDistance = routeDistance / nstep;
    for (let i = 0; i < this._aLength - 1; i++) {
      let from = turf.point(routeFeature.geometry.coordinates[i]);
      let to = turf.point(routeFeature.geometry.coordinates[i + 1]);

      let lDistance = turf.distance(from, to, {
        units: 'kilometers',
      });

      if (i === 0) {
        coordinates.push(routeFeature.geometry.coordinates[0]);
      }
      if (lDistance > nDistance) {
        // 延长线段
        let rings = this._lineMore(from, to, lDistance, nDistance);
        coordinates = coordinates.concat(rings);
      } else {
        coordinates.push(routeFeature.geometry.coordinates[i + 1]);
      }
    }

    return GeoJsonProvider.getLineStringFeature(coordinates);
  }

  /**
   * 延长线段
   * @param {Numner[]} from -起始坐标
   * @param {Numner[]} to -结束坐标
   * @param {Number} distance -距离
   * @param {Number} splitLength -分割长度
   */
  _lineMore(from, to, distance, splitLength) {
    var step = parseInt(distance / splitLength);
    var leftLength = distance - step * splitLength;

    var rings = [];
    var routeLine = turf.lineString([from.geometry.coordinates, to.geometry.coordinates]);

    for (let i = 1; i <= step; i++) {
      let nlength = i * splitLength;
      let pnt = turf.along(routeLine, nlength, {
        units: 'kilometers',
      });
      rings.push(pnt.geometry.coordinates);
    }

    if (leftLength > 0) {
      rings.push(to.geometry.coordinates);
    }

    return rings;
  }

  /**
   * 开始动画
   */
  _animate() {
    const that = this;

    /**
     * 帧播放
     */
    function _frame() {
      if (that._counter >= that._steps) {
        return;
      }

      let startPnt, endPnt;
      if (that._counter === 0) {
        that._trailFC.features[0].geometry.coordinates = [];

        startPnt = that._realFeature.geometry.coordinates[that._counter];
        endPnt = that._realFeature.geometry.coordinates[that._counter + 1];
      } else {
        startPnt = that._realFeature.geometry.coordinates[that._counter - 1];
        endPnt = that._realFeature.geometry.coordinates[that._counter];
      }
      const pntProp = that._fc.features[that._counter].properties;

      that._animateFC.features[2].properties.type = 'ani';
      that._animateFC.features[2].properties.bearing = turf.bearing(turf.point(startPnt), turf.point(endPnt)) - 90;
      that._animateFC.features[2].geometry.coordinates = that._realFeature.geometry.coordinates[that._counter];
      that._trailFC.features[0].geometry.coordinates.push(that._animateFC.features[2].geometry.coordinates);

      that._animateLayer.setData(that._animateFC);
      that._trailLayer.setData(that._trailFC);

      // 聚焦动画点
      //that._map.panTo(startPnt);
      that._hideTooltip();
      if (that._playing === true && that._counter >= 0) {
        that._showTooltip(startPnt, pntProp);
      }

      // 停止定时器
      if (that._timer) {
        clearTimeout(that._timer);
        that._timer = null;
      }
      if (that._playing) {
        that._timer = setTimeout(function () {
          _frame();
        }, 1000 / that._frameRate);
      }

      that._counter += 1;
    }

    _frame();
  }

  /**
   * 清空弹出框
   */
  _clearPopups() {
    if (this.popupList && this.popupList.length > 0) {
      this.popupList.forEach((popup) => {
        popup.hide();
      });

      this.popupList = [];
    }
  }

  /**
   * 显示提示框
   * @param {Number[]} lonLat -经纬度
   * @param {Object} prop -属性
   */
  _showTooltip(lonLat, prop) {
    if (this._tooltip && this._mapRef) {
      let key = Object.keys(this._tooltip)[0];
      let name = this._tooltip[key];

      let val = prop[name];
      if (key === '时间' && val && val.indexOf('T') > 0) {
        val = DataUtils.formatDt(val, 'yyyy-MM-dd hh:mm:ss');
      }

      // 显示提示框
      let text = !val
                 ? key + '缺失'
                 : key + ': ' + val;

      this._mapRef.showTooltip(lonLat, text);
    }
  }

  /**
   * 隐藏提示框
   */
  _hideTooltip() {
    if (this._mapRef) {
      this._mapRef.hideTooltip();
    }
  }
}
