import create from "../store";
import {
  getCurrentRound,
  joinGame,
  sendGuess,
  sendTimeout,
} from "./apiMethods";
import {
  IN_ROUND,
  POST_GAME,
  POST_ROUND,
  PRE_GAME,
  PRE_ROUND,
} from "./gameStates";
import {
  clearGameInfoFromLocalStorage,
  clearRoundInfoFromLocalStorage,
  getInfoFromLocalStorage,
  saveGameInfoToLocalStorage,
  saveTimerToLocalStorage,
} from "./localStorageMethods";

const [hooks, actions, watch] = create(store => ({
  // state
  gameId: null,
  playerName: null,
  lastRound: {
    roundNum: -1,
    targetPoint: {
      lat: 0,
      lng: 0,
    },
    score: -1,
    totalScore: -1,
  },
  playerId: null,
  gameState: PRE_GAME,
  currentRound: null,
  targetPoint: null,
  roundSeconds: 0,
  panoStartPosition: null,
  panoStartPov: null,
  // actions
  /* eslint-disable no-param-reassign */
  setPlayerName: name => {
    store.playerName = name;
  },
  goToLobby: gameId =>
    store({
      gameId,
      playerId: null,
      gameState: PRE_ROUND,
    }),
  startRound: () => {
    store.gameState = IN_ROUND;
  },
  goToSummary: (gameId, clearSavedGame = true) => {
    if (gameId) {
      store.gameId = gameId;
    }
    store.gameState = POST_GAME;
    if (clearSavedGame) {
      clearRoundInfoFromLocalStorage();
      clearGameInfoFromLocalStorage();
    }
  },
  updateCurrentRound: async () => {
    const { currentRound, coord, timer } = await getCurrentRound(
      store.gameId,
      store.playerId
    );
    store({
      currentRound,
      targetPoint: coord,
      panoStartPosition: coord,
      panoStartPov: { heading: 0, pitch: 0 },
      roundSeconds: timer,
    });
  },
  joinGame: async () => {
    const { gameId } = store;
    const name = store.playerName;
    const { playerId } = await joinGame(gameId, name);
    store.playerId = playerId;
    await store.updateCurrentRound();
    saveGameInfoToLocalStorage(gameId, name, playerId);
  },
  rejoinGame: async () => {
    const {
      gameId,
      playerName,
      playerId,
      timer,
      position,
      pov,
    } = getInfoFromLocalStorage();
    store({ gameId, playerName, playerId });
    await store.updateCurrentRound();
    store({
      roundSeconds: timer ?? store.roundSeconds,
      panoStartPosition: position ?? store.panoStartPosition,
      panoStartPov: pov ?? store.panoStartPov,
      gameState: IN_ROUND,
    });
  },
  submitGuess: async selectedPoint => {
    clearRoundInfoFromLocalStorage();
    const { score, totalScore } = selectedPoint
      ? await sendGuess(
          store.gameId,
          store.playerId,
          store.currentRound,
          selectedPoint,
          store.roundSeconds
        )
      : await sendTimeout(store.gameId, store.playerId, store.currentRound);
    store({
      lastRound: {
        roundNum: store.currentRound,
        targetPoint: store.targetPoint,
        score,
        totalScore,
      },
      gameState: POST_ROUND,
    });
    await store.updateCurrentRound();
  },
  updateRoundSeconds: update => {
    store({ roundSeconds: update });
    saveTimerToLocalStorage(store.roundSeconds);
  },
  /* eslint-enable no-param-reassign */
}));

if (process.env.REACT_APP_MONITOR_STORE === "true") {
  /* eslint-disable no-console */
  watch.onChange((key, newValue, oldValue) =>
    console.log(
      `Updating ${key} from ${JSON.stringify(oldValue)} to ${JSON.stringify(
        newValue
      )}`
    )
  );
  watch.onCall((key, ...args) =>
    console.log(`Called ${key} action with ${args}`)
  );
  /* eslint-enable no-console */
  watch.setGlobal("terrassumptionsStore");
}

export const {
  useGameId,
  usePlayerName,
  useLastRound,
  useGameState,
  useCurrentRound,
  useTargetPoint,
  useRoundSeconds,
  usePanoStartPosition,
  usePanoStartPov,
} = hooks;
export const dispatch = actions;
