// store/websocket.js
import Vue from 'vue';

// state 정의
const state = {
  socket: {
    isConnected: false, // WebSocket 연결 상태
    requests: {}, // 각 요청에 대한 응답을 저장하는 객체
    reconnectError: false, // WebSocket 재연결 시도 중에 에러가 발생했는지의 상태
    currentMessage: null, // 마지막으로 받은 메시지
  },
  serverUrl: 'ws://127.0.0.1:8001',  // WebSocket 서버의 URL
  reconnectInterval: 5000, // WebSocket 연결이 끊어진 경우, 재연결을 시도하기 전 대기 시간 (밀리초)
};

// getters 정의
const getters = {
  getResponse: (state) => (WORK_VALUE) => state.socket.requests[WORK_VALUE], // 특정 요청의 응답을 반환하는 getter

  isResponseForRequest: (state) => (WORK_VALUE) => state.socket.requests.hasOwnProperty(WORK_VALUE), // 요청에 대한 응답이 도착했는지 확인하는 getter

  getCurrentMessage: (state) => state.socket.currentMessage, // 마지막으로 받은 메시지를 반환하는 getter

  isConnected: (state) => state.socket.isConnected,

};

// mutations 정의
const mutations = {
  // WebSocket 연결이 열릴 때 실행되는 뮤테이션
  SOCKET_ONOPEN (state, event)  {
    Vue.prototype.$socket = event.currentTarget;
    state.socket.isConnected = true; // 연결 상태를 true로 설정
    state.socket.reconnectError = false; // 재연결 에러 상태를 false로 설정    
    console.log("Connection succeed!");
  },
  // WebSocket 연결이 닫힐 때 실행되는 뮤테이션
  SOCKET_ONCLOSE (state, event)  {
    state.socket.isConnected = false; // 연결 상태를 false로 설정
    console.log("Connection closed!");
    // 재연결 시도를 위해 setTimeout 함수를 사용
    setTimeout(() => {
      state.socket.reconnectError = true; // 재연결 에러 상태를 true로 설정
      this.dispatch('websocket/connect'); // 재연결을 위해 connect 액션을 디스패치
    }, state.reconnectInterval);
  },
  // WebSocket 연결 중 에러가 발생했을 때 실행되는 뮤테이션
  SOCKET_ONERROR (state, event)  {
    console.error(state, event);
  },
  // WebSocket으로부터 메시지를 받았을 때 실행되는 뮤테이션
  SOCKET_ONMESSAGE (state, messageData)  {
    const message = JSON.parse(messageData);
    console.log("Received message from server: ", message);
    console.log(state.socket.requests);
    if (message.WORK_VALUE && state.socket.requests.hasOwnProperty(message.WORK_VALUE)) {
      Vue.set(state.socket.requests, message.WORK_VALUE, message);
      state.socket.currentMessage = message; // 현재 소켓 메시지 업데이트
    }
  },
  registerRequest (state,WORK_VALUE) { // 요청을 요청-응답 맵에 등록하는 뮤테이션
    Vue.set(state.socket.requests, WORK_VALUE, null);
  },
  SOCKET_RECONNECT(state, count) {
    console.info(state, count);
  },
  // WebSocket 재연결 시도 중 에러가 발생했을 때 실행되는 뮤테이션
  SOCKET_RECONNECT_ERROR(state) {
    state.socket.reconnectError = true;
  },
  unregisterRequest (state, WORK_VALUE) { // 요청-응답 맵에서 요청 삭제
    Vue.delete(state.socket.requests, WORK_VALUE);
  },  

  // WebSocket 연결 중 에러가 발생했을 때 실행되는 뮤테이션
  SOCKET_INFO_SET (state, massage)  {    
    state.serverUrl = 'ws://127.0.0.1:'+massage;
    console.log(state.serverUrl);
  },
};

// actions 정의
const actions = {
  // WebSocket에 연결하는 액션
  connect({ commit, state }) {
    return new Promise((resolve, reject) => {
      try {        
        // 이미 연결이 열려있는 경우 새 연결을 만들지 않음
        if(Vue.prototype.$socket && Vue.prototype.$socket.readyState === WebSocket.OPEN) {
          console.log("Connection already opened!");
          state.socket.isConnected = true; // 연결 상태를 true로 설정
          resolve();
        } else {
          const socket = new WebSocket(state.serverUrl);
  
          // WebSocket 이벤트 핸들러 설정
          socket.onopen = (event) => commit('SOCKET_ONOPEN', event); // 연결이 열렸을 때
          socket.onclose = (event) => commit('SOCKET_ONCLOSE', event); // 연결이 닫혔을 때
          socket.onerror = (event) => commit('SOCKET_ONERROR', event); // 에러가 발생했을 때
          socket.onmessage = (event) => commit('SOCKET_ONMESSAGE', event.data); // 메시지를 받았을 때
  
          console.log("Connection opened!");
          resolve();
        }        
      } catch (error) {
        reject(error);
      }
    });
  },
  // WebSocket으로 메시지를 보내는 액션
  sendMessage({ commit, state }, message) {
    Vue.prototype.$socket.send(JSON.stringify(message));
  },
  // WebSocket 연결을 종료하는 액션
  disconnect({ commit, state }) {
    return new Promise((resolve, reject) => {
      try {
        if(Vue.prototype.$socket !== undefined && Vue.prototype.$socket.readyState === WebSocket.OPEN) {
          Vue.prototype.$socket.close();
          console.log("Connection closed!");
          resolve();
        } else {
          console.log("No active connection found!");
          reject("No active connection found!");
        }
      } catch (error) {
        reject(error);
      }
    });
  },
};

// Vuex module export
export default {
  namespaced: true,
  state,
  getters,
  mutations,
  actions
};
