import "./shaderlib/EffectComposer";
import "./shaderlib/RenderPass";
import "./shaderlib/ShaderPass";
import "./shaderlib/MaskPass";
import "./shaderlib/CopyShader";
import "./shaderlib/VignetteShader";

AFRAME.registerSystem ('tunneleffect', {
  schema: {
    checkThresholdMs: { type: 'number', default: 200 },
    vignetteFadingMs: { type: 'number', default: 800 },
    movingEvent: { type: 'string', default: 'move' },
    radius: { type: 'number', default: 0.9, min: 0.5 },
    minRadius: { type: 'number', default: 0.5, min: 0.1 },
    softness: { type: 'number', default: 0.1, min: 0.0 },
    opacity: { type: 'number', default: 0.9, min: 0.0 }
  },

  init: function () {
    console.log('init tunneleffect');
    const data = this.data;
    this.scene = this.el;
    this.isMoving = false;
    this.dt = 0;
    this.t = 0;
    this.thresholdMs = data.checkThresholdMs;
    this.fadingMs = data.vignetteFadingMs;
    this.initMs = Date.now();
    this.radius = data.radius;
    this.minRadius = 0.65;
    this.softness = data.softness;
    this.opacity = data.opacity;
    this.movingStartTimeMs = 0;
    this.lastMovingTimeMs = 0;
    // original render function of the renderer
    this.originalRenderFunc = this.scene.renderer.render;
    // add event listener for moving event
    this.enableTunnelEffect = this.enableTunnelEffect.bind(this);
    this.scene.addEventListener(data.movingEvent, this.enableTunnelEffect);
  },

  update: function () {
    // todo
  },

  play: function () {

  },

  pause: function () {
    this.scene.removeEventListener(data.movingEvent, this.enableTunnelEffect);
  },

  tick: function (time, deltaTime) {
    if (!this.isMoving) { return; }
    if (time - this.movingStartTimeMs < this.fadingMs) {
      this._fadeInEffect(time, this.movingStartTimeMs, this.fadingMs);
    } else {
      if (time - this.lastMovingTimeMs < this.thresholdMs) { return; }
      if (time - this.lastMovingTimeMs < this.fadingMs / 1.5) {
        this._fadeOutEffect(time, this.lastMovingTimeMs, this.fadingMs / 1.5);
      } else {
        this.isMoving = false;
        this.scene.renderer.render = this.originalRenderFunc;
        this.lastMovingTimeMs = time;
        this.movingStartTimeMs = time;
      }
    }
  },

  _updateComposer: function () {
    if (!this.renderer) {
      this.renderer = this.scene.renderer;
      this.camera = this.scene.camera;
    }
    if (!this.composer) {
      this.composer = new THREE.EffectComposer(this.renderer);
    }
    this.composer.resize();
    if (!this.scenePass) {
      this.scenePass = new THREE.RenderPass(this.scene.object3D, this.camera);
    }
    if (!this.vignettePass) {
      this._updateVignettePass(this.radius, this.softness, this.opacity);
    }
    this.composer.addPass(this.scenePass);
    this.composer.addPass(this.vignettePass);
  },

  _updateVignettePass: function (radius, softness, opacity) {
    if (!this.vignettePass) {
      this.vignettePass = new THREE.ShaderPass(THREE.VignetteShader);
    }
    const { width, height } = this.renderer.getSize();
    const pixelRatio = this.renderer.getPixelRatio();
    this.vignettePass.uniforms['radius'].value = radius;
    this.vignettePass.uniforms['softness'].value = softness;
    this.vignettePass.uniforms['opacity'].value = opacity;
    this.vignettePass['resolution'] = new THREE.Uniform(new THREE.Vector2(width * pixelRatio , height * pixelRatio));
    if (!this.vignettePass.renderToScreen) {
      this.vignettePass.renderToScreen = true;
    }
  },

  bindRenderFunc: function () {
    const renderer = this.scene.renderer;
    const render = renderer.render;
    const system = this;
    let isDigest = false;

    renderer.render = function () {
      if (isDigest) {
        render.apply(this, arguments);
      } else {
        isDigest = true;
        system.composer.render(system.dt);
        isDigest = false;
      }
    };
  },

  _fadingEffect: function (currentTime, baseTime, fadingDuration, originRadius, targetRadius) {
    const progress = (currentTime - baseTime) / fadingDuration;
    const deltaR = (originRadius - targetRadius) * progress;
    const r = this.radius - deltaR;
    this._updateVignettePass(r, this.softness, this.opacity);
  },

  _fadeOutEffect: function (currentTime, baseTime, fadingDuration) {
    this._fadingEffect(currentTime, baseTime, fadingDuration, this.minRadius, this.radius);
  },

  _fadeInEffect: function (currentTime, baseTime, fadingDuration) {
    this._fadingEffect(currentTime, baseTime, fadingDuration, this.radius, this.minRadius);
  },

  enableTunnelEffect: function () {
    if (this.isMoving) {
      this.lastMovingTimeMs = Date.now() - this.initMs;
      return;
    }
    this.isMoving = true;
    this.movingStartTimeMs = Date.now() - this.initMs;
    this._updateComposer();
    this.bindRenderFunc();
  }
});