import {
  useMapResizeKeybindings,
  useRoundTimer,
} from "../components/screens/GamePanel/GuessPane/hooks";

jest.mock("react");
jest.mock("../domain/gameStore");

import { useEffect, useState } from "react";
import { dispatch, useRoundSeconds } from "../domain/gameStore";

describe("GuessPane hooks", () => {
  describe("useMapResizeKeybindings", () => {
    document.addEventListener = jest.fn();
    document.removeEventListener = jest.fn();

    it("attaches key listener on mount and removes them on unmount", () => {
      let listener;
      document.addEventListener.mockImplementation((_, fn) => {
        listener = fn;
      });
      let cleanup;
      useEffect.mockImplementation(fn => {
        cleanup = fn();
      });
      const toggleMapSize = jest.fn();
      useMapResizeKeybindings(toggleMapSize);
      expect(document.addEventListener).toHaveBeenCalledWith(
        "keydown",
        listener,
        false
      );
      listener({ code: "Escape" });
      expect(toggleMapSize).toHaveBeenCalled();
      cleanup();
      expect(document.removeEventListener).toHaveBeenCalledWith(
        "keydown",
        listener,
        false
      );
    });
    it("attaches key listener that only listens on escape", () => {
      let listener;
      document.addEventListener.mockImplementation((_, fn) => {
        listener = fn;
      });
      let cleanup;
      useEffect.mockImplementation(fn => {
        cleanup = fn();
      });
      const toggleMapSize = jest.fn();
      useMapResizeKeybindings(toggleMapSize);
      expect(document.addEventListener).toHaveBeenCalledWith(
        "keydown",
        listener,
        false
      );
      listener({ code: "Enter" });
      expect(toggleMapSize).not.toHaveBeenCalled();
    });
  });
  describe("useRoundTimer", () => {
    beforeEach(() => {
      useEffect.mockImplementation(f => {
        const cleanup = f();
        if (cleanup) {
          cleanup();
        }
      });
      setTimeout.mockImplementation(f => f());
      dispatch.updateRoundSeconds.mockImplementation(f => f(100));
    });
    it("sets up a timer and counts down", () => {
      useRoundSeconds.mockReturnValue(100);
      useState.mockReturnValue([false, () => {}]);
      const onTimeout = jest.fn();
      expect(useRoundTimer(onTimeout)).toBe(100);
      expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 1000);
      expect(dispatch.updateRoundSeconds).toHaveReturnedWith(99);
      expect(clearTimeout).toHaveBeenCalled();
      expect(onTimeout).not.toHaveBeenCalled();
    });
    it("calls onTimeout when round ends", () => {
      useRoundSeconds.mockReturnValue(0);
      useState.mockReturnValue([false, () => {}]);
      const onTimeout = jest.fn();
      expect(useRoundTimer(onTimeout)).toBe(0);
      expect(setTimeout).not.toHaveBeenCalled();
      expect(dispatch.updateRoundSeconds).not.toHaveBeenCalled();
      expect(onTimeout).toHaveBeenCalled();
    });
    it("only calls onTimeout once", () => {
      useRoundSeconds.mockReturnValue(0);
      useState.mockReturnValue([true, () => {}]);
      const onTimeout = jest.fn();
      expect(useRoundTimer(onTimeout)).toBe(0);
      expect(onTimeout).not.toHaveBeenCalled();
    });
  });
});
