import { makeAppObjectRepo } from "@vived/core";
import { Vector2 } from "@vived/core";
import { LabelDropDragMode, makeLabelDropRepo, LabelDropRepo, } from "./LabelDropRepo";
function makeTestRig() {
    const appObjects = makeAppObjectRepo();
    const registerSpy = jest.spyOn(appObjects, "registerSingleton");
    const labelDropAO = appObjects.getOrCreate("labelDrop");
    const labelDrop = makeLabelDropRepo(labelDropAO);
    const changeObserver = jest.fn();
    labelDrop.addChangeObserver(changeObserver);
    const submissionObserver = jest.fn();
    labelDrop.addLabelDropSubmissionObserver(submissionObserver);
    return {
        appObjects,
        labelDrop,
        changeObserver,
        submissionObserver,
        registerSpy,
    };
}
describe("Label Drop Repo", () => {
    it("Gets the singleton", () => {
        const { appObjects, labelDrop } = makeTestRig();
        expect(LabelDropRepo.get(appObjects)).toEqual(labelDrop);
    });
    it("Registers as the singleton", () => {
        const { registerSpy, labelDrop } = makeTestRig();
        expect(registerSpy).toHaveBeenCalledWith(labelDrop);
    });
    it("Makes a label drop item", () => {
        const { labelDrop } = makeTestRig();
        const item = labelDrop.makeLabelDropItem();
        expect(labelDrop.hasForAppObject(item.id)).toEqual(true);
    });
    it("Makes a label drop item with a known ID", () => {
        const { labelDrop } = makeTestRig();
        labelDrop.makeLabelDropItem("someID");
        expect(labelDrop.hasForAppObject("someID")).toEqual(true);
    });
    it("Can submit a correct label drop answer", () => {
        const { labelDrop, changeObserver, submissionObserver } = makeTestRig();
        const dropItem = labelDrop.makeLabelDropItem("labelDropId");
        dropItem.targetIds = ["obj1", "obj2"];
        expect(labelDrop.getRemainingLabelDrops().length).toEqual(1);
        submissionObserver.mockClear();
        changeObserver.mockClear();
        labelDrop.submitLabelDrop("labelDropId", "obj2");
        const result = {
            id: "labelDropId",
            isCorrect: true,
        };
        expect(submissionObserver).toHaveBeenCalledWith(result);
        expect(changeObserver).toHaveBeenCalled();
        expect(labelDrop.getRemainingLabelDrops().length).toEqual(0);
        expect(labelDrop.resultIsCorrect).toEqual(true);
    });
    it("Can submit an incorrect label drop answer", () => {
        const { labelDrop, changeObserver, submissionObserver } = makeTestRig();
        const dropItem = labelDrop.makeLabelDropItem("labelDropId");
        dropItem.targetIds = ["obj1", "obj2"];
        expect(labelDrop.getRemainingLabelDrops().length).toEqual(1);
        submissionObserver.mockClear();
        changeObserver.mockClear();
        labelDrop.submitLabelDrop("labelDropId", "obj3");
        const result = {
            id: "labelDropId",
            isCorrect: false,
        };
        expect(submissionObserver).toHaveBeenCalledWith(result);
        expect(changeObserver).toHaveBeenCalled();
        expect(labelDrop.getRemainingLabelDrops().length).toEqual(1);
        expect(labelDrop.getRemainingLabelDrops()[0]).toEqual("labelDropId");
        expect(labelDrop.resultIsCorrect).toEqual(false);
    });
    it("Resets the items and notifies", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        const dropItem = labelDrop.makeLabelDropItem("labelDropId");
        dropItem.reset = jest.fn();
        changeObserver.mockClear();
        labelDrop.reset();
        expect(changeObserver).toHaveBeenCalled();
        expect(dropItem.reset).toHaveBeenCalled();
    });
    it("Can set the id of label drop to edit", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        const id = "labelDropId";
        labelDrop.makeLabelDropItem("labelDropId");
        expect(labelDrop.editingID).toBeUndefined();
        changeObserver.mockClear();
        labelDrop.editingID = id;
        expect(labelDrop.editingID).toEqual(id);
        expect(changeObserver).toHaveBeenCalled();
    });
    it("Does not change editing id if it is not found", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        expect(labelDrop.editingID).toBeUndefined();
        changeObserver.mockClear();
        labelDrop.editingID = "fake id";
        expect(labelDrop.editingID).toEqual(undefined);
        expect(changeObserver).not.toHaveBeenCalled();
    });
    it("Can reset the id of label drop to edit back to undefined", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        labelDrop.makeLabelDropItem("labelDropId");
        labelDrop.editingID = "labelDropId";
        expect(labelDrop.editingID).not.toBeUndefined();
        changeObserver.mockClear();
        labelDrop.editingID = undefined;
        expect(labelDrop.editingID).toEqual(undefined);
        expect(changeObserver).toHaveBeenCalled();
    });
    it("Drag mode initializes as SCREEN after construction", () => {
        const { labelDrop } = makeTestRig();
        expect(labelDrop.dragMode).toEqual(LabelDropDragMode.SCREEN);
    });
    it("Can set drag mode", () => {
        const { labelDrop } = makeTestRig();
        const newMode = LabelDropDragMode.WORLD;
        expect(labelDrop.dragMode).not.toEqual(newMode);
        labelDrop.dragMode = newMode;
        expect(labelDrop.dragMode).toEqual(newMode);
    });
    it("Notifies once when drag mode updates", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        const newMode = LabelDropDragMode.WORLD;
        expect(labelDrop.dragMode).not.toEqual(newMode);
        labelDrop.dragMode = newMode;
        labelDrop.dragMode = newMode;
        labelDrop.dragMode = newMode;
        expect(changeObserver).toHaveBeenCalledTimes(1);
    });
    it("Doesn't notify when drag mode is set but value hasn't change", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        const mode = LabelDropDragMode.WORLD;
        labelDrop.dragMode = mode;
        expect(labelDrop.dragMode).toEqual(mode);
        changeObserver.mockClear();
        labelDrop.dragMode = mode;
        labelDrop.dragMode = mode;
        labelDrop.dragMode = mode;
        expect(changeObserver).not.toHaveBeenCalled();
    });
    it("Result initializes as undefined after construction", () => {
        const { labelDrop } = makeTestRig();
        expect(labelDrop.resultIsCorrect).toBeUndefined();
    });
    it("Can set result value", () => {
        const { labelDrop } = makeTestRig();
        const testValue = true;
        expect(labelDrop.resultIsCorrect).not.toEqual(testValue);
        labelDrop.resultIsCorrect = testValue;
        expect(labelDrop.resultIsCorrect).toEqual(testValue);
    });
    it("Notifies once if result value changes", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        const newValue = true;
        expect(labelDrop.resultIsCorrect).not.toEqual(newValue);
        labelDrop.resultIsCorrect = newValue;
        labelDrop.resultIsCorrect = newValue;
        labelDrop.resultIsCorrect = newValue;
        expect(changeObserver).toHaveBeenCalledTimes(1);
    });
    it("Doesn't notify when result is set but value hasn't change", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        const testValue = true;
        labelDrop.resultIsCorrect = testValue;
        expect(labelDrop.resultIsCorrect).toEqual(testValue);
        changeObserver.mockClear();
        labelDrop.resultIsCorrect = testValue;
        labelDrop.resultIsCorrect = testValue;
        labelDrop.resultIsCorrect = testValue;
        expect(changeObserver).not.toHaveBeenCalled();
    });
    it("Initializes drag alpha value to 0 after construction", () => {
        const { labelDrop } = makeTestRig();
        expect(labelDrop.dragAlpha).toEqual(0);
    });
    it("Can set drag alpha value", () => {
        const { labelDrop } = makeTestRig();
        const testNumber = 0.1234;
        expect(labelDrop.dragAlpha).not.toEqual(testNumber);
        labelDrop.dragAlpha = testNumber;
        expect(labelDrop.dragAlpha).toEqual(testNumber);
    });
    it("Notifies once if drag alpha changes", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        const testNumber = 0.1234;
        expect(labelDrop.dragAlpha).not.toEqual(testNumber);
        labelDrop.dragAlpha = testNumber;
        labelDrop.dragAlpha = testNumber;
        labelDrop.dragAlpha = testNumber;
        expect(changeObserver).toHaveBeenCalledTimes(1);
    });
    it("Doesn't notify when drag alpha is set but value hasn't change", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        const testNumber = 0.1234;
        labelDrop.dragAlpha = testNumber;
        expect(labelDrop.dragAlpha).toEqual(testNumber);
        changeObserver.mockClear();
        labelDrop.dragAlpha = testNumber;
        labelDrop.dragAlpha = testNumber;
        labelDrop.dragAlpha = testNumber;
        expect(changeObserver).not.toHaveBeenCalled();
    });
    it("Clamps drag alpha values greater than 1 to 1", () => {
        const { labelDrop } = makeTestRig();
        labelDrop.dragAlpha = 0.5;
        expect(labelDrop.dragAlpha).toEqual(0.5);
        labelDrop.dragAlpha = 100;
        labelDrop.dragAlpha = 100;
        labelDrop.dragAlpha = 100;
        expect(labelDrop.dragAlpha).toEqual(1);
    });
    it("Clamps drag alpha values less than 0 to 0", () => {
        const { labelDrop } = makeTestRig();
        labelDrop.dragAlpha = 0.5;
        expect(labelDrop.dragAlpha).toEqual(0.5);
        labelDrop.dragAlpha = -1;
        labelDrop.dragAlpha = -1;
        labelDrop.dragAlpha = -1;
        expect(labelDrop.dragAlpha).toEqual(0);
    });
    it("Initializes screen position upon construction", () => {
        const { labelDrop } = makeTestRig();
        expect(labelDrop.screenPosition).toEqual(Vector2.Zero());
    });
    it("Can set screen position", () => {
        const { labelDrop } = makeTestRig();
        const newVector = new Vector2(100, 200);
        expect(labelDrop.screenPosition).not.toEqual(newVector);
        labelDrop.screenPosition = newVector;
        expect(labelDrop.screenPosition).toEqual(newVector);
    });
    it("Notifies once if screen position changes", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        const newVector = new Vector2(100, 200);
        expect(labelDrop.screenPosition).not.toEqual(newVector);
        labelDrop.screenPosition = newVector;
        labelDrop.screenPosition = newVector;
        labelDrop.screenPosition = newVector;
        expect(changeObserver).toHaveBeenCalledTimes(1);
    });
    it("Doesn't notify when screen position is set but its value hasn't change", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        const vector = new Vector2(100, 200);
        labelDrop.screenPosition = vector;
        expect(labelDrop.screenPosition).toEqual(vector);
        changeObserver.mockClear();
        labelDrop.screenPosition = vector;
        labelDrop.screenPosition = vector;
        labelDrop.screenPosition = vector;
        expect(changeObserver).not.toHaveBeenCalled();
    });
    it("Sets up the drag helper transform", () => {
        const { labelDrop } = makeTestRig();
        expect(labelDrop.dragHelperTransform).toBeDefined();
        expect(labelDrop.dragHelperTransform.appObject).toBeDefined();
        expect(labelDrop.dragHelperTransform.appObject.id).toEqual("LabelDropDragHelper");
    });
    it("Initializes isEditingNewAnswer as false after construction", () => {
        const { labelDrop } = makeTestRig();
        expect(labelDrop.isEditingNewAnswer).toBe(false);
    });
    it("Can set isEditingNewAnswer value", () => {
        const { labelDrop } = makeTestRig();
        expect(labelDrop.isEditingNewAnswer).not.toEqual(true);
        labelDrop.isEditingNewAnswer = true;
        expect(labelDrop.isEditingNewAnswer).toEqual(true);
    });
    it("Notifies once if isEditingNewAnswer changes", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        expect(labelDrop.isEditingNewAnswer).not.toEqual(true);
        labelDrop.isEditingNewAnswer = true;
        labelDrop.isEditingNewAnswer = true;
        labelDrop.isEditingNewAnswer = true;
        expect(changeObserver).toHaveBeenCalledTimes(1);
    });
    it("Doesn't notify when isEditingNewAnswer is set but value hasn't change", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        labelDrop.isEditingNewAnswer = true;
        expect(labelDrop.isEditingNewAnswer).toEqual(true);
        changeObserver.mockClear();
        labelDrop.isEditingNewAnswer = true;
        labelDrop.isEditingNewAnswer = true;
        labelDrop.isEditingNewAnswer = true;
        expect(changeObserver).not.toHaveBeenCalled();
    });
    it("Returns a validation message if there are no drop items", () => {
        const { labelDrop } = makeTestRig();
        expect(labelDrop.validationMessage).toEqual(LabelDropRepo.LABEL_DROP_ANSWER_REQUIRED);
        labelDrop.makeLabelDropItem();
        expect(labelDrop.validationMessage).toBeNull();
    });
    it("Disposes the app object when it is deleted", () => {
        const { labelDrop } = makeTestRig();
        const item = labelDrop.makeLabelDropItem("item1");
        item.appObject.dispose = jest.fn();
        labelDrop.deleteItem("item1");
        expect(item.appObject.dispose).toHaveBeenCalled();
        expect(labelDrop.hasForAppObject("item1")).toEqual(false);
    });
    it("Notifies when an item is deleted", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        const item = labelDrop.makeLabelDropItem("item1");
        item.appObject.dispose = jest.fn();
        changeObserver.mockClear();
        labelDrop.deleteItem("item1");
        labelDrop.deleteItem("item1");
        labelDrop.deleteItem("item1");
        labelDrop.deleteItem("item1");
        expect(changeObserver).toHaveBeenCalledTimes(1);
    });
    it("Disposes the app object when all are deleted", () => {
        const { labelDrop } = makeTestRig();
        const item = labelDrop.makeLabelDropItem("item1");
        item.appObject.dispose = jest.fn();
        labelDrop.deleteAllItems();
        expect(item.appObject.dispose).toHaveBeenCalled();
        expect(labelDrop.hasForAppObject("item1")).toEqual(false);
    });
    it("Notifies when all items are deleted", () => {
        const { labelDrop, changeObserver } = makeTestRig();
        const item = labelDrop.makeLabelDropItem("item1");
        item.appObject.dispose = jest.fn();
        changeObserver.mockClear();
        labelDrop.deleteAllItems();
        labelDrop.deleteAllItems();
        labelDrop.deleteAllItems();
        labelDrop.deleteAllItems();
        expect(changeObserver).toHaveBeenCalledTimes(1);
    });
});
//# sourceMappingURL=LabelDropRepo.test.js.map