import { makeAppObjectRepo } from "@vived/core";
import { Angle, ParametricLine, Quaternion, Vector3 } from "@vived/core";
import { makeStylusEntity, StylusEntity, } from "./StylusEntity";
class MockController {
    constructor() {
        this.onButtonDown = jest.fn();
        this.onButtonUp = jest.fn();
        this.onStylusMove = jest.fn();
        this.onButtonClick = jest.fn();
    }
}
function makeTestRig() {
    const appObjects = makeAppObjectRepo();
    const stylusAO = appObjects.getOrCreate("stylus");
    const stylus = makeStylusEntity(stylusAO);
    const observer = jest.fn();
    stylus.addChangeObserver(observer);
    const controller = new MockController();
    stylus.registerController(controller);
    return { stylus, controller, observer };
}
describe("Stylus Entity", () => {
    it("Forwards a press to the controller", () => {
        const { stylus, controller } = makeTestRig();
        stylus.updateButtonState(1, true);
        expect(controller.onButtonDown).toHaveBeenCalledWith(1);
        stylus.updateButtonState(1, false);
        expect(controller.onButtonUp).toHaveBeenCalledWith(1);
    });
    it("Only forwards if there is a change", () => {
        const { stylus, controller } = makeTestRig();
        stylus.updateButtonState(1, false);
        stylus.updateButtonState(1, false);
        stylus.updateButtonState(1, false);
        expect(controller.onButtonUp).not.toHaveBeenCalled();
        stylus.updateButtonState(1, true);
        controller.onButtonDown.mockClear();
        stylus.updateButtonState(1, true);
        stylus.updateButtonState(1, true);
        stylus.updateButtonState(1, true);
        expect(controller.onButtonUp).not.toHaveBeenCalled();
    });
    it("Forms the parametric line as expected", () => {
        const { stylus } = makeTestRig();
        stylus.transform.localPosition = Vector3.Zero();
        stylus.transform.localRotation = Quaternion.Identity();
        let rayPoint = ParametricLine.GetPointAtDistance(stylus.pickRay, 1);
        let expectedPoint = new Vector3(0, 0, 1);
        expect(Vector3.Close(rayPoint, expectedPoint)).toBeTruthy();
        stylus.transform.localRotation = Quaternion.FromAngleAxis(Vector3.Up(), Angle.FromDegrees(90));
        rayPoint = ParametricLine.GetPointAtDistance(stylus.pickRay, 1);
        expectedPoint = new Vector3(1, 0, 0);
        expect(Vector3.Close(rayPoint, expectedPoint)).toBeTruthy();
        stylus.transform.localPosition = new Vector3(1, 2, 3);
        rayPoint = ParametricLine.GetPointAtDistance(stylus.pickRay, 1);
        expectedPoint = new Vector3(2, 2, 3);
        expect(Vector3.Close(rayPoint, expectedPoint)).toBeTruthy();
    });
    it("Triggers the controller move when the transform position changes", () => {
        const { stylus, controller } = makeTestRig();
        stylus.transform.localPosition = new Vector3(1, 2, 3);
        expect(controller.onStylusMove).toHaveBeenCalled();
    });
    it("Triggers the controller move when the transform rotation changes", () => {
        const { stylus, controller } = makeTestRig();
        stylus.transform.localRotation = new Quaternion(1, 2, 3, 4);
        expect(controller.onStylusMove).toHaveBeenCalled();
    });
    it("Triggers a button click", () => {
        const { stylus, controller } = makeTestRig();
        stylus.updateButtonState(1, true);
        stylus.updateButtonState(1, false);
        expect(controller.onButtonClick).toHaveBeenCalledWith(1);
    });
    it("Does not click if a different button is pressed", () => {
        const { stylus, controller } = makeTestRig();
        stylus.updateButtonState(1, true);
        stylus.updateButtonState(0, true);
        stylus.updateButtonState(1, false);
        expect(controller.onButtonClick).not.toHaveBeenCalled();
        stylus.updateButtonState(1, true);
        stylus.updateButtonState(2, false);
        expect(controller.onButtonClick).not.toHaveBeenCalled();
    });
    it("Does click if there is a little movement", () => {
        const { stylus, controller } = makeTestRig();
        stylus.transform.localPosition = Vector3.Zero();
        stylus.updateButtonState(1, true);
        stylus.transform.localPosition = new Vector3(StylusEntity.clickMovementThreshold * 0.99, 0, 0);
        stylus.updateButtonState(1, false);
        expect(controller.onButtonClick).toHaveBeenCalled();
    });
    it("Does not click if the movement is too great", () => {
        const { stylus, controller } = makeTestRig();
        stylus.transform.localPosition = Vector3.Zero();
        stylus.updateButtonState(1, true);
        stylus.transform.localPosition = new Vector3(StylusEntity.clickMovementThreshold, 0, 0);
        stylus.updateButtonState(1, false);
        expect(controller.onButtonClick).not.toHaveBeenCalled();
    });
    it("Does click if a little time passed", () => {
        const { stylus, controller } = makeTestRig();
        const mockDateNow = jest.fn();
        Date.now = mockDateNow;
        mockDateNow.mockReturnValue(0);
        stylus.updateButtonState(1, true);
        mockDateNow.mockReturnValue(StylusEntity.clickTimeThresholdMS - 1);
        stylus.updateButtonState(1, false);
        expect(controller.onButtonClick).toHaveBeenCalled();
    });
    it("Does not click if too much time passed", () => {
        const { stylus, controller } = makeTestRig();
        const mockDateNow = jest.fn();
        Date.now = mockDateNow;
        mockDateNow.mockReturnValue(0);
        stylus.updateButtonState(1, true);
        mockDateNow.mockReturnValue(StylusEntity.clickTimeThresholdMS + 1);
        stylus.updateButtonState(1, false);
        expect(controller.onButtonClick).not.toHaveBeenCalled();
    });
    it("Sets is in use to false", () => {
        const { stylus } = makeTestRig();
        stylus.transform.worldPosition = Vector3.Zero();
        stylus.transform.worldRotation = Quaternion.Identity();
        stylus.transform.notifyOnChange();
        expect(stylus.isInUse).toEqual(false);
    });
    it("Sets is in use to true", () => {
        const { stylus } = makeTestRig();
        stylus.transform.worldPosition = Vector3.One();
        stylus.transform.worldRotation = new Quaternion(1, 1, 1, 1);
        stylus.transform.notifyOnChange();
        expect(stylus.isInUse).toEqual(true);
    });
    it("Returns correct button states", () => {
        const { stylus } = makeTestRig();
        expect(stylus.getButtonState(0)).toBeFalsy();
        expect(stylus.getButtonState(1)).toBeFalsy();
        expect(stylus.getButtonState(2)).toBeFalsy();
        expect(stylus.getButtonState(-1)).toBeFalsy();
        expect(stylus.getButtonState(3)).toBeFalsy();
        stylus.updateButtonState(0, true);
        expect(stylus.getButtonState(0)).toBeTruthy();
        expect(stylus.getButtonState(1)).toBeFalsy();
        expect(stylus.getButtonState(2)).toBeFalsy();
        stylus.updateButtonState(0, false);
        expect(stylus.getButtonState(0)).toBeFalsy();
        stylus.updateButtonState(1, true);
        expect(stylus.getButtonState(1)).toBeTruthy();
        stylus.updateButtonState(2, true);
        expect(stylus.getButtonState(2)).toBeTruthy();
    });
});
//# sourceMappingURL=StylusEntity.test.js.map