import { Cartesian2 } from "../../Source/Cesium.js";
import { Cartesian3 } from "../../Source/Cesium.js";
import { Color } from "../../Source/Cesium.js";
import { DistanceDisplayCondition } from "../../Source/Cesium.js";
import { JulianDate } from "../../Source/Cesium.js";
import { Quaternion } from "../../Source/Cesium.js";
import { ConstantProperty } from "../../Source/Cesium.js";
import { ModelGraphics } from "../../Source/Cesium.js";
import { NodeTransformationProperty } from "../../Source/Cesium.js";
import { PropertyBag } from "../../Source/Cesium.js";
import { ClippingPlaneCollection } from "../../Source/Cesium.js";
import { ColorBlendMode } from "../../Source/Cesium.js";
import { HeightReference } from "../../Source/Cesium.js";
import { ShadowMode } from "../../Source/Cesium.js";

describe("DataSources/ModelGraphics", function () {
  it("creates expected instance from raw assignment and construction", function () {
    var options = {
      uri: "0",
      scale: 1,
      show: false,
      minimumPixelSize: 2,
      maximumScale: 200,
      incrementallyLoadTextures: false,
      runAnimations: false,
      clampAnimations: false,
      shadows: ShadowMode.DISABLED,
      heightReference: HeightReference.CLAMP_TO_GROUND,
      distanceDisplayCondition: new DistanceDisplayCondition(),
      silhouetteColor: new Color(1.0, 0.0, 0.0, 1.0),
      silhouetteSize: 3.0,
      color: new Color(0.0, 1.0, 0.0, 0.2),
      colorBlendMode: ColorBlendMode.HIGHLIGHT,
      colorBlendAmount: 0.5,
      clippingPlanes: new ClippingPlaneCollection(),
      imageBasedLightingFactor: new Cartesian2(0.5, 0.5),
      lightColor: new Color(1.0, 1.0, 0.0, 1.0),
      nodeTransformations: {
        node1: {
          translation: Cartesian3.UNIT_Y,
          rotation: new Quaternion(0.5, 0.5, 0.5, 0.5),
          scale: Cartesian3.UNIT_X,
        },
      },
      articulations: {
        "articulation1 stage1": 45,
      },
    };

    var model = new ModelGraphics(options);
    expect(model.uri).toBeInstanceOf(ConstantProperty);
    expect(model.scale).toBeInstanceOf(ConstantProperty);
    expect(model.show).toBeInstanceOf(ConstantProperty);
    expect(model.minimumPixelSize).toBeInstanceOf(ConstantProperty);
    expect(model.maximumScale).toBeInstanceOf(ConstantProperty);
    expect(model.incrementallyLoadTextures).toBeInstanceOf(ConstantProperty);
    expect(model.shadows).toBeInstanceOf(ConstantProperty);
    expect(model.heightReference).toBeInstanceOf(ConstantProperty);
    expect(model.distanceDisplayCondition).toBeInstanceOf(ConstantProperty);
    expect(model.silhouetteColor).toBeInstanceOf(ConstantProperty);
    expect(model.silhouetteSize).toBeInstanceOf(ConstantProperty);
    expect(model.color).toBeInstanceOf(ConstantProperty);
    expect(model.colorBlendMode).toBeInstanceOf(ConstantProperty);
    expect(model.colorBlendAmount).toBeInstanceOf(ConstantProperty);
    expect(model.clippingPlanes).toBeInstanceOf(ConstantProperty);
    expect(model.imageBasedLightingFactor).toBeInstanceOf(ConstantProperty);
    expect(model.lightColor).toBeInstanceOf(ConstantProperty);
    expect(model.runAnimations).toBeInstanceOf(ConstantProperty);
    expect(model.clampAnimations).toBeInstanceOf(ConstantProperty);

    expect(model.nodeTransformations).toBeInstanceOf(PropertyBag);
    expect(model.articulations).toBeInstanceOf(PropertyBag);

    expect(model.uri.getValue()).toEqual(options.uri);
    expect(model.scale.getValue()).toEqual(options.scale);
    expect(model.show.getValue()).toEqual(options.show);
    expect(model.minimumPixelSize.getValue()).toEqual(options.minimumPixelSize);
    expect(model.maximumScale.getValue()).toEqual(options.maximumScale);
    expect(model.incrementallyLoadTextures.getValue()).toEqual(
      options.incrementallyLoadTextures
    );
    expect(model.shadows.getValue()).toEqual(options.shadows);
    expect(model.heightReference.getValue()).toEqual(options.heightReference);
    expect(model.distanceDisplayCondition.getValue()).toEqual(
      options.distanceDisplayCondition
    );
    expect(model.silhouetteColor.getValue()).toEqual(options.silhouetteColor);
    expect(model.silhouetteSize.getValue()).toEqual(options.silhouetteSize);
    expect(model.color.getValue()).toEqual(options.color);
    expect(model.colorBlendMode.getValue()).toEqual(options.colorBlendMode);
    expect(model.colorBlendAmount.getValue()).toEqual(options.colorBlendAmount);
    expect(model.clippingPlanes.getValue().planes).toEqual(
      options.clippingPlanes.planes
    );
    expect(model.imageBasedLightingFactor.getValue()).toEqual(
      options.imageBasedLightingFactor
    );
    expect(model.lightColor.getValue()).toEqual(options.lightColor);
    expect(model.runAnimations.getValue()).toEqual(options.runAnimations);
    expect(model.clampAnimations.getValue()).toEqual(options.clampAnimations);

    var actualNodeTransformations = model.nodeTransformations.getValue(
      new JulianDate()
    );
    var expectedNodeTransformations = options.nodeTransformations;

    // by default toEqual requires constructors to match.  for the purposes of this test, we only care about the structure.
    actualNodeTransformations = JSON.parse(
      JSON.stringify(actualNodeTransformations)
    );
    expectedNodeTransformations = JSON.parse(
      JSON.stringify(expectedNodeTransformations)
    );
    expect(actualNodeTransformations).toEqual(expectedNodeTransformations);

    var actualArticulations = model.articulations.getValue(new JulianDate());
    var expectedArticulations = options.articulations;

    // by default toEqual requires constructors to match.  for the purposes of this test, we only care about the structure.
    actualArticulations = JSON.parse(JSON.stringify(actualArticulations));
    expectedArticulations = JSON.parse(JSON.stringify(expectedArticulations));
    expect(actualArticulations).toEqual(expectedArticulations);
  });

  it("merge assigns unassigned properties", function () {
    var source = new ModelGraphics();
    source.uri = new ConstantProperty("");
    source.show = new ConstantProperty(true);
    source.scale = new ConstantProperty(1.0);
    source.minimumPixelSize = new ConstantProperty(2.0);
    source.maximumScale = new ConstantProperty(200.0);
    source.incrementallyLoadTextures = new ConstantProperty(true);
    source.shadows = new ConstantProperty(ShadowMode.ENABLED);
    source.heightReference = new ConstantProperty(
      HeightReference.CLAMP_TO_GROUND
    );
    source.distanceDisplayCondition = new ConstantProperty(
      new DistanceDisplayCondition()
    );
    source.silhouetteColor = new ConstantProperty(
      new Color(1.0, 0.0, 0.0, 1.0)
    );
    source.silhouetteSize = new ConstantProperty(3.0);
    source.color = new ConstantProperty(new Color(0.0, 1.0, 0.0, 0.2));
    source.colorBlendMode = new ConstantProperty(ColorBlendMode.HIGHLIGHT);
    source.colorBlendAmount = new ConstantProperty(0.5);
    source.clippingPlanes = new ConstantProperty(new ClippingPlaneCollection());
    source.imageBasedLightingFactor = new ConstantProperty(
      new Cartesian2(0.5, 0.5)
    );
    source.lightColor = new ConstantProperty(new Color(1.0, 1.0, 0.0, 1.0));
    source.runAnimations = new ConstantProperty(true);
    source.clampAnimations = new ConstantProperty(true);
    source.nodeTransformations = {
      node1: new NodeTransformationProperty({
        translation: Cartesian3.UNIT_Y,
        rotation: new Quaternion(0.5, 0.5, 0.5, 0.5),
        scale: Cartesian3.UNIT_X,
      }),
      node2: new NodeTransformationProperty({
        scale: Cartesian3.UNIT_Z,
      }),
    };
    source.articulations = {
      "a1 s1": 10,
      "a2 s2": 20,
    };

    var target = new ModelGraphics();
    target.merge(source);

    expect(target.uri).toBe(source.uri);
    expect(target.show).toBe(source.show);
    expect(target.scale).toBe(source.scale);
    expect(target.minimumPixelSize).toBe(source.minimumPixelSize);
    expect(target.maximumScale).toBe(source.maximumScale);
    expect(target.incrementallyLoadTextures).toBe(
      source.incrementallyLoadTextures
    );
    expect(target.shadows).toBe(source.shadows);
    expect(target.heightReference).toBe(source.heightReference);
    expect(target.distanceDisplayCondition).toBe(
      source.distanceDisplayCondition
    );
    expect(target.silhouetteColor).toEqual(source.silhouetteColor);
    expect(target.silhouetteSize).toEqual(source.silhouetteSize);
    expect(target.color).toBe(source.color);
    expect(target.colorBlendMode).toBe(source.colorBlendMode);
    expect(target.colorBlendAmount).toBe(source.colorBlendAmount);
    expect(target.clippingPlanes).toBe(source.clippingPlanes);
    expect(target.imageBasedLightingFactor).toBe(
      source.imageBasedLightingFactor
    );
    expect(target.lightColor).toBe(source.lightColor);
    expect(target.runAnimations).toBe(source.runAnimations);
    expect(target.clampAnimations).toBe(source.clampAnimations);
    expect(target.nodeTransformations).toEqual(source.nodeTransformations);
    expect(target.articulations).toEqual(source.articulations);
  });

  it("merge does not assign assigned properties", function () {
    var source = new ModelGraphics();
    source.uri = new ConstantProperty("");
    source.show = new ConstantProperty(true);
    source.scale = new ConstantProperty(1.0);
    source.minimumPixelSize = new ConstantProperty(2.0);
    source.maximumScale = new ConstantProperty(200.0);
    source.incrementallyLoadTextures = new ConstantProperty(true);
    source.shadows = new ConstantProperty(ShadowMode.ENABLED);
    source.heightReference = new ConstantProperty(
      HeightReference.CLAMP_TO_GROUND
    );
    source.distanceDisplayCondition = new ConstantProperty(
      new DistanceDisplayCondition()
    );
    source.silhouetteColor = new ConstantProperty(new Color());
    source.silhouetteSize = new ConstantProperty(1.0);
    source.color = new ConstantProperty(new Color(0.0, 1.0, 0.0, 0.2));
    source.colorBlendMode = new ConstantProperty(ColorBlendMode.HIGHLIGHT);
    source.colorBlendAmount = new ConstantProperty(0.5);
    source.clippingPlanes = new ConstantProperty(new ClippingPlaneCollection());
    source.imageBasedLightingFactor = new ConstantProperty(
      new Cartesian2(0.5, 0.5)
    );
    source.lightColor = new ConstantProperty(new Color(1.0, 1.0, 0.0, 1.0));
    source.runAnimations = new ConstantProperty(true);
    source.clampAnimations = new ConstantProperty(true);
    source.nodeTransformations = {
      transform: new NodeTransformationProperty(),
    };
    source.articulations = {
      "a1 s1": 10,
      "a2 s2": 20,
    };

    var uri = new ConstantProperty("");
    var show = new ConstantProperty(true);
    var scale = new ConstantProperty(1.0);
    var minimumPixelSize = new ConstantProperty(2.0);
    var maximumScale = new ConstantProperty(200.0);
    var incrementallyLoadTextures = new ConstantProperty(true);
    var shadows = new ConstantProperty(ShadowMode.ENABLED);
    var heightReference = new ConstantProperty(HeightReference.CLAMP_TO_GROUND);
    var distanceDisplayCondition = new ConstantProperty(
      new DistanceDisplayCondition()
    );
    var silhouetteColor = new ConstantProperty(new Color());
    var silhouetteSize = new ConstantProperty(1.0);
    var color = new ConstantProperty(new Color(0.0, 1.0, 0.0, 0.2));
    var colorBlendMode = new ConstantProperty(ColorBlendMode.HIGHLIGHT);
    var colorBlendAmount = new ConstantProperty(0.5);
    var clippingPlanes = new ConstantProperty(new ClippingPlaneCollection());
    var imageBasedLightingFactor = new ConstantProperty(
      new Cartesian2(0.5, 0.5)
    );
    var lightColor = new ConstantProperty(new Color(1.0, 1.0, 0.0, 1.0));
    var runAnimations = new ConstantProperty(true);
    var clampAnimations = new ConstantProperty(true);
    var nodeTransformations = new PropertyBag({
      transform: new NodeTransformationProperty(),
    });
    var articulations = new PropertyBag({
      "a1 s1": 10,
      "a2 s2": 20,
    });

    var target = new ModelGraphics();
    target.uri = uri;
    target.show = show;
    target.scale = scale;
    target.minimumPixelSize = minimumPixelSize;
    target.maximumScale = maximumScale;
    target.incrementallyLoadTextures = incrementallyLoadTextures;
    target.shadows = shadows;
    target.heightReference = heightReference;
    target.distanceDisplayCondition = distanceDisplayCondition;
    target.silhouetteColor = silhouetteColor;
    target.silhouetteSize = silhouetteSize;
    target.color = color;
    target.colorBlendMode = colorBlendMode;
    target.colorBlendAmount = colorBlendAmount;
    target.clippingPlanes = clippingPlanes;
    target.imageBasedLightingFactor = imageBasedLightingFactor;
    target.lightColor = lightColor;
    target.runAnimations = runAnimations;
    target.clampAnimations = clampAnimations;
    target.nodeTransformations = nodeTransformations;
    target.articulations = articulations;

    target.merge(source);

    expect(target.uri).toBe(uri);
    expect(target.show).toBe(show);
    expect(target.scale).toBe(scale);
    expect(target.minimumPixelSize).toBe(minimumPixelSize);
    expect(target.maximumScale).toBe(maximumScale);
    expect(target.incrementallyLoadTextures).toBe(incrementallyLoadTextures);
    expect(target.shadows).toBe(shadows);
    expect(target.heightReference).toBe(heightReference);
    expect(target.distanceDisplayCondition).toBe(distanceDisplayCondition);
    expect(target.silhouetteColor).toBe(silhouetteColor);
    expect(target.silhouetteSize).toBe(silhouetteSize);
    expect(target.color).toBe(color);
    expect(target.colorBlendMode).toBe(colorBlendMode);
    expect(target.colorBlendAmount).toBe(colorBlendAmount);
    expect(target.clippingPlanes).toBe(clippingPlanes);
    expect(target.imageBasedLightingFactor).toBe(imageBasedLightingFactor);
    expect(target.lightColor).toBe(lightColor);
    expect(target.runAnimations).toBe(runAnimations);
    expect(target.clampAnimations).toBe(clampAnimations);
    expect(target.nodeTransformations).toBe(nodeTransformations);
    expect(target.articulations).toBe(articulations);
  });

  it("clone works", function () {
    var source = new ModelGraphics();
    source.uri = new ConstantProperty("");
    source.show = new ConstantProperty(true);
    source.scale = new ConstantProperty(1.0);
    source.minimumPixelSize = new ConstantProperty(2.0);
    source.maximumScale = new ConstantProperty(200.0);
    source.incrementallyLoadTextures = new ConstantProperty(true);
    source.shadows = new ConstantProperty(ShadowMode.ENABLED);
    source.heightReference = new ConstantProperty(
      HeightReference.CLAMP_TO_GROUND
    );
    source.distanceDisplayCondition = new ConstantProperty(
      new DistanceDisplayCondition()
    );
    source.silhouetteColor = new ConstantProperty(new Color());
    source.silhouetteSize = new ConstantProperty(2.0);
    source.color = new ConstantProperty(new Color(0.0, 1.0, 0.0, 0.2));
    source.colorBlendMode = new ConstantProperty(ColorBlendMode.HIGHLIGHT);
    source.colorBlendAmount = new ConstantProperty(0.5);
    source.clippingPlanes = new ConstantProperty(new ClippingPlaneCollection());
    source.imageBasedLightingFactor = new ConstantProperty(
      new Cartesian2(0.5, 0.5)
    );
    source.lightColor = new ConstantProperty(new Color(1.0, 1.0, 0.0, 1.0));
    source.runAnimations = new ConstantProperty(true);
    source.clampAnimations = new ConstantProperty(true);
    source.nodeTransformations = {
      node1: new NodeTransformationProperty(),
      node2: new NodeTransformationProperty(),
    };
    source.articulations = {
      "a1 s1": 10,
      "a2 s2": 20,
    };

    var result = source.clone();
    expect(result.uri).toBe(source.uri);
    expect(result.show).toBe(source.show);
    expect(result.scale).toBe(source.scale);
    expect(result.minimumPixelSize).toBe(source.minimumPixelSize);
    expect(result.maximumScale).toBe(source.maximumScale);
    expect(result.incrementallyLoadTextures).toBe(
      source.incrementallyLoadTextures
    );
    expect(result.shadows).toBe(source.shadows);
    expect(result.heightReference).toBe(source.heightReference);
    expect(result.distanceDisplayCondition).toBe(
      source.distanceDisplayCondition
    );
    expect(result.silhouetteColor).toEqual(source.silhouetteColor);
    expect(result.silhouetteSize).toEqual(source.silhouetteSize);
    expect(result.color).toBe(source.color);
    expect(result.colorBlendMode).toBe(source.colorBlendMode);
    expect(result.colorBlendAmount).toBe(source.colorBlendAmount);
    expect(result.clippingPlanes).toBe(source.clippingPlanes);
    expect(result.imageBasedLightingFactor).toBe(
      source.imageBasedLightingFactor
    );
    expect(result.lightColor).toBe(source.lightColor);
    expect(result.runAnimations).toBe(source.runAnimations);
    expect(result.clampAnimations).toBe(source.clampAnimations);
    expect(result.nodeTransformations).toEqual(source.nodeTransformations);
    expect(result.articulations).toEqual(source.articulations);
  });

  it("merge throws if source undefined", function () {
    var target = new ModelGraphics();
    expect(function () {
      target.merge(undefined);
    }).toThrowDeveloperError();
  });
});
