import { Clock } from "../../Source/Cesium.js";
import { FeatureDetection } from "../../Source/Cesium.js";
import { Iso8601 } from "../../Source/Cesium.js";
import { JulianDate } from "../../Source/Cesium.js";
import { Math as CesiumMath } from "../../Source/Cesium.js";
import { VideoSynchronizer } from "../../Source/Cesium.js";
import pollToPromise from "../pollToPromise.js";

describe("Core/VideoSynchronizer", function () {
  //Video textures do not work on Internet Explorer
  if (FeatureDetection.isInternetExplorer()) {
    return;
  }

  function loadVideo() {
    var element = document.createElement("video");
    var source = document.createElement("source");
    source.setAttribute("src", "Data/Videos/big-buck-bunny-trailer-small.webm");
    source.setAttribute("type", "video/webm");
    element.appendChild(source);

    source = document.createElement("source");
    source.setAttribute("src", "Data/Videos/big-buck-bunny-trailer-small.mp4");
    source.setAttribute("type", "video/mp4");
    element.appendChild(source);

    source = document.createElement("source");
    source.setAttribute("src", "Data/Videos/big-buck-bunny-trailer-small.mov");
    source.setAttribute("type", "video/quicktime");
    element.appendChild(source);

    return element;
  }

  it("Can default construct", function () {
    var videoSynchronizer = new VideoSynchronizer();

    expect(videoSynchronizer.clock).not.toBeDefined();
    expect(videoSynchronizer.element).not.toBeDefined();
    expect(videoSynchronizer.epoch).toBe(Iso8601.MINIMUM_VALUE);
    expect(videoSynchronizer.tolerance).toBe(1.0);
    expect(videoSynchronizer.isDestroyed()).toBe(false);
    expect(videoSynchronizer.destroy()).not.toBeDefined();
    expect(videoSynchronizer.isDestroyed()).toBe(true);
  });

  it("Can construct with options", function () {
    var clock = new Clock();
    var element = document.createElement("video");
    var epoch = new JulianDate();
    var tolerance = 0.15;

    var videoSynchronizer = new VideoSynchronizer({
      clock: clock,
      element: element,
      epoch: epoch,
      tolerance: tolerance,
    });

    expect(videoSynchronizer.clock).toBe(clock);
    expect(videoSynchronizer.element).toBe(element);
    expect(videoSynchronizer.epoch).toBe(epoch);
    expect(videoSynchronizer.tolerance).toBe(tolerance);
    expect(videoSynchronizer.isDestroyed()).toBe(false);
    expect(videoSynchronizer.destroy()).not.toBeDefined();
    expect(videoSynchronizer.isDestroyed()).toBe(true);
  });

  it("Syncs time when looping", function () {
    var epoch = JulianDate.fromIso8601("2015-11-01T00:00:00Z");
    var clock = new Clock();
    clock.shouldAnimate = false;
    clock.currentTime = epoch.clone();

    var element = loadVideo();
    element.loop = true;

    var videoSynchronizer = new VideoSynchronizer({
      clock: clock,
      element: element,
      epoch: epoch,
    });

    return pollToPromise(function () {
      clock.tick();
      return element.currentTime === 0;
    })
      .then(function () {
        clock.currentTime = JulianDate.addSeconds(epoch, 10, clock.currentTime);
        return pollToPromise(function () {
          clock.tick();
          return element.currentTime === 10;
        });
      })
      .then(function () {
        clock.currentTime = JulianDate.addSeconds(epoch, 60, clock.currentTime);
        return pollToPromise(function () {
          clock.tick();
          return CesiumMath.equalsEpsilon(
            element.currentTime,
            60 - element.duration,
            CesiumMath.EPSILON3
          );
        });
      })
      .then(function () {
        clock.currentTime = JulianDate.addSeconds(epoch, -1, clock.currentTime);
        return pollToPromise(function () {
          clock.tick();
          return CesiumMath.equalsEpsilon(
            element.currentTime,
            element.duration - 1,
            CesiumMath.EPSILON1
          );
        });
      })
      .then(function () {
        videoSynchronizer.destroy();
      });
  });

  it("Syncs time when not looping", function () {
    var epoch = JulianDate.fromIso8601("2015-11-01T00:00:00Z");
    var clock = new Clock();
    clock.shouldAnimate = false;
    clock.currentTime = epoch.clone();

    var element = loadVideo();

    var videoSynchronizer = new VideoSynchronizer({
      clock: clock,
      element: element,
      epoch: epoch,
    });

    return pollToPromise(function () {
      clock.tick();
      return element.currentTime === 0;
    })
      .then(function () {
        clock.currentTime = JulianDate.addSeconds(epoch, 10, clock.currentTime);
        return pollToPromise(function () {
          clock.tick();
          return element.currentTime === 10;
        });
      })
      .then(function () {
        clock.currentTime = JulianDate.addSeconds(epoch, 60, clock.currentTime);
        return pollToPromise(function () {
          clock.tick();
          return CesiumMath.equalsEpsilon(
            element.currentTime,
            element.duration,
            CesiumMath.EPSILON3
          );
        });
      })
      .then(function () {
        clock.currentTime = JulianDate.addSeconds(epoch, -1, clock.currentTime);
        return pollToPromise(function () {
          clock.tick();
          return element.currentTime === 0;
        });
      })
      .then(function () {
        videoSynchronizer.destroy();
      });
  });

  it("Plays/pauses video based on clock", function () {
    var epoch = JulianDate.fromIso8601("2015-11-01T00:00:00Z");
    var clock = new Clock();

    // Since Chrome doesn't allow video playback without user
    // interaction, we use a mock element.
    var element = jasmine.createSpyObj("MockVideoElement", [
      "addEventListener",
      "removeEventListener",
      "play",
      "pause",
    ]);
    element.paused = false;
    element.play.and.callFake(function () {
      this.paused = false;
    });
    element.pause.and.callFake(function () {
      this.paused = true;
    });

    var videoSynchronizer = new VideoSynchronizer({
      clock: clock,
      element: element,
      epoch: epoch,
    });

    clock.shouldAnimate = false;
    clock.tick();
    expect(element.pause.calls.count()).toEqual(1);

    clock.shouldAnimate = true;
    clock.tick();
    expect(element.play.calls.count()).toEqual(1);

    clock.shouldAnimate = false;
    clock.tick();
    expect(element.pause.calls.count()).toEqual(2);

    videoSynchronizer.destroy();
  });
});
