/* global assert, process, sinon, setup, suite, test */
var entityFactory = require('../helpers').entityFactory;
var THREE = require('index').THREE;

suite('sound', function () {
  setup(function (done) {
    var el = this.el = entityFactory();
    THREE.Cache.files = {};
    setTimeout(() => {
      el.sceneEl.addEventListener('loaded', function () { done(); });

      el.setAttribute('sound', {
        autoplay: true,
        src: 'url(mysoundfile.mp3)',
        loop: true,
        distanceModel: 'exponential',
        maxDistance: 20000,
        refDistance: 2,
        rolloffFactor: 4,
        poolSize: 3
      });
    });
  });

  suite('update', function () {
    test('creates sound', function () {
      var el = this.el;
      var audioPool = el.getObject3D(el.components.sound.attrName);
      for (var i = 0; i < audioPool.children.length; i++) {
        var audio = audioPool.children[i];
        assert.equal(audio.type, 'Audio');
        assert.equal(audio.getDistanceModel(), 'exponential');
        assert.equal(audio.getMaxDistance(), 20000);
        assert.equal(audio.getRefDistance(), 2);
        assert.equal(audio.getRolloffFactor(), 4);
        console.log(audio.autoplay);
        assert.notOk(audio.autoplay);
        assert.ok(audio.getLoop());
      }
    });

    test('re-creates sound when changing src', function () {
      var el = this.el;
      var oldAudio = el.getObject3D('sound').children[0];
      el.setAttribute('sound', 'src', 'url(anothersound.wav)');
      var newAudio = el.getObject3D('sound').children[0];
      assert.notEqual(oldAudio.uuid, newAudio.uuid);
    });

    test('can change src', function () {
      var el = this.el;
      el.setAttribute('sound', 'src', 'url(anothersound.wav)');
      var audioPool = el.getObject3D(el.components.sound.attrName);
      for (var i = 0; i < audioPool.children.length; i++) {
        var audio = audioPool.children[i];
        assert.equal(audio.type, 'Audio');
        assert.notOk(audio.autoplay);
        assert.ok(audio.getLoop());
      }
    });

    test.skip('can change volume', function () {
      var audioPool;
      var el = this.el;
      var i;

      el.setAttribute('sound', 'volume', 0.75);
      audioPool = el.getObject3D(el.components.sound.attrName);
      for (i = 0; i < audioPool.children.length; i++) {
        assert.equal(audioPool.children[i].getVolume(), 0.75);
      }
    });
  });

  suite('pause', function () {
    test('does not call sound pause if not playing', function () {
      var el = this.el;
      var sound = el.components.sound.pool.children[0] = {
        disconnect: sinon.stub(),
        pause: sinon.stub(),
        stop: sinon.stub(),
        isPlaying: false,
        buffer: true,
        source: {buffer: true}
      };
      el.pause();
      assert.notOk(sound.pause.called);
    });

    test('calls sound pause if playing', function () {
      var el = this.el;
      var sound = el.components.sound.pool.children[0] = {
        disconnect: sinon.stub(),
        pause: sinon.stub(),
        stop: sinon.stub(),
        isPlaying: true,
        buffer: true,
        source: {buffer: true}
      };
      el.components.sound.isPlaying = true;
      el.pause();

      // Currently we're calling stop when the component is paused as we reset
      // the state on `play` instad of resuming it
      assert.notOk(sound.pause.called);
      assert.ok(sound.stop.called);
    });
  });

  suite('play', function () {
    test('does not call sound pause if not playing', function () {
      var el = this.el;
      var sound = el.components.sound.pool.children[0] = {
        disconnect: sinon.stub(),
        play: sinon.stub(),
        stop: sinon.stub(),
        isPlaying: false,
        buffer: true,
        source: {buffer: true}
      };
      el.components.sound.autoplay = true;
      el.play();
      assert.notOk(sound.play.called);
    });
  });

  suite('pauseSound', function () {
    test('pauses sound', function () {
      var el = this.el;
      var sound = el.components.sound.pool.children[0] = {
        disconnect: sinon.stub(),
        isPlaying: true,
        isPaused: false,
        stop: sinon.stub(),
        pause: sinon.stub(),
        buffer: true,
        source: {buffer: true}
      };
      el.components.sound.pauseSound();
      assert.ok(sound.pause.called);
      assert.ok(sound.isPaused);
    });
  });

  suite('playSound', function () {
    test('plays sound when not loaded', function () {
      var el = this.el;
      var sound = el.components.sound.pool.children[0] = {
        disconnect: sinon.stub(),
        play: sinon.stub(),
        stop: sinon.stub(),
        isPlaying: false,
        buffer: true,
        source: {buffer: true}
      };
      el.components.sound.loaded = false;

      el.components.sound.playSound();
      assert.notOk(sound.play.called);
    });

    test('plays sound when loaded', function () {
      var el = this.el;
      var sound = el.components.sound.pool.children[0] = {
        disconnect: sinon.stub(),
        play: sinon.stub(),
        stop: sinon.stub(),
        isPlaying: false,
        buffer: true,
        source: {buffer: true}
      };
      el.components.sound.loaded = true;

      el.components.sound.playSound();
      assert.ok(sound.play.called);
    });

    test('plays sound if sound already playing when changing src', function (done) {
      var el = this.el;
      var playSoundStub = el.components.sound.playSound = sinon.stub();
      el.components.sound.stopSound = sinon.stub();
      el.addEventListener('sound-loaded', function () {
        assert.ok(playSoundStub.called);
        done();
      });
      el.setAttribute('sound', 'src', 'url(base/tests/assets/test.ogg)');
      el.components.sound.isPlaying = true;
    });

    test('plays sound on event', function (done) {
      const el = this.el;
      el.setAttribute('sound', 'on', 'foo');
      const playSoundStub = el.components.sound.playSound = sinon.stub();
      el.emit('foo');
      setTimeout(() => {
        assert.ok(playSoundStub.called);
        done();
      });
    });
  });

  suite('stopSound', function () {
    test('stops sound', function () {
      var el = this.el;
      var sound = el.components.sound.pool.children[0] = {
        disconnect: sinon.stub(),
        isPlaying: true,
        stop: sinon.stub(),
        buffer: true,
        source: {buffer: true}
      };
      el.components.sound.stopSound();
      assert.ok(sound.stop.called);
    });
  });

  suite('asset', function () {
    test('audio tag', function (done) {
      var sceneEl = this.el.sceneEl;
      var assetsEl = sceneEl.querySelector('a-assets');
      sceneEl.removeChild(assetsEl);
      process.nextTick(function () {
        assetsEl = document.createElement('a-assets');
        var audioEl = document.createElement('audio');
        audioEl.setAttribute('src', 'base/tests/assets/test.ogg');
        audioEl.setAttribute('id', 'testogg');
        assetsEl.appendChild(audioEl);
        sceneEl.appendChild(assetsEl);
        setTimeout(function () {
          var el = document.createElement('a-entity');
          el.addEventListener('sound-loaded', function () {
            assert.ok(this.components.sound.loaded);
            done();
          });
          el.setAttribute('sound', 'src', '#testogg');
          sceneEl.appendChild(el);
        });
      });
    });

    test.skip('preloading audio tag', function (done) {
      var sceneEl = this.el.sceneEl;
      var assetsEl = sceneEl.querySelector('a-assets');
      sceneEl.removeChild(assetsEl);
      process.nextTick(function () {
        assetsEl = document.createElement('a-assets');
        var audioEl = document.createElement('audio');
        audioEl.setAttribute('src', 'base/tests/assets/test.ogg');
        audioEl.setAttribute('id', 'testogg');
        audioEl.setAttribute('autoplay', '');
        assetsEl.appendChild(audioEl);
        sceneEl.appendChild(assetsEl);
        setTimeout(function () {
          var el = document.createElement('a-entity');
          el.addEventListener('sound-loaded', function () {
            assert.ok(this.components.sound.loaded);
            done();
          });
          el.setAttribute('sound', 'src', '#testogg');
          sceneEl.appendChild(el);
        }, 10);
      });
    });

    test('a-asset-item', function (done) {
      var sceneEl = this.el.sceneEl;
      var assetsEl = sceneEl.querySelector('a-assets');
      sceneEl.removeChild(assetsEl);
      process.nextTick(function () {
        assetsEl = document.createElement('a-assets');
        var assetItemEl = document.createElement('a-asset-item');
        assetItemEl.setAttribute('src', 'base/tests/assets/test.ogg');
        assetItemEl.setAttribute('id', 'testogg');
        assetItemEl.setAttribute('response-type', 'arraybuffer');
        assetsEl.appendChild(assetItemEl);
        sceneEl.appendChild(assetsEl);
        process.nextTick(function () {
          var el = document.createElement('a-entity');
          el.setAttribute('sound', 'src', '#testogg');
          el.addEventListener('sound-loaded', function () {
            assert.ok(this.components.sound.loaded);
            done();
          });
          sceneEl.appendChild(el);
        });
      });
    });
  });

  suite('use the same src twice', function () {
    test('use the same src twice', function (done) {
      var sceneEl = this.el.sceneEl;
      var el1 = document.createElement('a-entity');
      var el2 = document.createElement('a-entity');
      el1.setAttribute('sound', 'src', 'url(base/tests/assets/test.ogg)');
      el2.setAttribute('sound', 'src', 'url(base/tests/assets/test.ogg)');
      var loadedCount = 0;
      el1.addEventListener('sound-loaded', function () {
        assert.ok(el1.components.sound.loaded);
        loadedCount++;
        if (loadedCount === 2) {
          done();
        }
      });
      el2.addEventListener('sound-loaded', function () {
        assert.ok(el2.components.sound.loaded);
        loadedCount++;
        if (loadedCount === 2) {
          done();
        }
      });
      sceneEl.appendChild(el1);
      sceneEl.appendChild(el2);
    });
  });
});
