import * as echarts from 'echarts/lib/echarts';
import Maptalks3DLayer from './Maptalks3DLayer';
import SceneHelper from '../common/SceneHelper';
import graphicGL from '../../util/graphicGL';
import displayShadowGLSL from '../../util/shader/displayShadow.glsl.js';
graphicGL.Shader.import(displayShadowGLSL);
export default echarts.ComponentView.extend({
  type: 'maptalks3D',
  __ecgl__: true,
  init: function (ecModel, api) {
    this._groundMesh = new graphicGL.Mesh({
      geometry: new graphicGL.PlaneGeometry(),
      material: new graphicGL.Material({
        shader: new graphicGL.Shader({
          vertex: graphicGL.Shader.source('ecgl.displayShadow.vertex'),
          fragment: graphicGL.Shader.source('ecgl.displayShadow.fragment')
        }),
        depthMask: false
      }),
      // Render first
      renderOrder: -100,
      culling: false,
      castShadow: false,
      $ignorePicking: true,
      renderNormal: true
    });
  },
  _initMaptalksLayer: function (mapbox3DModel, api) {
    var zr = api.getZr();
    this._zrLayer = new Maptalks3DLayer('maptalks3D', zr, mapbox3DModel.get('center'), mapbox3DModel.get('zoom'));
    zr.painter.insertLayer(-1000, this._zrLayer);
    this._lightRoot = new graphicGL.Node();
    this._sceneHelper = new SceneHelper(this._lightRoot);

    this._sceneHelper.initLight(this._lightRoot);

    var maptalks = this._zrLayer.getMaptalks();

    var dispatchInteractAction = this._dispatchInteractAction.bind(this, api, maptalks); // PENDING


    ['zoomend', 'zooming', 'zoomstart', 'dragrotating', 'pitch', 'pitchend', 'movestart', 'moving', 'moveend', 'resize', 'touchstart', 'touchmove', 'touchend', 'animating'].forEach(function (eName) {
      maptalks.on(eName, dispatchInteractAction);
    });
  },
  render: function (maptalks3DModel, ecModel, api) {
    if (!this._zrLayer) {
      this._initMaptalksLayer(maptalks3DModel, api);
    }

    var mtks = this._zrLayer.getMaptalks();

    var urlTemplate = maptalks3DModel.get('urlTemplate');
    var baseLayer = mtks.getBaseLayer();

    if (urlTemplate !== this._oldUrlTemplate) {
      if (!baseLayer) {
        baseLayer = new maptalks.TileLayer('maptalks-echarts-gl-baselayer', {
          urlTemplate: urlTemplate,
          // used sequentially to help with browser parallel requests per domain limitation
          subdomains: ['a', 'b', 'c'],
          attribution: maptalks3DModel.get('attribution')
        });
        mtks.setBaseLayer(baseLayer);
      } else {
        // PENDING setOptions may not work?
        baseLayer.setOptions({
          urlTemplate: urlTemplate,
          attribution: maptalks3DModel.get('attribution')
        });
      }
    }

    this._oldUrlTemplate = urlTemplate;
    mtks.setCenter(maptalks3DModel.get('center'));
    mtks.setZoom(maptalks3DModel.get('zoom'), {
      animation: false
    });
    mtks.setPitch(maptalks3DModel.get('pitch'));
    mtks.setBearing(maptalks3DModel.get('bearing'));
    maptalks3DModel.setMaptalks(mtks);
    var coordSys = maptalks3DModel.coordinateSystem; // Not add to rootNode. Or light direction will be stretched by rootNode scale

    coordSys.viewGL.scene.add(this._lightRoot);
    coordSys.viewGL.add(this._groundMesh);

    this._updateGroundMesh(); // Update lights


    this._sceneHelper.setScene(coordSys.viewGL.scene);

    this._sceneHelper.updateLight(maptalks3DModel); // Update post effects


    coordSys.viewGL.setPostEffect(maptalks3DModel.getModel('postEffect'), api);
    coordSys.viewGL.setTemporalSuperSampling(maptalks3DModel.getModel('temporalSuperSampling'));
    this._maptalks3DModel = maptalks3DModel;
  },
  afterRender: function (maptalks3DModel, ecModel, api, layerGL) {
    var renderer = layerGL.renderer;

    this._sceneHelper.updateAmbientCubemap(renderer, maptalks3DModel, api);

    this._sceneHelper.updateSkybox(renderer, maptalks3DModel, api); // FIXME If other series changes coordinate system.
    // FIXME When doing progressive rendering.


    maptalks3DModel.coordinateSystem.viewGL.scene.traverse(function (mesh) {
      if (mesh.material) {
        mesh.material.define('fragment', 'NORMAL_UP_AXIS', 2);
        mesh.material.define('fragment', 'NORMAL_FRONT_AXIS', 1);
      }
    });
  },
  updateCamera: function (maptalks3DModel, ecModel, api, payload) {
    maptalks3DModel.coordinateSystem.setCameraOption(payload);

    this._updateGroundMesh();

    api.getZr().refresh();
  },
  _dispatchInteractAction: function (api, maptalks, maptalks3DModel) {
    api.dispatchAction({
      type: 'maptalks3DChangeCamera',
      pitch: maptalks.getPitch(),
      zoom: getMapboxZoom(maptalks.getResolution()) + 1,
      center: maptalks.getCenter().toArray(),
      bearing: maptalks.getBearing(),
      maptalks3DId: this._maptalks3DModel && this._maptalks3DModel.id
    });
  },
  _updateGroundMesh: function () {
    if (this._maptalks3DModel) {
      var coordSys = this._maptalks3DModel.coordinateSystem;
      var pt = coordSys.dataToPoint(coordSys.center);

      this._groundMesh.position.set(pt[0], pt[1], -0.001);

      var plane = new graphicGL.Plane(new graphicGL.Vector3(0, 0, 1), 0);
      var ray1 = coordSys.viewGL.camera.castRay(new graphicGL.Vector2(-1, -1));
      var ray2 = coordSys.viewGL.camera.castRay(new graphicGL.Vector2(1, 1));
      var pos0 = ray1.intersectPlane(plane);
      var pos1 = ray2.intersectPlane(plane);
      var scale = pos0.dist(pos1) / coordSys.viewGL.rootNode.scale.x;

      this._groundMesh.scale.set(scale, scale, 1);
    }
  },
  dispose: function (ecModel, api) {
    if (this._zrLayer) {
      this._zrLayer.dispose();
    }

    api.getZr().painter.delLayer(-1000);
  }
});
const MAX_RES = 2 * 6378137 * Math.PI / (256 * Math.pow(2, 20));

function getMapboxZoom(res) {
  return 19 - Math.log(res / MAX_RES) / Math.LN2;
}