import { Cesium3DTileset } from "../../../Source/Cesium.js";
import { Cesium3DTileStyle } from "../../../Source/Cesium.js";
import { Globe } from "../../../Source/Cesium.js";
import createScene from "../../createScene.js";
import { when } from "../../../Source/Cesium.js";
import { Cesium3DTilesInspectorViewModel } from "../../../Source/Cesium.js";

describe(
  "Widgets/Cesium3DTilesInspector/Cesium3DTilesInspectorViewModel",
  function () {
    // Parent tile with content and four child tiles with content
    var tilesetUrl = "./Data/Cesium3DTiles/Tilesets/Tileset/tileset.json";

    var scene;
    var viewModel;
    var performanceContainer = document.createElement("div");

    beforeAll(function () {
      scene = createScene();
    });

    afterAll(function () {
      scene.destroyForSpecs();
    });

    beforeEach(function () {
      scene.globe = new Globe();
      scene.initializeFrame();
    });

    afterEach(function () {
      scene.primitives.removeAll();
    });

    it("can create and destroy", function () {
      var viewModel = new Cesium3DTilesInspectorViewModel(
        scene,
        performanceContainer
      );
      expect(viewModel._scene).toBe(scene);
      expect(viewModel.isDestroyed()).toEqual(false);
      viewModel.destroy();
      expect(viewModel.isDestroyed()).toEqual(true);
    });

    it("throws if scene is undefined", function () {
      expect(function () {
        return new Cesium3DTilesInspectorViewModel();
      }).toThrowDeveloperError();
    });

    it("throws if performanceContainer is undefined", function () {
      expect(function () {
        return new Cesium3DTilesInspectorViewModel(scene);
      }).toThrowDeveloperError();
    });

    describe("tileset options", function () {
      it("show properties", function () {
        viewModel = new Cesium3DTilesInspectorViewModel(
          scene,
          performanceContainer
        );
        var tileset = new Cesium3DTileset({
          url: tilesetUrl,
        });
        viewModel.tileset = tileset;
        var done = when.defer();
        tileset.readyPromise.then(function () {
          expect(viewModel.properties.indexOf("id") !== -1).toBe(true);
          expect(viewModel.properties.indexOf("Longitude") !== -1).toBe(true);
          expect(viewModel.properties.indexOf("Latitude") !== -1).toBe(true);
          expect(viewModel.properties.indexOf("Height") !== -1).toBe(true);
          viewModel.destroy();
          done.resolve();
        });
        return done;
      });
    });

    describe("display options", function () {
      beforeAll(function () {
        viewModel = new Cesium3DTilesInspectorViewModel(
          scene,
          performanceContainer
        );
        var tileset = new Cesium3DTileset({
          url: tilesetUrl,
        });
        viewModel.tileset = tileset;
        return tileset.readyPromise;
      });

      afterAll(function () {
        viewModel.destroy();
      });

      it("colorize", function () {
        viewModel.colorize = true;
        expect(viewModel.tileset.debugColorizeTiles).toBe(true);
        viewModel.colorize = false;
        expect(viewModel.tileset.debugColorizeTiles).toBe(false);
      });

      it("wireframe", function () {
        viewModel.wireframe = true;
        expect(viewModel.tileset.debugWireframe).toBe(true);
        viewModel.wireframe = false;
        expect(viewModel.tileset.debugWireframe).toBe(false);
      });

      it("showBoundingVolumes", function () {
        viewModel.showBoundingVolumes = true;
        expect(viewModel.tileset.debugShowBoundingVolume).toBe(true);
        viewModel.showBoundingVolumes = false;
        expect(viewModel.tileset.debugShowBoundingVolume).toBe(false);
      });

      it("showContentVolumes", function () {
        viewModel.showContentBoundingVolumes = true;
        expect(viewModel.tileset.debugShowContentBoundingVolume).toBe(true);
        viewModel.showContentBoundingVolumes = false;
        expect(viewModel.tileset.debugShowContentBoundingVolume).toBe(false);
      });

      it("showRequestVolumes", function () {
        viewModel.showRequestVolumes = true;
        expect(viewModel.tileset.debugShowViewerRequestVolume).toBe(true);
        viewModel.showRequestVolumes = false;
        expect(viewModel.tileset.debugShowViewerRequestVolume).toBe(false);
      });

      it("showOnlyPickedTileDebugLabel", function () {
        viewModel.showOnlyPickedTileDebugLabel = true;
        expect(viewModel.tileset.debugPickedTileLabelOnly).toBe(true);
        viewModel.showOnlyPickedTileDebugLabel = false;
        expect(viewModel.tileset.debugPickedTileLabelOnly).toBe(false);
      });

      it("showGeometricError", function () {
        viewModel.showGeometricError = true;
        expect(viewModel.tileset.debugShowGeometricError).toBe(true);
        viewModel.showGeometricError = false;
        expect(viewModel.tileset.debugShowGeometricError).toBe(false);
      });

      it("showRenderingStatistics", function () {
        viewModel.showRenderingStatistics = true;
        expect(viewModel.tileset.debugShowRenderingStatistics).toBe(true);
        viewModel.showRenderingStatistics = false;
        expect(viewModel.tileset.debugShowRenderingStatistics).toBe(false);
      });

      it("showMemoryUsage", function () {
        viewModel.showMemoryUsage = true;
        expect(viewModel.tileset.debugShowMemoryUsage).toBe(true);
        viewModel.showMemoryUsage = false;
        expect(viewModel.tileset.debugShowMemoryUsage).toBe(false);
      });

      it("showUrl", function () {
        viewModel.showUrl = true;
        expect(viewModel.tileset.debugShowUrl).toBe(true);
        viewModel.showUrl = false;
        expect(viewModel.tileset.debugShowUrl).toBe(false);
      });

      it("pointCloudShading", function () {
        viewModel.pointCloudShading = true;
        expect(viewModel.tileset.pointCloudShading.attenuation).toBe(true);
        viewModel.pointCloudShading = false;
        expect(viewModel.tileset.pointCloudShading.attenuation).toBe(false);
      });

      it("geometricErrorScale", function () {
        viewModel.geometricErrorScale = 1.0;
        expect(viewModel.tileset.pointCloudShading.geometricErrorScale).toBe(
          1.0
        );
        viewModel.geometricErrorScale = 0.0;
        expect(viewModel.tileset.pointCloudShading.geometricErrorScale).toBe(
          0.0
        );
      });

      it("maximumAttenuation", function () {
        viewModel.maximumAttenuation = 1.0;
        expect(viewModel.tileset.pointCloudShading.maximumAttenuation).toBe(
          1.0
        );
        viewModel.maximumAttenuation = 0.0;
        expect(
          viewModel.tileset.pointCloudShading.maximumAttenuation
        ).not.toBeDefined();
      });

      it("baseResolution", function () {
        viewModel.baseResolution = 1.0;
        expect(viewModel.tileset.pointCloudShading.baseResolution).toBe(1.0);
        viewModel.baseResolution = 0.0;
        expect(
          viewModel.tileset.pointCloudShading.baseResolution
        ).not.toBeDefined();
      });

      it("eyeDomeLighting", function () {
        viewModel.eyeDomeLighting = true;
        expect(viewModel.tileset.pointCloudShading.eyeDomeLighting).toBe(true);
        viewModel.eyeDomeLighting = false;
        expect(viewModel.tileset.pointCloudShading.eyeDomeLighting).toBe(false);
      });

      it("eyeDomeLightingStrength", function () {
        viewModel.eyeDomeLightingStrength = 1.0;
        expect(
          viewModel.tileset.pointCloudShading.eyeDomeLightingStrength
        ).toBe(1.0);
        viewModel.eyeDomeLightingStrength = 0.0;
        expect(
          viewModel.tileset.pointCloudShading.eyeDomeLightingStrength
        ).toBe(0.0);
      });

      it("eyeDomeLightingRadius", function () {
        viewModel.eyeDomeLightingRadius = 1.0;
        expect(viewModel.tileset.pointCloudShading.eyeDomeLightingRadius).toBe(
          1.0
        );
        viewModel.eyeDomeLightingRadius = 0.0;
        expect(viewModel.tileset.pointCloudShading.eyeDomeLightingRadius).toBe(
          0.0
        );
      });
    });

    describe("update options", function () {
      beforeAll(function () {
        viewModel = new Cesium3DTilesInspectorViewModel(
          scene,
          performanceContainer
        );
        viewModel.tileset = new Cesium3DTileset({
          url: tilesetUrl,
        });
        return viewModel.tileset.readyPromise;
      });

      afterAll(function () {
        viewModel.destroy();
      });

      it("freeze frame", function () {
        viewModel.freezeFrame = false;
        expect(viewModel.tileset.debugFreezeFrame).toBe(false);
        viewModel.freezeFrame = true;
        expect(viewModel.tileset.debugFreezeFrame).toBe(true);
      });

      it("maximum screen space error", function () {
        viewModel.dynamicScreenSpaceError = false;
        viewModel.maximumScreenSpaceError = 10;
        expect(viewModel.tileset.dynamicScreenSpaceError).toBe(false);
        expect(viewModel.tileset.maximumScreenSpaceError).toBe(10);
      });

      it("dynamic screen space error", function () {
        viewModel.dynamicScreenSpaceError = true;
        viewModel.dynamicScreenSpaceErrorFactor = 2;
        viewModel.dynamicScreenSpaceErrorDensity = 0.1;
        expect(viewModel.tileset.dynamicScreenSpaceError).toBe(true);
        expect(viewModel.tileset.dynamicScreenSpaceErrorFactor).toBe(2);
        expect(viewModel.tileset.dynamicScreenSpaceErrorDensity).toBe(0.1);
      });
    });

    describe("style options", function () {
      var style;

      beforeAll(function () {
        style = new Cesium3DTileStyle({
          color: {
            conditions: [
              ["${Height} >= 83", "color('purple', 0.5)"],
              ["${Height} >= 80", "color('red')"],
              ["${Height} >= 70", "color('orange')"],
              ["${Height} >= 12", "color('yellow')"],
              ["${Height} >= 7", "color('lime')"],
              ["${Height} >= 1", "color('cyan')"],
              ["true", "color('blue')"],
            ],
          },
          meta: {
            description: "'Building id ${id} has height ${Height}.'",
          },
        });

        viewModel = new Cesium3DTilesInspectorViewModel(
          scene,
          performanceContainer
        );
        viewModel.tileset = new Cesium3DTileset({
          url: tilesetUrl,
        });

        return viewModel.tileset.readyPromise;
      });

      afterAll(function () {
        viewModel.destroy();
      });

      it("loads tileset style", function () {
        viewModel.tileset.style = style;
        viewModel._update();
        expect(JSON.stringify(style.style)).toBe(
          JSON.stringify(JSON.parse(viewModel.styleString))
        );
      });

      it("does not throw on invalid syntax", function () {
        expect(function () {
          viewModel.styleString = "invalid";
        }).not.toThrowError();
      });

      it("recompiles style", function () {
        viewModel._style = undefined;
        viewModel.tileset.style = style;
        viewModel._update();
        var s = JSON.parse(viewModel.styleString);
        s.color = "color('red')";
        viewModel.styleString = JSON.stringify(s);
        viewModel.compileStyle();
        viewModel._update();
        expect(viewModel.tileset.style.style.color).toBe("color('red')");
        expect(viewModel.tileset.style.style.meta.description).toBe(
          "'Building id ${id} has height ${Height}.'"
        );
      });

      it("does not throw on invalid value", function () {
        expect(function () {
          viewModel.styleString = '{ "color": "color(1)" }';
        }).not.toThrowError();
      });
    });
  },
  "WebGL"
);
