import { getCurrentRound } from "../domain/apiMethods";
import {
  clearGameInfoFromLocalStorage,
  clearRoundInfoFromLocalStorage,
  getInfoFromLocalStorage,
  hasSavedGameInfo,
  saveGameInfoToLocalStorage,
  savePanoPositionToLocalStorage,
  savePanoPovToLocalStorage,
  saveTimerToLocalStorage,
} from "../domain/localStorageMethods";

const localStorageGameId = "terrassumptions:gameId";
const localStoragePlayerName = "terrassumptions:playerName";
const localStoragePlayerId = "terrassumptions:playerId";

const localStorageTimer = "terrassumptions:timer";

const localStoragePanoLat = "terrassumptions:pano:lat";
const localStoragePanoLng = "terrassumptions:pano:lng";

const localStoragePanoHeading = "terrassumptions:pano:heading";
const localStoragePanoPitch = "terrassumptions:pano:pitch";

jest.mock("../domain/apiMethods");

describe("localStorageMethods", () => {
  beforeEach(() => {
    jest.spyOn(window.localStorage.__proto__, "getItem");
    jest.spyOn(window.localStorage.__proto__, "setItem");
    jest.spyOn(window.localStorage.__proto__, "removeItem");
  });

  describe("hasSavedGameInfo", () => {
    it("works when all data missing", async () => {
      expect(await hasSavedGameInfo()).toBe(false);
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
      expect(getCurrentRound).not.toHaveBeenCalled();
    });
    it("works when player info missing", async () => {
      const data = {
        [localStorageGameId]: "test-game-id",
      };
      localStorage.getItem.mockImplementation(key => data[key] ?? null);

      expect(await hasSavedGameInfo()).toBe(false);
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
      expect(getCurrentRound).not.toHaveBeenCalled();
    });
    it("works when playerId missing", async () => {
      const data = {
        [localStorageGameId]: "test-game-id",
        [localStoragePlayerName]: "test-player",
      };
      localStorage.getItem.mockImplementation(key => data[key] ?? null);

      expect(await hasSavedGameInfo()).toBe(false);
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
      expect(getCurrentRound).not.toHaveBeenCalled();
    });
    it("works when getCurrentRound fails", async () => {
      const data = {
        [localStorageGameId]: "test-game-id",
        [localStoragePlayerName]: "test-player",
        [localStoragePlayerId]: "test-player-id",
      };
      localStorage.getItem.mockImplementation(key => data[key] ?? null);
      getCurrentRound.mockImplementation(() => {
        throw new Error();
      });
      expect(await hasSavedGameInfo()).toBe(false);
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
      expect(getCurrentRound).toHaveBeenCalled();
    });
    it("works when no data missing", async () => {
      const data = {
        [localStorageGameId]: "test-game-id",
        [localStoragePlayerName]: "test-player",
        [localStoragePlayerId]: "test-player-id",
      };
      localStorage.getItem.mockImplementation(key => data[key] ?? null);

      expect(await hasSavedGameInfo()).toBe(true);
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
      expect(getCurrentRound).toHaveBeenCalled();
    });
  });

  describe("saveGameInfoToLocalStorage", () => {
    it("saves given data", () => {
      saveGameInfoToLocalStorage(
        "test-game-id",
        "test-player-name",
        "test-player-id"
      );
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
    });
  });

  describe("saveTimerToLocalStorage", () => {
    it("saves given data", () => {
      saveTimerToLocalStorage(100);
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
    });
  });

  describe("savePanoPositionToLocalStorage", () => {
    it("saves given data", () => {
      savePanoPositionToLocalStorage(1, 2);
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
    });
  });

  describe("savePanoPovToLocalStorage", () => {
    it("saves given data", () => {
      savePanoPovToLocalStorage(3, 4);
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
    });
  });

  describe("clearGameInfoFromLocalStorage", () => {
    it("clears data", () => {
      clearGameInfoFromLocalStorage();
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
    });
  });

  describe("clearRoundInfoFromLocalStorage", () => {
    it("clears data", () => {
      clearRoundInfoFromLocalStorage();
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
    });
  });

  describe("getInfoFromLocalStorage", () => {
    it("gets data", () => {
      const data = {
        [localStorageGameId]: "test-game-id",
        [localStoragePlayerName]: "test-player",
        [localStoragePlayerId]: "test-player-id",
        [localStorageTimer]: "300",
        [localStoragePanoLat]: "test-lat",
        [localStoragePanoLng]: "test-lng",
        [localStoragePanoHeading]: "test-heading",
        [localStoragePanoPitch]: "test-pitch",
      };
      localStorage.getItem.mockImplementation(key => data[key] ?? null);

      expect(getInfoFromLocalStorage()).toMatchSnapshot();
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
    });
    it("handles bad/missing extra data", () => {
      const data = {
        [localStorageGameId]: "test-game-id",
        [localStoragePlayerName]: "test-player",
        [localStoragePlayerId]: "test-player-id",
        [localStoragePanoLng]: "test-lng",
        [localStoragePanoPitch]: "test-pitch",
      };
      localStorage.getItem.mockImplementation(key => data[key] ?? null);

      expect(getInfoFromLocalStorage()).toMatchSnapshot();
      expect(localStorage.getItem).toMatchSnapshot();
      expect(localStorage.setItem).toMatchSnapshot();
      expect(localStorage.removeItem).toMatchSnapshot();
    });
  });
});
