import { socketService } from '../../main';
import { Constants } from 'const/constants';

const state = {
  joinableGames: [],
  /** @type {import('type/comm').CommStatus} */
  loadGamesStatus: { status: Constants.REQ_IDLE, text: 'Not connected' },
  connectionStatus: { status: Constants.REQ_IDLE, text: 'Not connected' },
  createGameStatus: { status: Constants.REQ_IDLE, text: 'Not connected' },
  joinGameStatus: { status: Constants.REQ_IDLE, text: 'Not connected' }
};

const getters = {
  joinableGames(state) {
    return state.joinableGames;
  },
  connectionStatus(state) {
    return state.connectionStatus;
  },
  loadGamesStatus(state) {
    return state.loadGamesStatus;
  },
  createGameStatus(state) {
    return state.createGameStatus;
  },
  joinGameStatus(state) {
    return state.joinGameStatus;
  }
};

const mutations = {
  SET_JOINABLE_GAMES: (state, payload) => {
    state.joinableGames = payload;
  },
  SET_CONNECTION_STATUS: (state, payload) => {
    state.connectionStatus = payload;
  },
  SET_LOAD_GAMES_STATUS: (state, payload) => {
    state.loadGamesStatus = payload;
  },
  SET_CREATE_GAME_STATUS: (state, payload) => {
    state.createGameStatus = payload;
  },
  SET_JOIN_GAME_STATUS: (state, payload) => {
    state.joinGameStatus = payload;
  },
  RESET_ALL_STATUS: state => {
    let status = { status: Constants.REQ_IDLE, text: 'Not connected' };
    state.connectionStatus = status;
    state.loadGamesStatus = status;
    state.createGameStatus = status;
    state.joinGameStatus = status;
  }
};

const actions = {
  fetchJoinableGames: ({ commit, rootState }) => {
    let loadGamesStatus = {
      status: Constants.REQ_REQUESTED,
      text: 'Loading Games'
    };
    commit('SET_LOAD_GAMES_STATUS', loadGamesStatus);
    socketService
      .getGamesList(rootState.username)
      .then(games => {
        loadGamesStatus.status = Constants.REQ_SUCCESS;
        if (games.length === 0) {
          loadGamesStatus.text =
            'No games found, wait for a new or create one !';
        } else {
          loadGamesStatus.text = 'Online games loaded';
        }
        commit('SET_JOINABLE_GAMES', games);
        commit('SET_LOAD_GAMES_STATUS', loadGamesStatus);
      })
      .catch(() => {
        loadGamesStatus = {
          status: Constants.REQ_ERROR,
          text: 'Error reaching server'
        };
        commit('SET_LOAD_GAMES_STATUS', loadGamesStatus);
      });
  },
  connect: ({ commit }, payload) => {
    return new Promise((resolve, reject) => {
      let connectionStatus = {};
      if (payload === '') {
        connectionStatus = {
          status: Constants.REQ_ERROR,
          text: 'Enter a valid username'
        };

        commit('SET_CONNECTION_STATUS', connectionStatus);
        reject();
      } else {
        commit('SET_USERNAME', payload, { root: true });
        connectionStatus = {
          status: Constants.REQ_REQUESTED,
          text: 'Connecting...'
        };
        commit('SET_CONNECTION_STATUS', connectionStatus);
        socketService
          .connect(payload)
          .then(() => {
            connectionStatus = {
              status: Constants.REQ_SUCCESS,
              text: 'Connected as ' + payload
            };
            commit('SET_CONNECTION_STATUS', connectionStatus);
            commit('SET_IS_CONNECTED', true, { root: true });
            localStorage.setItem('username', payload);
            resolve();
          })
          .catch(err => {
            connectionStatus = {
              status: Constants.REQ_ERROR,
              text: 'Could not connect as ' + payload + ' (' + err + ')'
            };
            commit('SET_CONNECTION_STATUS', connectionStatus);
            commit('SET_USERNAME', '', { root: true });
            reject();
          });
      }
    });
  },
  createOnlineGame: ({ commit, rootState }, payload) => {
    let createGameStatus = {
      status: Constants.REQ_REQUESTED,
      text: 'Creating Game'
    };
    let game = {
      player1: rootState.username,
      player2: '',
      deck: payload.deckMode,
      advRules: payload.advRules,
      status: 'CREATED',
      data: '{}'
    };
    commit('SET_CREATE_GAME_STATUS', createGameStatus);

    socketService
      .createGame(game)
      .then(id => {
        createGameStatus.status = Constants.REQ_SUCCESS;
        createGameStatus.text = 'Success creating online game ' + id;
        commit('SET_CREATE_GAME_STATUS', createGameStatus);
        commit('SET_GAME_ID', id, { root: true });
        commit('SET_IS_GAME_RUNNING', true, { root: true });
      })
      .catch(() => {
        createGameStatus = {
          status: Constants.REQ_ERROR,
          text: 'Error reaching server'
        };
        commit('SET_CREATE_GAME_STATUS', createGameStatus);
      });
  },
  joinOnlineGame: ({ commit, rootState }, payload) => {
    let joinGameStatus = {
      status: Constants.REQ_REQUESTED,
      text: 'Joining Game'
    };
    commit('SET_JOIN_GAME_STATUS', joinGameStatus);

    socketService
      .joinGame(rootState.username, payload.id, payload.isNew)
      .then(() => {
        joinGameStatus.status = Constants.REQ_SUCCESS;
        joinGameStatus.text = 'Success joining online game ' + payload.id;
        commit('SET_JOIN_GAME_STATUS', joinGameStatus);
        commit('SET_GAME_ID', payload.id, { root: true });
        commit('SET_IS_GAME_RUNNING', true, { root: true });
        if (!payload.isNew) {
          localStorage.setItem('gameId', payload.id);
        }
      })
      .catch(() => {
        joinGameStatus.status = Constants.REQ_ERROR;
        joinGameStatus.text = 'Error +-reaching server';
        commit('SET_JOIN_GAME_STATUS', joinGameStatus);
      });
  }
};
export default {
  namespaced: true,
  state,
  getters,
  mutations,
  actions
};