import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { utils } from 'amos-tool';
import { Connect as UIConnect } from 'amos-framework';
import A3DDesigner, { Connect } from 'amos-3d/lib/designer';
import WorkerObjContent from 'amos-3d/lib/worker/WorkerObjContent';
import { transitionHelper } from 'amos-3d/lib/helpers';
import { InfoHelper } from 'base-r3d/lib/plugins';
import * as endConf from 'amos-processor/lib/config/endconf';
import { LensJumpFactory } from 'base-r3d/lib/factory';
import MaskContent from './MaskContent';
import { getObjFromNet } from './../../services/3dService';
import { initView3DFromBizAction } from './../../services/bizService';
import { desigerConf, desigerHelperConfig, bizControls } from './conf';
import PointsPool from './PointsPool';
import { eventTopics, isControllerEvent,  isManualOperate } from './consts';
import { executeView3dCMD,  parseManual, parseBubbleMarkers, changeBubbleTitle } from './dataProcessor';
import ScreenSaverView from './screenSaver/ScreenSaverView';
import { dealRiskSourceChange,dealRiskSourceFlicker, dealTaskworkChange } from './ruleDataProcessor';

const AmosConfig = endConf.AmosConfig;
const enableScreenSaver = AmosConfig.screenSaverConf.enable;
const showInterval = AmosConfig.screenSaverConf.delayTime * 1000;

const { resizeConnect } = Connect;
const eventConnect = UIConnect.eventConnect;
const { BaseObjHelper } = transitionHelper;

const LENS_LEVEL = {
  ROOT: 'root',
  SUB: 'sub'
};

const layerConfig = {
  defaultSelects: '',
  layers: []
};

@resizeConnect
@eventConnect
class View3D extends Component {
  constructor(props) {
    super(props);
    this.state = {
      objs: null,
      asyncModels: null,
      startAsyncLoad: false,
      showExplain: false,
      showScreenSaver: false,
      markers: {
        riskSource: [],
        equipment: [],
        danger: [],
        majorHazard: [],
        taskWork: []
      },
      executeStatus: ''
    };

    getObjFromNet('/threeres/models/xian-ccpc/index.json', (objs, asyncModels) => {
      this.setState({
        objs ,
        asyncModels
      });
    });
    this.lensLevel = LENS_LEVEL.ROOT;
    // this.markerList = {};
  }

  componentDidMount() {
    this._registerEvents();
    this._bindPubSubEvents();
    this._bindRulesPubSubEvents();
  }

  componentWillUnmount() {
    // this.infoHelper && this.infoHelper.destroy();
  }

  // eslint-disable-next-line react/sort-comp
  _registerEvents = () => {
    this.r3d.on('dbclick', evt => {
      if (evt.button !== 0) {
        return;
      }
      const object = evt.object;
      if (object) {
        this.cameraFactory.flyTo({
          position: object.position.toArray(),
          duration: 6000
        });
      }
    });
    this.r3d.on('keydown', evt => {
      // 返回上级
      if (this.lensLevel === LENS_LEVEL.SUB && evt.code === 'Backspace') {
        this.lensJumpFactory.jumpRoot();
        this.lensLevel = LENS_LEVEL.ROOT;
      }
    });
  };

  _bindPubSubEvents = () => {
    this.props.subscribe(eventTopics.base3d_view, (topic, data) => {
      if (isControllerEvent(topic)) {
        executeView3dCMD(this, topic, data);
      } else if (isManualOperate(topic)) {
        parseManual(this, topic, data);
      }
    });
  };

  _bindRulesPubSubEvents = () => {
    this.props.subscribe(eventTopics.fromws, (topic, data) => {
      if (topic === eventTopics.map_bubble) { // 监控屏气泡
        parseBubbleMarkers(this, data);
      }
    });
  }

  onGraphCreated = ({ cameraFactory, sceneFactory, outlineFactory, r3d }) => {
    this.cameraFactory = cameraFactory;
    this.sceneFactory = sceneFactory;
    this.outlineFactory = outlineFactory;
    this.r3d = r3d;

    // 重新设置 outline 风格
    this.outlineFactory.outlineConfig = {
      visibleEdgeColor: '#f8a303',
      hiddenEdgeColor: '#ffe2ad'
    };
    this.lensJumpFactory = new LensJumpFactory({
      r3d,

    // 设置 Infowindow
    // this.infoHelper = new InfoHelper({
    //   r3d,
    //   cameraFactory,
    //   sceneFactory,
    //   // element: this.createInfowindow('提示框')
    //   title: '默认标题'
    // });

    // 设置 摄像机跳跃
      cameraFactory,
      sceneFactory,
      cameraEffect: desigerHelperConfig.cameraEffect
    });
  };

