import { makeAppObjectRepo } from "@vived/core";
import { makeMouseInput, MouseInputEntity, } from "./MouseInput";
class MockController {
    constructor() {
        this.onClick = jest.fn();
        this.onDown = jest.fn();
        this.onUp = jest.fn();
        this.onMove = jest.fn();
        this.onWheel = jest.fn();
        this.onDoubleClick = jest.fn();
    }
}
function makeTestRig() {
    const appObjects = makeAppObjectRepo();
    const ao = appObjects.getOrCreate("App");
    const mouseInput = makeMouseInput(ao);
    const mockController = new MockController();
    mouseInput.registerController(mockController);
    const element = document.createElement("div");
    mouseInput.setEventElement(element);
    return { mouseInput, mockController, element, appObjects };
}
describe("Mouse input", () => {
    it("Sets the element", () => {
        const { mouseInput, element } = makeTestRig();
        expect(mouseInput.eventElement).toEqual(element);
    });
    it("Clears the element", () => {
        const { mouseInput, element } = makeTestRig();
        expect(mouseInput.eventElement).toEqual(element);
        mouseInput.clearInputElement();
        expect(mouseInput.eventElement).toBeUndefined();
    });
    it("Allows a controller to be removed", () => {
        const { element, mockController, mouseInput } = makeTestRig();
        mouseInput.removeController(mockController);
        const e = new MouseEvent("mousedown");
        element.dispatchEvent(e);
        expect(mockController.onDown).not.toHaveBeenCalled();
    });
    it("Gets the entity", () => {
        const { mouseInput, appObjects } = makeTestRig();
        expect(MouseInputEntity.get(appObjects)).toEqual(mouseInput);
    });
    it("Warns if it cannot find the entity", () => {
        const { mouseInput, appObjects } = makeTestRig();
        console.warn = jest.fn();
        mouseInput.dispose();
        expect(MouseInputEntity.get(appObjects)).toEqual(undefined);
        expect(console.warn).toHaveBeenCalled();
    });
    it("Warns if it finds multiple entity", () => {
        const { mouseInput, appObjects } = makeTestRig();
        const anotherAO = appObjects.getOrCreate("anotherAppObject");
        makeMouseInput(anotherAO);
        console.warn = jest.fn();
        expect(MouseInputEntity.get(appObjects)).toEqual(mouseInput);
        expect(console.warn).toHaveBeenCalled();
    });
});
describe("Mouse scene input - On Down", () => {
    it("Notifies controller with the event", () => {
        const { element, mockController } = makeTestRig();
        const e = new MouseEvent("mousedown", { button: 1 });
        element.dispatchEvent(e);
        const inputEvent = mockController.onDown.mock
            .calls[0][0];
        expect(inputEvent.event).toEqual(e);
        expect(inputEvent.button).toEqual(1);
    });
    it("Removes event listener when the element is cleared", () => {
        const { element, mockController, mouseInput } = makeTestRig();
        mouseInput.clearInputElement();
        const e = new MouseEvent("mousedown");
        element.dispatchEvent(e);
        expect(mockController.onDown).not.toHaveBeenCalled();
    });
    it("Removes event listener when the element is changed", () => {
        const { element, mockController, mouseInput } = makeTestRig();
        const newElement = document.createElement("div");
        mouseInput.setEventElement(newElement);
        const e = new MouseEvent("mousedown");
        element.dispatchEvent(e);
        expect(mockController.onDown).not.toHaveBeenCalled();
    });
});
describe("Mouse scene input - On Up", () => {
    it("Notifies controller with the event", () => {
        const { element, mockController } = makeTestRig();
        const e = new MouseEvent("mouseup", { button: 1 });
        element.dispatchEvent(e);
        const inputEvent = mockController.onUp.mock.calls[0][0];
        expect(inputEvent.event).toEqual(e);
        expect(inputEvent.button).toEqual(1);
    });
    it("Removed event listener when the element is cleared", () => {
        const { element, mockController, mouseInput } = makeTestRig();
        mouseInput.clearInputElement();
        const e = new MouseEvent("mouseup");
        element.dispatchEvent(e);
        expect(mockController.onUp).not.toHaveBeenCalled();
    });
    it("Removed event listener when the element is changed", () => {
        const { element, mockController, mouseInput } = makeTestRig();
        const newElement = document.createElement("div");
        mouseInput.setEventElement(newElement);
        const e = new MouseEvent("mouseup");
        element.dispatchEvent(e);
        expect(mockController.onUp).not.toHaveBeenCalled();
    });
});
describe("Mouse scene input - Move", () => {
    it("Notifies controller with the event", () => {
        const { element, mockController } = makeTestRig();
        const e = new MouseEvent("mousemove");
        element.dispatchEvent(e);
        const inputEvent = mockController.onMove.mock
            .calls[0][0];
        expect(inputEvent.event).toEqual(e);
    });
    it("Removed event listener when the element is cleared", () => {
        const { element, mockController, mouseInput } = makeTestRig();
        mouseInput.clearInputElement();
        const e = new MouseEvent("mousemove");
        element.dispatchEvent(e);
        expect(mockController.onMove).not.toHaveBeenCalled();
    });
    it("Removed event listener when the element is changed", () => {
        const { element, mockController, mouseInput } = makeTestRig();
        const newElement = document.createElement("div");
        mouseInput.setEventElement(newElement);
        const e = new MouseEvent("mousemove");
        element.dispatchEvent(e);
        expect(mockController.onMove).not.toHaveBeenCalled();
    });
});
describe("Mouse scene input - Mouse Leave", () => {
    it("Treats a mouse out like a mouse up if there is a presss", () => {
        const { element, mockController } = makeTestRig();
        const down = new MouseEvent("mousedown");
        element.dispatchEvent(down);
        const out = new MouseEvent("mouseout");
        element.dispatchEvent(out);
        const inputEvent = mockController.onUp.mock.calls[0][0];
        expect(inputEvent.event).toEqual(out);
    });
    it("Does nothing on leave if there is not a press", () => {
        const { element, mockController } = makeTestRig();
        const out = new MouseEvent("mouseout");
        element.dispatchEvent(out);
        expect(mockController.onUp).not.toHaveBeenCalled();
    });
});
describe("Mouse scene input - Click", () => {
    it("Notifies controller with the event", () => {
        const { element, mockController } = makeTestRig();
        const down = new MouseEvent("mousedown");
        element.dispatchEvent(down);
        const up = new MouseEvent("mouseup");
        element.dispatchEvent(up);
        const inputEvent = mockController.onClick.mock
            .calls[0][0];
        expect(inputEvent.event).toEqual(up);
    });
    it("Does not register a click if the up is too far away", () => {
        const { element, mockController } = makeTestRig();
        const down = new MouseEvent("mousedown", { screenX: 0, screenY: 0 });
        element.dispatchEvent(down);
        const up = new MouseEvent("mouseup", { screenX: 5, screenY: 5 });
        element.dispatchEvent(up);
        expect(mockController.onClick).not.toHaveBeenCalled();
    });
    it("Does not register a click if there is too much movement", () => {
        const { element, mockController } = makeTestRig();
        const down = new MouseEvent("mousedown", { screenX: 0, screenY: 0 });
        element.dispatchEvent(down);
        const move = new MouseEvent("mousemove", { screenX: 5, screenY: 5 });
        element.dispatchEvent(move);
        const up = new MouseEvent("mouseup", { screenX: 0, screenY: 0 });
        element.dispatchEvent(up);
        expect(mockController.onClick).not.toHaveBeenCalled();
    });
    it("Does not register a click if the mouse leaves", () => {
        const { element, mockController } = makeTestRig();
        const down = new MouseEvent("mousedown", { screenX: 0, screenY: 0 });
        element.dispatchEvent(down);
        const leave = new MouseEvent("mouseout");
        element.dispatchEvent(leave);
        const up = new MouseEvent("mouseup", { screenX: 0, screenY: 0 });
        element.dispatchEvent(up);
        expect(mockController.onClick).not.toHaveBeenCalled();
    });
});
describe("Mouse scene input - Wheel", () => {
    it("Notifies controller with the event", () => {
        const { element, mockController } = makeTestRig();
        const e = new WheelEvent("wheel");
        element.dispatchEvent(e);
        const inputEvent = mockController.onWheel.mock
            .calls[0][0];
        expect(inputEvent.event).toEqual(e);
    });
    it("Removed event listener when the element is cleared", () => {
        const { element, mockController, mouseInput } = makeTestRig();
        mouseInput.clearInputElement();
        const e = new WheelEvent("wheel");
        element.dispatchEvent(e);
        expect(mockController.onWheel).not.toHaveBeenCalled();
    });
    it("Removed event listener when the element is changed", () => {
        const { element, mockController, mouseInput } = makeTestRig();
        const newElement = document.createElement("div");
        mouseInput.setEventElement(newElement);
        const e = new WheelEvent("wheel");
        element.dispatchEvent(e);
        expect(mockController.onWheel).not.toHaveBeenCalled();
    });
});
describe("Mouse scene input - Double Click", () => {
    it("Notifies controller with the event", () => {
        const { element, mockController } = makeTestRig();
        const down = new MouseEvent("mousedown", { screenX: 0, screenY: 0 });
        element.dispatchEvent(down);
        const up = new MouseEvent("mouseup", { screenX: 0, screenY: 0 });
        element.dispatchEvent(up);
        element.dispatchEvent(down);
        element.dispatchEvent(up);
        expect(mockController.onDoubleClick).toHaveBeenCalledTimes(1);
        const inputEvent = mockController.onDoubleClick.mock
            .calls[0][0];
        expect(inputEvent.event).toEqual(up);
    });
    it("Does not register  click if the second click is too far away", () => {
        const { element, mockController } = makeTestRig();
        const down = new MouseEvent("mousedown", { screenX: 0, screenY: 0 });
        element.dispatchEvent(down);
        const up = new MouseEvent("mouseup", { screenX: 0, screenY: 0 });
        element.dispatchEvent(up);
        const down2 = new MouseEvent("mousedown", { screenX: 10, screenY: 10 });
        element.dispatchEvent(down2);
        const up2 = new MouseEvent("mouseup", { screenX: 10, screenY: 10 });
        element.dispatchEvent(up2);
        expect(mockController.onDoubleClick).not.toHaveBeenCalled();
    });
    it("Doesn't get out of sequecne", () => {
        const { element, mockController } = makeTestRig();
        const mockTime = jest.fn();
        Date.now = mockTime;
        mockTime.mockReturnValue(0);
        const down = new MouseEvent("mousedown", { screenX: 0, screenY: 0 });
        const up = new MouseEvent("mouseup", { screenX: 0, screenY: 0 });
        element.dispatchEvent(down);
        element.dispatchEvent(up);
        mockTime.mockReturnValue(1000);
        element.dispatchEvent(down);
        element.dispatchEvent(up);
        mockTime.mockReturnValue(1001);
        element.dispatchEvent(down);
        element.dispatchEvent(up);
        expect(mockController.onDoubleClick).toHaveBeenCalledTimes(1);
    });
    it("Does not register if it takes too long", () => {
        const { element, mockController } = makeTestRig();
        const mockTime = jest.fn();
        Date.now = mockTime;
        mockTime.mockReturnValue(0);
        const down = new MouseEvent("mousedown", { screenX: 0, screenY: 0 });
        element.dispatchEvent(down);
        const up = new MouseEvent("mouseup", { screenX: 0, screenY: 0 });
        element.dispatchEvent(up);
        mockTime.mockReturnValue(1000);
        element.dispatchEvent(down);
        element.dispatchEvent(up);
        expect(mockController.onDoubleClick).not.toHaveBeenCalled();
    });
    it("Does not register a double click if the mouse leaves", () => {
        const { element, mockController } = makeTestRig();
        const down = new MouseEvent("mousedown", { screenX: 0, screenY: 0 });
        element.dispatchEvent(down);
        const up = new MouseEvent("mouseup", { screenX: 0, screenY: 0 });
        element.dispatchEvent(up);
        const leave = new MouseEvent("mouseout");
        element.dispatchEvent(leave);
        element.dispatchEvent(down);
        element.dispatchEvent(up);
        expect(mockController.onDoubleClick).not.toHaveBeenCalled();
    });
});
//# sourceMappingURL=MouseInput.test.js.map