/* 
TODO 修改完成
*/
import React from 'react';
import ReactDOM from 'react-dom';
import { map } from '../../mapContext';
import { popupOptions, clusterOptions } from '../../utils/config';
import { createDeviceIcon, MutipleDevice, SingleDevice } from '../../utils/overlayer';
import { cache } from '@zenview/micro-utils';
import ResourceLayer from '../ResourceLayer';
import { validLatLon } from '../../utils/geo';
import * as L from 'leaflet';
import { LMConfig } from '@zenview/micro-basic-library';

let nearByPointsCache = {};

@map
class ClusterLayer extends React.Component {
  constructor(props) {
    super(props);
    this.autoFix = false;
    this.types = null;
    this.status = null;
    this.cameraType = null;
    this.curPopupMarker = null;
    this.posType = null;
    this.currentSingleMaker = null;
    this.currentMutipleMaker = null;
    this.singPopupDom = document.createElement('div');
    this.mutiplePopupDom = document.createElement('div');
    this.singPopupDom.className = 'marker-popup-single-content';
    this.mutiplePopupDom.className = 'marker-popup-mutiple-content arrow-map-layout';
    this.state = {
      points: props.points || null,
      isDataChange: false,
      mutiplePoints: [],
      singlePoint: {},
    };
    let clusterFlag = cache.getCache('clusterFlag',  'session');
    const markerClusterGroupOptions = {...clusterOptions}
    if(clusterFlag){ //在最大zoom层级时是否展开点位
      markerClusterGroupOptions.disableClusteringAtZoom=LMConfig.LMapConfig.layerOptions.maxZoom
    }
    this.clusterMarkers = L.markerClusterGroup(markerClusterGroupOptions).addTo(this.props.map);
    this.featureGroup = L.featureGroup();
  }
  static getDerivedStateFromProps(props, state) {
    if (props.points && props.points !== state.points) {
      return { isDataChange: true, points: props.points };
    }
    return null;
  }
  componentDidMount() {
    this._initMapCluster();
    if (Array.isArray(this.state.points) && this.state.points.length > 0) {
      this._initMarker(this.state.points);
    }
  }
  componentDidUpdate() {
    if (this.state.isDataChange) {
      this.setState({ isDataChange: false });
      if (Array.isArray(this.state.points) && this.state.points.length > 0) {
        this._initMarker(this.state.points);
      } else {
        this.clusterMarkers.clearLayers();
        this.featureGroup.clearLayers();
      }
    }
  }
  componentWillUnmount() {
    //this.singPopupDom.remove();
    this.mutiplePopupDom.remove();
    this.clusterMarkers.clearLayers();
    this.featureGroup.clearLayers();
    this.featureGroup = null;
    this.clusterMarkers = null;
    this.singPopupDom = null;
    this.mutiplePopupDom = null;
    this.curPopupMarker = null;
  }
  _initMapCluster() {
    const { mapMethods, map, customMaxZoom } = this.props;
    this.clusterMarkers.on('clusterclick', (e) => {
      if (this.curPopupMarker === e.layer) return;
      let zoom = mapMethods.getZoom();
      // customMaxZoom 自定义maxzoom
      if (zoom === (customMaxZoom || LMConfig?.LMapConfig?.layerOptions?.maxZoom)) {
        const markers = e.layer.getAllChildMarkers();
        const points = markers.map((v) => v.__extData);
        this.setState({ mutiplePoints: points });
        const popup = L.popup({ ...popupOptions, autoClose: true, closeOnClick: true }).setContent(this.mutiplePopupDom);
        e.layer.unbindPopup();
        e.layer.bindPopup(popup).openPopup();
        this.curPopupMarker = e.layer;
      } else {
        e.layer.zoomToBounds({ padding: [20, 20] });
      }
    });
    map.on('click', () => {
      if (this.curPopupMarker) {
        this.curPopupMarker.closePopup();
        this.curPopupMarker = null;
      }
    });
  }

  _initMarker(points) {
    const { autoView = true } = this.props;
    this.featureGroup.clearLayers();
    this.clusterMarkers.clearLayers();
    const markers = [];
    const posType = this.posType;
    for (let i = 0, l = points.length; i < l; i++) {
      let point = points[i];
      // fix bug[8228]，兼容过滤无效坐标，add by zhangyu 2020.06.29
      if (!point.latitude || !point.longitude || !validLatLon(point.latitude, point.longitude)) {
        continue;
      }
      if (this.types && this.types.indexOf(point.deviceType) === -1) {
        continue;
      }
      if (this.status && this.status.indexOf(point.deviceStatus) === -1) {
        continue;
      }
      if (this.cameraType && this.cameraType.indexOf(point.cameraType) === -1) {
        continue;
      }

      if (Array.isArray(posType)) {
        let isCommnity = (Array.isArray(point.pathId) && point.pathId.includes(119101)) || (Array.isArray(point.placeTags) && point.placeTags.includes(119101));
        // 都没有选中时
        if (!posType.includes('other') && !posType.includes('community')) {
          if (posType.includes('communityOther')) {
            if (!((isCommnity && !point.villageLocationType) || (point.villageLocationType && posType.includes(point.villageLocationType)))) {
              continue;
            }
          } else {
            if (!point.villageLocationType || posType.indexOf(point.villageLocationType) === -1) {
              continue;
            }
          }
        }
        // 只选中小区时
        if (!posType.includes('other') && posType.includes('community')) {
          if (!isCommnity) {
            continue;
          }
        }
        // 选中其他时
        if (posType.includes('other') && !posType.includes('community')) {
          if (point.villageLocationType && posType.indexOf(point.villageLocationType) === -1) {
            continue;
          }
          if (!posType.includes('communityOther')) {
            if (!point.villageLocationType && isCommnity) {
              continue;
            }
          }
        }
      }

      let marker = this.createMarker(point);
      this.featureGroup.addLayer(marker);
      markers.push(marker);
    }
    this.clusterMarkers.addLayers(markers);
    this.props.createCallback && this.props.createCallback(this);
    if (autoView && !this.autoFix) {
      this.autoFix = true;
      this.mapReset();
    }
  }