  // onMarkersCreated = (type, { markersCache }) => {
  //   this.markerList[type] = markersCache;
  // };

  onAllDone = objGroup => {
    this.sceneFactory.level.change(objGroup);
    this.cameraFactory.fitView(desigerHelperConfig.cameraEffect);
    this.setState({
      startAsyncLoad: true
    });
    this.props.onLoadCompleted();
    window.onload = enableScreenSaver ? this.loading(this) : () => {};
    enableScreenSaver && this.displayTask(this);
  };

  onAfterWorkerInit = workerObjGroup => {
    // 处理跳跃
    this.lensJumpFactory.process(workerObjGroup);
  };

  onComplete = obj => {
    const me = this;
    if (!obj.isForceParent) {
      obj.on('click', evt => {
        console.log('obj click:', evt);
        // this.focusPosition(evt.pickedPosition);
        me.outlineFactory.toggleOutline(evt.object);
        me.focusObject(evt.object);

        // 设置 infowindow
        // me.infoHelper.setParent(evt.object);
        // me.infoHelper.setTitle(`模型名称：${evt.object.name}`);
      });
    }
    // 处理跳跃
    this.lensJumpFactory.process(obj);
  };

  loading(me) {
    document.onmousemove = () => this.resetTask(me);
  }

  resetTask(me) {
    me.setState({ showScreenSaver: false });
    clearTimeout(this.timer);
    // this.timer = this.displayTask(me);
    this.timer = setTimeout(() => {
      console.log('delay task');
      me.setState({ showScreenSaver: true });
      clearTimeout(this.timer);
    }, showInterval);
  }

  displayTask(me) {
    setTimeout(() => {
      console.log('delay task');
      me.setState({ showScreenSaver: true });
      clearTimeout(this.timer);
    }, showInterval);
  }

  focusPosition = position => {
    if (position) {
      this.cameraFactory.flyTo({
        position,
        duration: 1000
      });
    }
  };

  focusObject = object => {
    const me = this;
    if (object) {
      this.cameraFactory.flyTo({
        target: object,
        duration: 1000,
        // 飞行到具体的 obj 之后，执行进入层级操作
        onComplete() {
          console.log('fly done!', object);
          // 进入子层级
          if (object.foreignKey) {
            me.lensJumpFactory.jumpInByForeignKey(object.foreignKey, excludeObj => {
              // 处理非该层级的物体 （fadeOut）
              me.fadeOut(excludeObj);
            });
            me.lensLevel = LENS_LEVEL.SUB;
          }
        }
      });
    }
  };

  fadeOut = obj => {
    // obj helper
    const baseObjHelper = new BaseObjHelper({ obj });
    baseObjHelper.fadeOut();
  };

  changeMarkerType = (item, isCancel) => {
    const { markers } = this.state;
    if (item.isLine) {
      this.setState({
        toggleRoad: !isCancel
      });
    } else {
      if (isCancel) {
        bizControls.forEach(item => {
          if (item.type === 'riskSource') {
            markers['majorHazard'] = [];
          }
          markers[item.type] = [];
        });
        this.setState({
          markers
        });
      } else {
        if (item.type === 'riskSource') {//同时加载类型为重大危险源的点
          this.asyncLoadMarkerData('majorHazard');
        }
        this.asyncLoadMarkerData(item.type);
      }
    }
  };

  asyncLoadMarkerData = markerType => {
    const { markers } = this.state;
    initView3DFromBizAction(markerType).then(d => {
      markers[markerType] = d;
      this.setState({
        markers
      });
    });
  };

  executeOperate = ({ key, value }) => {
    // 最佳视角，即恢复默认视角
    if (key === 'fitview') {
      this.cameraFactory.fitView(desigerHelperConfig.cameraEffect);
    }
    // 操作说明
    else if (key === 'explain'){
      this.setState({
        showExplain: value
      });
    }
  };

  handleExplainClose = () => {
    this.setState({
      showExplain: false
    });
  }

  /**
   * 更新 markers data
   * 批量更新
   * @params {Object} markersData {markerType<String>: markers<Array>}
   */
  changeMarkersData = markersData => {
    if (!utils.isEmpty(markersData)) {
      const { markers } = this.state;
      const newMarkers = Object.assign({}, markers, markersData);
      this.setState({
        markers: newMarkers
      });
    }
  };

  createInfowindow = text => {
    const div = document.createElement('div');
    div.style.position = 'absolute';
    div.className = 'three-ui-infowindow';
    div.innerText = text;
    return div;
  };

  afterRender = () => {
    // this.infoHelper && this.infoHelper.update();
  };

