import { makeAppObjectRepo } from "@vived/core";
import { ParametricLine, Quaternion, Vector3 } from "@vived/core";
import { makeMockPixelToSceneRayUC } from "../../Babylon";
import { makeMouseInput } from "../../MouseInput";
import { makeTouchInput } from "../../TouchController";
import { makeStylusEntity } from "../Entity/StylusEntity";
import { EmulateStylusUC, makeEmulateStylusUC } from "./EmulateStylusUC";
function makeTestRig() {
    const appObjects = makeAppObjectRepo();
    const registerSingletonSpy = jest.spyOn(appObjects, "registerSingleton");
    const mouseInput = makeMouseInput(appObjects.getOrCreate("Mouse"));
    const inputElement = document.createElement("div");
    mouseInput.setEventElement(inputElement);
    const touchInout = makeTouchInput(appObjects.getOrCreate("Touch"));
    touchInout.setEventElement(inputElement);
    const ao = appObjects.getOrCreate("Stylus");
    const stylus = makeStylusEntity(ao);
    const uc = makeEmulateStylusUC(ao);
    const mockSceneRay = makeMockPixelToSceneRayUC(appObjects);
    mockSceneRay.pixelToSceneRay.mockReturnValue(ParametricLine.FromPointDirection(new Vector3(1, 1, -1), Vector3.Forward()));
    return {
        uc,
        appObjects,
        registerSingletonSpy,
        mouseInput,
        inputElement,
        stylus,
        touchInout,
    };
}
describe("Emulate Stylus UC", () => {
    it("Registers as a singleton", () => {
        const { uc, registerSingletonSpy } = makeTestRig();
        expect(registerSingletonSpy).toHaveBeenCalledWith(uc);
    });
    it("Gets the singleton", () => {
        const { uc, appObjects } = makeTestRig();
        expect(EmulateStylusUC.get(appObjects)).toEqual(uc);
    });
    it("Can be started and stopped", () => {
        const { uc } = makeTestRig();
        expect(uc.isEmulating).toEqual(false);
        uc.startEmulating();
        expect(uc.isEmulating).toEqual(true);
        uc.stopEmulating();
        expect(uc.isEmulating).toEqual(false);
    });
    it("Steals the input element from the mouse input", () => {
        const { uc, mouseInput } = makeTestRig();
        const clearInputElementSpy = jest.spyOn(mouseInput, "clearInputElement");
        uc.startEmulating();
        expect(clearInputElementSpy).toHaveBeenCalled();
    });
    it("Only steals once", () => {
        const { uc, mouseInput } = makeTestRig();
        const clearInputElementSpy = jest.spyOn(mouseInput, "clearInputElement");
        uc.startEmulating();
        uc.startEmulating();
        uc.startEmulating();
        expect(clearInputElementSpy).toHaveBeenCalledTimes(1);
    });
    it("Clears the input element from the touch input", () => {
        const { uc, touchInout } = makeTestRig();
        const clearInputElementSpy = jest.spyOn(touchInout, "clearInputElement");
        uc.startEmulating();
        expect(clearInputElementSpy).toHaveBeenCalled();
    });
    it("Only clears once", () => {
        const { uc, touchInout } = makeTestRig();
        const clearInputElementSpy = jest.spyOn(touchInout, "clearInputElement");
        uc.startEmulating();
        uc.startEmulating();
        uc.startEmulating();
        expect(clearInputElementSpy).toHaveBeenCalledTimes(1);
    });
    it("Returns the mouse input element when stopped", () => {
        const { uc, mouseInput, inputElement } = makeTestRig();
        const setElementSpy = jest.spyOn(mouseInput, "setEventElement");
        uc.startEmulating();
        uc.stopEmulating();
        expect(setElementSpy).toHaveBeenCalledWith(inputElement);
    });
    it("Only returns to the mouse once", () => {
        const { uc, mouseInput } = makeTestRig();
        const setElementSpy = jest.spyOn(mouseInput, "setEventElement");
        uc.startEmulating();
        uc.stopEmulating();
        uc.stopEmulating();
        uc.stopEmulating();
        uc.stopEmulating();
        expect(setElementSpy).toHaveBeenCalledTimes(1);
    });
    it("Returns the touch input element when stopped", () => {
        const { uc, touchInout, inputElement } = makeTestRig();
        const setElementSpy = jest.spyOn(touchInout, "setEventElement");
        uc.startEmulating();
        uc.stopEmulating();
        expect(setElementSpy).toHaveBeenCalledWith(inputElement);
    });
    it("Only returns to the touch once", () => {
        const { uc, touchInout } = makeTestRig();
        const setElementSpy = jest.spyOn(touchInout, "setEventElement");
        uc.startEmulating();
        uc.stopEmulating();
        uc.stopEmulating();
        uc.stopEmulating();
        uc.stopEmulating();
        expect(setElementSpy).toHaveBeenCalledTimes(1);
    });
    it("Sends mouse down to the stylus", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        stylus.updateButtonState = jest.fn();
        uc.startEmulating();
        const e = new MouseEvent("mousedown", { button: 1 });
        inputElement.dispatchEvent(e);
        expect(stylus.updateButtonState).toHaveBeenCalledWith(1, true);
    });
    it("Stops sending mouse down after stopped", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        stylus.updateButtonState = jest.fn();
        uc.startEmulating();
        uc.stopEmulating();
        const e = new MouseEvent("mousedown", { button: 1 });
        inputElement.dispatchEvent(e);
        expect(stylus.updateButtonState).not.toHaveBeenCalled();
    });
    it("Sends mouse up to the stylus", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        stylus.updateButtonState = jest.fn();
        uc.startEmulating();
        const e = new MouseEvent("mouseup", { button: 1 });
        inputElement.dispatchEvent(e);
        expect(stylus.updateButtonState).toHaveBeenCalledWith(1, false);
    });
    it("Stops sending mouse up after stopped", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        stylus.updateButtonState = jest.fn();
        uc.startEmulating();
        uc.stopEmulating();
        const e = new MouseEvent("mouseup", { button: 1 });
        inputElement.dispatchEvent(e);
        expect(stylus.updateButtonState).not.toHaveBeenCalled();
    });
    it("Rotates the stylus on mouse move", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        stylus.transform.worldRotation = Quaternion.Identity();
        uc.startEmulating();
        const e = new MouseEvent("mousemove", { clientX: 10, clientY: 10 });
        inputElement.dispatchEvent(e);
        expect(stylus.transform.worldRotation).not.toEqual(Quaternion.Identity());
    });
    it("Stops rotating the stylus on mouse move", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        stylus.transform.worldRotation = Quaternion.Identity();
        uc.startEmulating();
        uc.stopEmulating();
        const e = new MouseEvent("mousemove", { clientX: 10, clientY: 10 });
        inputElement.dispatchEvent(e);
        inputElement.dispatchEvent(e);
        inputElement.dispatchEvent(e);
        expect(stylus.transform.worldRotation).toEqual(Quaternion.Identity());
    });
    it("Bumps to the left when A is pressed", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        uc.startEmulating();
        stylus.transform.worldPosition = Vector3.Zero();
        stylus.transform.worldRotation = Quaternion.Identity();
        const downEvent = new KeyboardEvent("keydown", { code: "KeyA" });
        inputElement.dispatchEvent(downEvent);
        expect(stylus.transform.worldPosition.x).toBeLessThan(0);
        expect(stylus.transform.worldRotation).not.toEqual(Quaternion.Identity());
    });
    it("Stops bumping to the left when A is pressed", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        uc.startEmulating();
        stylus.transform.worldPosition = Vector3.Zero();
        uc.stopEmulating();
        const downEvent = new KeyboardEvent("keydown", { code: "KeyA" });
        inputElement.dispatchEvent(downEvent);
        expect(stylus.transform.worldPosition.x).toEqual(0);
    });
    it("Bumps to the right when D is pressed", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        uc.startEmulating();
        stylus.transform.worldPosition = Vector3.Zero();
        stylus.transform.worldRotation = Quaternion.Identity();
        const downEvent = new KeyboardEvent("keydown", { code: "KeyD" });
        inputElement.dispatchEvent(downEvent);
        expect(stylus.transform.worldPosition.x).toBeGreaterThan(0);
        expect(stylus.transform.worldRotation).not.toEqual(Quaternion.Identity());
    });
    it("Stops bumping to the right when D is pressed", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        uc.startEmulating();
        stylus.transform.worldPosition = Vector3.Zero();
        uc.stopEmulating();
        const downEvent = new KeyboardEvent("keydown", { code: "KeyD" });
        inputElement.dispatchEvent(downEvent);
        expect(stylus.transform.worldPosition.x).toEqual(0);
    });
    it("Bumps down when S is pressed", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        uc.startEmulating();
        stylus.transform.worldPosition = Vector3.Zero();
        stylus.transform.worldRotation = Quaternion.Identity();
        const downEvent = new KeyboardEvent("keydown", { code: "KeyS" });
        inputElement.dispatchEvent(downEvent);
        expect(stylus.transform.worldPosition.z).toBeLessThan(0);
        expect(stylus.transform.worldRotation).not.toEqual(Quaternion.Identity());
    });
    it("Stops bumping when S is pressed", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        uc.startEmulating();
        stylus.transform.worldPosition = Vector3.Zero();
        uc.stopEmulating();
        const downEvent = new KeyboardEvent("keydown", { code: "KeyS" });
        inputElement.dispatchEvent(downEvent);
        expect(stylus.transform.worldPosition.z).toEqual(0);
    });
    it("Bumps up when W is pressed", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        uc.startEmulating();
        stylus.transform.worldPosition = Vector3.Zero();
        stylus.transform.worldRotation = Quaternion.Identity();
        const downEvent = new KeyboardEvent("keydown", { code: "KeyW" });
        inputElement.dispatchEvent(downEvent);
        expect(stylus.transform.worldPosition.z).toBeGreaterThan(0);
        expect(stylus.transform.worldRotation).not.toEqual(Quaternion.Identity());
    });
    it("Stops bumping when W is pressed", () => {
        const { uc, inputElement, stylus } = makeTestRig();
        uc.startEmulating();
        stylus.transform.worldPosition = Vector3.Zero();
        uc.stopEmulating();
        const downEvent = new KeyboardEvent("keydown", { code: "KeyW" });
        inputElement.dispatchEvent(downEvent);
        expect(stylus.transform.worldPosition.z).toEqual(0);
    });
});
//# sourceMappingURL=EmulateStylusUC.test.js.map