  getAllClusterPoints() {
    return this.clusterMarkers.getLayers().map((v) => v.__extData);
  }

  bindCloseSingleMakerEvent = () => {
    if (this.currentSingleMaker) {
      this.currentSingleMaker.closePopup().unbindPopup();
    }
    this.singPopupDom.removeEventListener('mouseleave', this.bindCloseSingleMakerEvent, false);
  };

  bindCloseMutipleMakerEvent = () => {
    if (this.currentMutipleMaker) {
      this.currentMutipleMaker.closePopup().unbindPopup();
    }
    this.mutiplePopupDom.removeEventListener('mouseleave', this.bindCloseMutipleMakerEvent, false);
  };

  createMarker(point) {
    const { renderIconGroup, markerClick } = this.props;
    const marker = new L.Marker(L.latLng(point.latitude, point.longitude), {
      icon: createDeviceIcon(point),
    });
    marker.__extData = point;
    this.currentSingleMaker = marker;
    let popup;
    marker.on('mouseover', () => {
      const points = this.computedNearbyPoints(point);
      const options = { ...popupOptions, autoClose: true, closeOnClick: true };
      if (points.length > 1) {
        this.setState({ mutiplePoints: points });
        popup = L.popup(options).setContent(this.mutiplePopupDom);
        this.currentMutipleMaker = marker.bindPopup(popup).togglePopup();
        this.mutiplePopupDom.addEventListener('mouseleave', this.bindCloseMutipleMakerEvent, false);
      } else {
        this.setState({ singlePoint: point });
        options.offset = L.point(4, renderIconGroup ? 55 : -17);
        popup = L.popup({ ...options, className: `${options.className} map-sigle-device-popup` }).setContent(this.singPopupDom);
        this.currentSingleMaker = marker.bindPopup(popup).togglePopup();
        this.singPopupDom.addEventListener('mouseleave', this.bindCloseSingleMakerEvent, false);
      }
    });

    if (markerClick) {
      marker.on('click', () => {
        markerClick(point);
      });
    }

    return marker;
  }

  computedNearbyPoints(point) {
    if (nearByPointsCache[point.id]) {
      return nearByPointsCache[point.id];
    }
    let nearPoints = [];
    const { map } = this.props;
    const points = this.getAllClusterPoints();
    const centerPoint = L.latLng(point.latitude, point.longitude);
    for (let i = 0, l = points.length; i < l; i++) {
      if (points[i].latitude && points[i].longitude && map.distance(centerPoint, L.latLng(points[i].latitude, points[i].longitude)) <= 20) {
        nearPoints.push(points[i]);
      }
    }
    nearByPointsCache[point.id] = nearPoints;
    return nearPoints;
  }
  showCustomMarker = (types, status, cameraType, posType) => {
    nearByPointsCache = {};
    this.status = status;
    this.types = types;
    this.cameraType = cameraType;
    this.posType = posType;
    this._initMarker(this.state.points);
  };

  mapReset() {
    try {
      if (!LMConfig?.BSConfig?.LMapConfig?.specialConf) {
        const bounds = this.featureGroup.getBounds();
        if (bounds?._southWest && bounds?._northEast && bounds.isValid()) {
          this.props.map.fitBounds(bounds);
        } else {
          const [lon, lat] = LMConfig.LMapConfig?.layerOptions?.center;
          const latlng = L.latLng({ lat: lat, lng: lon });
          this.props.map.setView(latlng, LMConfig.LMapConfig?.layerOptions?.minZoom + 2);
        }
      } else {
        const [lon, lat] = LMConfig.LMapConfig?.layerOptions?.center;
        const latlng = L.latLng({ lat: lat, lng: lon });
        this.props.map.setView(latlng, LMConfig.LMapConfig?.layerOptions?.minZoom + 2);
      }
    } catch (error) {
      console.log(error);
    }
  }
  render() {
    const { singlePoint, mutiplePoints } = this.state;
    const { hasFilterResource, excludeTypes, hideFeatures, children, hasCameraType, divSource, hasCommunityType } = this.props;
    /*{ReactDOM.createPortal(
          <SingleDevice point={singlePoint} renderIconGroup={this.props.renderIconGroup} />,
          this.singPopupDom
        )}*/
    return (
      <>
        {hasFilterResource && (
          <ResourceLayer hasCameraType={hasCameraType} excludeTypes={excludeTypes} hideFeatures={hideFeatures} hasCommunityType={hasCommunityType} getPopupContainer={this.props.getPopupContainer} showCustomMarker={this.showCustomMarker}>
            {children}
          </ResourceLayer>
        )}
        {ReactDOM.createPortal(<SingleDevice point={singlePoint} renderIconGroup={this.props.renderIconGroup} itemClick={this.props.markerClick} />, this.singPopupDom)}

        {divSource &&
          ReactDOM.createPortal(
            <ResourceLayer excludeTypes={excludeTypes} hideFeatures={hideFeatures} getPopupContainer={this.props.getPopupContainer} showCustomMarker={this.showCustomMarker}>
              {children}
            </ResourceLayer>,
            divSource[0]
          )}

        {ReactDOM.createPortal(<MutipleDevice points={mutiplePoints} renderIconGroup={this.props.renderIconGroup} itemClick={this.props.markerClick} />, this.mutiplePopupDom)}
      </>
    );
  }
}
export default ClusterLayer;