  updateMarker = data => {
    const { type, id } = data;
    const { markers } = this.state;
    const markersArr = markers[type] || [];
    if (markersArr.length > 0) {
      let needUpdate = false;
      const newArr = markersArr.map(ma => {
        if (ma.id === id) {
          needUpdate = true;
          return {
            ...ma,
            ...data
          };
        }
        return ma;
      });
      // markersArr.forEach(ma => {
      //   if (ma.id === data.id){
      //     Object.assign(ma, data);
      //   }
      // });
      if (needUpdate) {
        markers[type] = newArr;
        this.setState({
          markers
        });
      }
    }
  };

  getScreenSaverContext = () => {
    return (<ScreenSaverView />);
  }

  hiddenScreenSaver = () => {
    this.setState({ showScreenSaver: false });
    clearTimeout(this.timer);
    this.timer = !enableScreenSaver ? null : setTimeout(() => {
      console.log('scoket delay task');
      this.setState({ showScreenSaver: true });
      clearTimeout(this.timer);
    }, showInterval);
  }

  triggerByRule =(topic,content)=>{
    const { seconds = 0, ruleObject = {}, taskWorkId } = content.data;
    const { riskSourceId } =  ruleObject;
    const { executeStatus } = this.state;
    switch (topic) {
      case eventTopics.map_bubble: changeBubbleTitle(this, content); // 监控屏气泡
        break;
      case 'base3d.fromws.riskPointIconChanged'://风险点图标变更
        //处理
        dealRiskSourceChange(this,riskSourceId,'riskSource');
        break;
      case 'base3d.fromws.riskLocationIconChanged'://风险位置图标变更
        //处理
        dealRiskSourceChange(this,riskSourceId,'riskSource');
        break;
      case 'base3d.fromws.riskAreaIconChanged'://风险区域颜色变更
        //处理
        dealRiskSourceChange(this,riskSourceId,'riskSource');
        break;
      case 'base3d.fromws.riskSourceFlicker'://风险点闪烁--1
        //处理
        dealRiskSourceFlicker(this,riskSourceId,'riskSource','run',seconds);
        break;
      case 'base3d.fromws.stopRiskSourceFlicker'://风险点停止闪烁
        //处理
        dealRiskSourceFlicker(this,riskSourceId,'riskSource','stop');
        break;
      case 'base3d.fromws.showhiddenTrouble'://隐患点位上显示该隐患--1
        //处理
        dealRiskSourceChange(this,riskSourceId,'danger');
        break;
      case 'base3d.fromws.hiddenTroubleFlicker'://隐患点闪烁--1
        //处理
        dealRiskSourceFlicker(this,riskSourceId,'danger','run',seconds);
        break;
      case 'base3d.fromws.stophiddenTroubleFlickr'://隐患点停止闪烁
        //处理
        dealRiskSourceFlicker(this,riskSourceId,'danger','stop');
        break;
      case 'base3d.fromws.taskWork_show'://在作业活动点位上显示该活动
        //处理
        dealTaskworkChange(this, taskWorkId, 'taskWork', 'show', executeStatus);
        break;
      case 'base3d.fromws.taskWork_hidden'://在作业活动点位上隐藏该活动
        //处理
        dealTaskworkChange(this, taskWorkId, 'taskWork', 'hide');
        break;
      default:
        console.log(topic + '不支持的类型');
    }
  }

  render() {
    const { objs, asyncModels, markers, startAsyncLoad, showExplain } = this.state;
    const { dimension } = this.props;
    const graphicProps = {
      ...dimension,
      ...desigerConf,
      enableAnimator: true,
      enableOutline: true,
      enableCSS2D: true,
      onCreated: this.onGraphCreated,
      afterRender: this.afterRender
    };
    const modelContentProps = {
      onAllDone: this.onAllDone,
      onComplete: this.onComplete
    };

    return (
      <A3DDesigner
        {...graphicProps}
        enableModelParser
        disabledEdit
        defaultLoading={false}
        ref={node => this.a3dRef = node}
        baseObjs={objs}
        maskContent={
          <MaskContent
            onItemClick={this.changeMarkerType}
            layerConfig={layerConfig}
            showExplain={showExplain}
            onExplainClose={this.handleExplainClose}
            hiddenScreenSaver={this.hiddenScreenSaver}
            onTrigger={this.triggerByRule}
          />
        }
        modelContentProps={modelContentProps}
      >
        {startAsyncLoad && <WorkerObjContent objs={asyncModels} onWorkerMessage={this.onWorkerLoading} enableLoading afterInit={this.onAfterWorkerInit} />}
        <PointsPool markers={markers} updateMarker={this.updateMarker} />
      </A3DDesigner>
    );
  }
}

View3D.propTypes = {
  dimension: PropTypes.shape({
    width: PropTypes.number,
    height: PropTypes.number
  }),
  subscribe: PropTypes.func,
  hiddenScreenSaver: PropTypes.func,
  onLoadCompleted: PropTypes.func
};

export default View3D;
