import { makeAppObjectRepo } from "@vived/core";
import { Quaternion, Vector3 } from "@vived/core";
import { EnablementEntity } from "../../Enablement";
import { ChannelModelState, ChannelModelEntity, makeChannelModelEntity, } from "./ChannelModel";
function makeTestRig() {
    const appObjects = makeAppObjectRepo();
    const appObj = appObjects.getOrCreate("appObj");
    const channelModel = makeChannelModelEntity(appObj);
    const observer = jest.fn();
    channelModel.addChangeObserver(observer);
    return { channelModel, observer, appObj, appObjects };
}
describe("Channel Model Entity", () => {
    it("Gets by ID", () => {
        const { channelModel, appObjects } = makeTestRig();
        expect(ChannelModelEntity.get("appObj", appObjects)).toEqual(channelModel);
    });
    it("Sets the id", () => {
        const { channelModel, appObj } = makeTestRig();
        expect(channelModel.appObject).toEqual(appObj);
    });
    it("Notifies when the name changes", () => {
        const { channelModel, observer } = makeTestRig();
        channelModel.name = "hello world";
        channelModel.name = "hello world";
        channelModel.name = "hello world";
        expect(channelModel.name).toEqual("hello world");
        expect(observer).toHaveBeenCalledTimes(1);
    });
    it("Notifies when the state changes", () => {
        const { channelModel, observer } = makeTestRig();
        expect(channelModel.state).toEqual(ChannelModelState.INIT);
        channelModel.state = ChannelModelState.LOADING;
        expect(channelModel.state).toEqual(ChannelModelState.LOADING);
        expect(observer).toHaveBeenCalled();
    });
    it("Does not notify if there is no change in the state", () => {
        const { channelModel, observer } = makeTestRig();
        expect(channelModel.state).toEqual(ChannelModelState.INIT);
        channelModel.state = ChannelModelState.INIT;
        channelModel.state = ChannelModelState.INIT;
        channelModel.state = ChannelModelState.INIT;
        channelModel.state = ChannelModelState.INIT;
        expect(observer).not.toHaveBeenCalled();
    });
    it("Sets an error", () => {
        const { channelModel, observer } = makeTestRig();
        expect(channelModel.state).toEqual(ChannelModelState.INIT);
        expect(channelModel.modelError).toBeUndefined();
        const e = new Error("Some Error");
        channelModel.modelError = e;
        expect(observer).toHaveBeenCalled();
        expect(channelModel.state).toEqual(ChannelModelState.ERROR);
        expect(channelModel.modelError).toEqual(e);
    });
    it("Sets the bounds min", () => {
        const { channelModel } = makeTestRig();
        const vector3 = new Vector3(1, 2, 3);
        expect(channelModel.bounds_min).toEqual(Vector3.Zero());
        channelModel.bounds_min = vector3;
        expect(channelModel.bounds_min).toEqual(vector3);
    });
    it("Should notify when the bounds min was changed", () => {
        const { channelModel, observer } = makeTestRig();
        const vector3 = new Vector3(1, 2, 3);
        channelModel.bounds_min = vector3;
        expect(observer).toHaveBeenCalled();
    });
    it("Doesn't notify when the bounds min was not changed", () => {
        const { channelModel, observer } = makeTestRig();
        const vector3 = new Vector3(1, 2, 3);
        channelModel.bounds_min = vector3;
        observer.mockClear();
        channelModel.bounds_min = vector3;
        channelModel.bounds_min = vector3;
        channelModel.bounds_min = vector3;
        expect(observer).not.toHaveBeenCalled();
    });
    it("Sets the bounds max", () => {
        const { channelModel } = makeTestRig();
        const vector3 = new Vector3(1, 2, 3);
        expect(channelModel.bounds_max).toEqual(Vector3.Zero());
        channelModel.bounds_max = vector3;
        expect(channelModel.bounds_max).toEqual(vector3);
    });
    it("Should notify when the bounds max was changed", () => {
        const { channelModel, observer } = makeTestRig();
        const vector3 = new Vector3(1, 2, 3);
        channelModel.bounds_max = vector3;
        expect(observer).toHaveBeenCalled();
    });
    it("Doesn't notify when the bounds max was not changed", () => {
        const { channelModel, observer } = makeTestRig();
        const vector3 = new Vector3(1, 2, 3);
        channelModel.bounds_max = vector3;
        observer.mockClear();
        channelModel.bounds_max = vector3;
        channelModel.bounds_max = vector3;
        channelModel.bounds_max = vector3;
        expect(observer).not.toHaveBeenCalled();
    });
    it("Sets the default position", () => {
        const { channelModel } = makeTestRig();
        const vector3 = new Vector3(1, 2, 3);
        expect(channelModel.defaultPosition).toEqual(Vector3.Zero());
        channelModel.defaultPosition = vector3;
        expect(channelModel.defaultPosition).toEqual(vector3);
    });
    it("Should notify when the default position was changed", () => {
        const { channelModel, observer } = makeTestRig();
        const vector3 = new Vector3(1, 2, 3);
        channelModel.defaultPosition = vector3;
        expect(observer).toHaveBeenCalled();
    });
    it("Doesn't notify when the default position was not changed", () => {
        const { channelModel, observer } = makeTestRig();
        const vector3 = new Vector3(1, 2, 3);
        channelModel.defaultPosition = vector3;
        observer.mockClear();
        channelModel.defaultPosition = vector3;
        channelModel.defaultPosition = vector3;
        channelModel.defaultPosition = vector3;
        expect(observer).not.toHaveBeenCalled();
    });
    it("Sets the default rotation", () => {
        const { channelModel } = makeTestRig();
        const quaternion = new Quaternion(1, 2, 3, 1);
        expect(channelModel.defaultRotation).toEqual(Quaternion.Identity());
        channelModel.defaultRotation = quaternion;
        expect(channelModel.defaultRotation).toEqual(quaternion);
    });
    it("Should notify when the default rotation was changed", () => {
        const { channelModel, observer } = makeTestRig();
        const quaternion = new Quaternion(1, 2, 3, 1);
        channelModel.defaultRotation = quaternion;
        expect(observer).toHaveBeenCalled();
    });
    it("Doesn't notify when the default rotation was not changed", () => {
        const { channelModel, observer } = makeTestRig();
        const quaternion = new Quaternion(1, 2, 3, 1);
        channelModel.defaultRotation = quaternion;
        observer.mockClear();
        channelModel.defaultRotation = quaternion;
        channelModel.defaultRotation = quaternion;
        channelModel.defaultRotation = quaternion;
        expect(observer).not.toHaveBeenCalled();
    });
    it("Should notify when the root rotation was changed", () => {
        const { channelModel, observer } = makeTestRig();
        const quaternion = new Quaternion(1, 2, 3, 1);
        channelModel.rootRotation = quaternion;
        expect(observer).toHaveBeenCalled();
    });
    it("Doesn't notify when the root rotation was not changed", () => {
        const { channelModel, observer } = makeTestRig();
        const quaternion = new Quaternion(1, 2, 3, 1);
        channelModel.rootRotation = quaternion;
        observer.mockClear();
        channelModel.rootRotation = quaternion;
        channelModel.rootRotation = quaternion;
        channelModel.rootRotation = quaternion;
        expect(observer).not.toHaveBeenCalled();
    });
    it("Sets the default scale", () => {
        const { channelModel } = makeTestRig();
        const scale = 2;
        expect(channelModel.defaultScale).toEqual(1);
        channelModel.defaultScale = scale;
        expect(channelModel.defaultScale).toEqual(scale);
    });
    it("Should notify when the default scale was changed", () => {
        const { channelModel, observer } = makeTestRig();
        const scale = 2;
        channelModel.defaultScale = scale;
        expect(observer).toHaveBeenCalled();
    });
    it("Doesn't notify when the default scale was not changed", () => {
        const { channelModel, observer } = makeTestRig();
        const scale = 2;
        channelModel.defaultScale = scale;
        observer.mockClear();
        channelModel.defaultScale = scale;
        channelModel.defaultScale = scale;
        channelModel.defaultScale = scale;
        expect(observer).not.toHaveBeenCalled();
    });
    it("Creates a new object and adds it to the repo", () => {
        const { channelModel } = makeTestRig();
        const obj = channelModel.addModelObject();
        expect(channelModel.modelObjectIds).toEqual([obj.id]);
        expect(channelModel.hasModelObject(obj.id)).toEqual(true);
    });
    it("Creates a new object with a specific id", () => {
        const { channelModel } = makeTestRig();
        const obj = channelModel.addModelObject("obj1");
        expect(obj.id).toEqual("obj1");
    });
    it("Gets the objects", () => {
        const { channelModel } = makeTestRig();
        const obj = channelModel.addModelObject();
        expect(channelModel.modelObjects()).toEqual([obj]);
    });
    it("Notifies when the enablement changes", () => {
        const { channelModel, observer } = makeTestRig();
        channelModel.enabled = true;
        expect(channelModel.enabled).toEqual(true);
        observer.mockClear();
        channelModel.enabled = false;
        expect(channelModel.enabled).toEqual(false);
        expect(observer).toHaveBeenCalledTimes(1);
        channelModel.enabled = false;
        channelModel.enabled = false;
        channelModel.enabled = false;
        channelModel.enabled = false;
        expect(observer).toHaveBeenCalledTimes(1);
    });
    it("Adds an enablement entity", () => {
        const { appObj } = makeTestRig();
        expect(appObj.hasComponent(EnablementEntity.type)).toEqual(true);
    });
});
describe("Channel Model Data", () => {
    it("Stores the correct version", () => {
        const { channelModel } = makeTestRig();
        const data = channelModel.data;
        expect(data.version).toEqual(1); // Always. Do not iterate. This keeps old App working.
    });
    it("Stores the name", () => {
        const { channelModel } = makeTestRig();
        channelModel.name = "a name";
        const data = channelModel.data;
        expect(data.name).toEqual("a name");
    });
    it("Stores the min bounds", () => {
        const { channelModel } = makeTestRig();
        channelModel.bounds_min = new Vector3(1, 2, 3);
        const data = channelModel.data;
        expect(data.bounds_min).toEqual({ x: 1, y: 2, z: 3 });
    });
    it("Stores the max bounds", () => {
        const { channelModel } = makeTestRig();
        channelModel.bounds_max = new Vector3(1, 2, 3);
        const data = channelModel.data;
        expect(data.bounds_max).toEqual({ x: 1, y: 2, z: 3 });
    });
    it("Stores the default Position", () => {
        const { channelModel } = makeTestRig();
        channelModel.defaultPosition = new Vector3(1, 2, 3);
        const data = channelModel.data;
        expect(data.defaultPosition).toEqual({ x: 1, y: 2, z: 3 });
    });
    it("Stores the default rotation", () => {
        const { channelModel } = makeTestRig();
        const quat = new Quaternion(1, 2, 3, 4);
        channelModel.defaultRotation = quat;
        const data = channelModel.data;
        expect(data.defaultRotation).toEqual(quat.dto);
    });
    it("Stores the default scale", () => {
        const { channelModel } = makeTestRig();
        channelModel.defaultScale = 5;
        const data = channelModel.data;
        expect(data.defaultScale).toEqual(5);
    });
    it("Stores the objects", () => {
        const { channelModel } = makeTestRig();
        const obj = channelModel.addModelObject("obj1");
        obj.subMeshPaths = ["meshPath1"];
        obj.tags = ["Tag1"];
        obj.label.default = "A Label";
        const data = channelModel.data;
        expect(data.objects).toHaveLength(1);
        expect(data.objects[0].id).toEqual("obj1");
        expect(data.objects[0].label).toEqual("A Label");
        expect(data.objects[0].meshPaths).toEqual(["meshPath1"]);
        expect(data.objects[0].tags).toEqual(["Tag1"]);
    });
    it("Stores the root rotation", () => {
        const { channelModel } = makeTestRig();
        const quat = new Quaternion(1, 2, 3, 4);
        channelModel.rootRotation = quat;
        const data = channelModel.data;
        expect(data.rootRotation).toEqual(quat.dto);
    });
});
describe("Apply General Data", () => {
    it("Applies the original objects", () => {
        const { channelModel } = makeTestRig();
        expect(channelModel.modelObjectIds).toEqual([]);
        const data = {
            objects: [
                {
                    id: "obj1",
                    label: "An Object",
                    meshPaths: ["mesh1"],
                    tags: ["tag1"],
                },
            ],
        };
        channelModel.setupFromData(data);
        expect(channelModel.modelObjectIds).toEqual(["obj1"]);
        const obj = channelModel.getModelObject("obj1");
        expect(obj?.label.default).toEqual("An Object");
        expect(obj?.subMeshPaths).toEqual(["mesh1"]);
        expect(obj?.tags).toEqual(["tag1"]);
    });
    it("Applies the original collection", () => {
        const { channelModel } = makeTestRig();
        expect(channelModel.originalCollectionID).toBeUndefined();
        const data = {
            originalCollectionID: "original collection",
        };
        channelModel.setupFromData(data);
        expect(channelModel.originalCollectionID).toEqual("original collection");
    });
    it("Applies the name", () => {
        const { channelModel } = makeTestRig();
        expect(channelModel.name).toEqual("");
        const data = {
            name: "a name",
        };
        channelModel.setupFromData(data);
        expect(channelModel.name).toEqual("a name");
    });
    it("Applies the default scale", () => {
        const { channelModel } = makeTestRig();
        expect(channelModel.defaultScale).toEqual(1);
        const data = {
            defaultScale: 10,
        };
        channelModel.setupFromData(data);
        expect(channelModel.defaultScale).toEqual(10);
    });
    it("Applies the default rotation", () => {
        const { channelModel } = makeTestRig();
        const quat = new Quaternion(1, 2, 3, 4);
        expect(channelModel.defaultRotation).toEqual(Quaternion.Identity());
        const data = {
            defaultRotation: quat.dto,
        };
        channelModel.setupFromData(data);
        expect(channelModel.defaultRotation).toEqual(quat);
    });
    it("Applies the root rotation", () => {
        const { channelModel } = makeTestRig();
        const quat = new Quaternion(1, 2, 3, 4);
        expect(channelModel.rootRotation).toEqual(Quaternion.Identity());
        const data = {
            rootRotation: quat.dto,
        };
        channelModel.setupFromData(data);
        expect(channelModel.rootRotation).toEqual(quat);
    });
    it("Applies the default position", () => {
        const { channelModel } = makeTestRig();
        const vec = new Vector3(1, 2, 3);
        expect(channelModel.defaultPosition).toEqual(Vector3.Zero());
        const data = {
            defaultPosition: vec.dto,
        };
        channelModel.setupFromData(data);
        expect(channelModel.defaultPosition).toEqual(vec);
    });
});
const rot = new Quaternion(1, 2, 3, 4);
const dataV2 = {
    bounds_max: { x: 1, y: 2, z: 3 },
    bounds_min: { x: 4, y: 5, z: 6 },
    defaultPosition: { x: 7, y: 8, z: 9 },
    defaultRotation: rot.dto,
    defaultScale: 10,
    name: "A Name",
    objects: [
        {
            id: "obj1",
            label: "An Object",
            meshPaths: ["mesh1"],
            tags: ["tag1"],
        },
    ],
    version: 2,
    originalCollectionID: "original collection",
};
describe("Apply V2 Data", () => {
    it("Applies the original objects", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV2);
        expect(channelModel.modelObjectIds).toEqual(["obj1"]);
        const obj = channelModel.getModelObject("obj1");
        expect(obj?.label.default).toEqual("An Object");
        expect(obj?.subMeshPaths).toEqual(["mesh1"]);
        expect(obj?.tags).toEqual(["tag1"]);
    });
    it("Applies the original collection", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV2);
        expect(channelModel.originalCollectionID).toEqual("original collection");
    });
    it("Applies the name", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV2);
        expect(channelModel.name).toEqual("A Name");
    });
    it("Applies the default scale", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV2);
        expect(channelModel.defaultScale).toEqual(10);
    });
    it("Applies the default rotation", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV2);
        expect(channelModel.defaultRotation).toEqual(rot);
    });
    it("Applies the default position", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV2);
        expect(channelModel.defaultPosition).toEqual(new Vector3(7, 8, 9));
    });
    it("Defaults the root rotation to the identity", () => {
        const { channelModel } = makeTestRig();
        channelModel.rootRotation = new Quaternion(1, 2, 3, 4);
        channelModel.setupFromData(dataV2);
        expect(channelModel.rootRotation).toEqual(Quaternion.Identity());
    });
    it("Applies the max bounds", () => {
        const { channelModel } = makeTestRig();
        channelModel.bounds_max = Vector3.Zero();
        channelModel.setupFromData(dataV2);
        expect(channelModel.bounds_max).toEqual(new Vector3(1, 2, 3));
    });
    it("Applies the min bounds", () => {
        const { channelModel } = makeTestRig();
        channelModel.bounds_min = Vector3.Zero();
        channelModel.setupFromData(dataV2);
        expect(channelModel.bounds_min).toEqual(new Vector3(4, 5, 6));
    });
});
const dataV1 = {
    bounds_max: { x: 1, y: 2, z: 3 },
    bounds_min: { x: 4, y: 5, z: 6 },
    defaultPosition: { x: 7, y: 8, z: 9 },
    defaultRotation: rot.dto,
    defaultScale: 10,
    name: "A Name",
    objects: [
        {
            id: "obj1",
            label: "An Object",
            meshPaths: ["mesh1"],
            version: 1,
        },
    ],
    version: 0,
};
describe("Apply V1 Data", () => {
    it("Applies the original objects", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV1);
        expect(channelModel.modelObjectIds).toEqual(["obj1"]);
        const obj = channelModel.getModelObject("obj1");
        expect(obj?.label.default).toEqual("An Object");
        expect(obj?.subMeshPaths).toEqual(["mesh1"]);
        expect(obj?.tags).toEqual([]);
    });
    it("Applies the original collection", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV1);
        expect(channelModel.originalCollectionID).toBeUndefined();
    });
    it("Applies the name", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV1);
        expect(channelModel.name).toEqual("A Name");
    });
    it("Applies the default scale", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV1);
        expect(channelModel.defaultScale).toEqual(10);
    });
    it("Applies the default rotation", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV1);
        expect(channelModel.defaultRotation).toEqual(rot);
    });
    it("Applies the default position", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV1);
        expect(channelModel.defaultPosition).toEqual(new Vector3(7, 8, 9));
    });
    it("Applies the min bounds", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV1);
        expect(channelModel.bounds_min).toEqual(new Vector3(4, 5, 6));
    });
    it("Applies the max bounds", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV1);
        expect(channelModel.bounds_max).toEqual(new Vector3(1, 2, 3));
    });
    it("Defaults the root rotation to the identity", () => {
        const { channelModel } = makeTestRig();
        channelModel.rootRotation = new Quaternion(1, 2, 3, 4);
        channelModel.setupFromData(dataV1);
        expect(channelModel.rootRotation).toEqual(Quaternion.Identity());
    });
    it("Applies the max bounds", () => {
        const { channelModel } = makeTestRig();
        channelModel.bounds_max = Vector3.Zero();
        channelModel.setupFromData(dataV1);
        expect(channelModel.bounds_max).toEqual(new Vector3(1, 2, 3));
    });
    it("Applies the min bounds", () => {
        const { channelModel } = makeTestRig();
        channelModel.bounds_min = Vector3.Zero();
        channelModel.setupFromData(dataV1);
        expect(channelModel.bounds_min).toEqual(new Vector3(4, 5, 6));
    });
});
const dataV0 = {
    bounds_max: { x: 1, y: 2, z: 3 },
    bounds_min: { x: 4, y: 5, z: 6 },
    defaultPosition: { x: 7, y: 8, z: 9 },
    defaultRotation: rot.dto,
    defaultScale: 10,
    name: "A Name",
    objects: [
        {
            id: "obj1",
            label: "An Object",
            meshPaths: ["mesh1"],
        },
    ],
    version: 1,
    description: "some description",
};
describe("Apply V0 Data", () => {
    it("Applies the original objects", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV0);
        expect(channelModel.modelObjectIds).toEqual(["obj1"]);
        const obj = channelModel.getModelObject("obj1");
        expect(obj?.label.default).toEqual("An Object");
        expect(obj?.subMeshPaths).toEqual(["mesh1"]);
        expect(obj?.tags).toEqual([]);
    });
    it("Applies the original collection", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV0);
        expect(channelModel.originalCollectionID).toBeUndefined();
    });
    it("Applies the name", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV0);
        expect(channelModel.name).toEqual("A Name");
    });
    it("Applies the default scale", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV0);
        expect(channelModel.defaultScale).toEqual(10);
    });
    it("Applies the default rotation", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV0);
        expect(channelModel.defaultRotation).toEqual(rot);
    });
    it("Applies the default position", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV0);
        expect(channelModel.defaultPosition).toEqual(new Vector3(7, 8, 9));
    });
    it("Applies the min bounds", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV0);
        expect(channelModel.bounds_min).toEqual(new Vector3(4, 5, 6));
    });
    it("Applies the max bounds", () => {
        const { channelModel } = makeTestRig();
        channelModel.setupFromData(dataV0);
        expect(channelModel.bounds_max).toEqual(new Vector3(1, 2, 3));
    });
    it("Defaults the root rotation to the identity", () => {
        const { channelModel } = makeTestRig();
        channelModel.rootRotation = new Quaternion(1, 2, 3, 4);
        channelModel.setupFromData(dataV0);
        expect(channelModel.rootRotation).toEqual(Quaternion.Identity());
    });
    it("Applies the max bounds", () => {
        const { channelModel } = makeTestRig();
        channelModel.bounds_max = Vector3.Zero();
        channelModel.setupFromData(dataV0);
        expect(channelModel.bounds_max).toEqual(new Vector3(1, 2, 3));
    });
    it("Applies the min bounds", () => {
        const { channelModel } = makeTestRig();
        channelModel.bounds_min = Vector3.Zero();
        channelModel.setupFromData(dataV0);
        expect(channelModel.bounds_min).toEqual(new Vector3(4, 5, 6));
    });
});
//# sourceMappingURL=ChannelModel.test.js.map