import debounce from 'lodash/debounce';

function registerHandler({ commit }, { table, handler }) {
  commit('REGISTER_HANDLER', { table, handler });
}

function unregisterHandler({ commit }, { table, handler }) {
  commit('UNREGISTER_HANDLER', { table, handler });
}

function processServerEvent({ commit, dispatch, state, rootState }, message) {
  //console.log("processServerEvent", message);
  // Error handling for invalid messages
  if (!message) {
    console.error("processServerEvent called without arguments");
    return;
  }

  if (!message.channel) {
    console.error("processServerEvent message missing channel");
    return;
  }

  if (!message.payload) {
    console.error("processServerEvent message missing payload");
    return;
  }

  if (message.payload.operation == "INSERT") {
    if (message.payload.new == null) {
      console.error("Expected payload.new to be non-null");
      return;
    }
  } else if (message.payload.operation == "UPDATE") {
    if (message.payload.old == null || message.payload.new == null) {
      console.error("Expected payload.old and paylaod.new to be non-null");
      return;
    }
  } else if (message.payload.operation == "DELETE") {
    if (message.payload.old == null) {
      console.error("Expected payload.old to be non-null");
      return;
    }
  } else {
    console.warn(`Unrecognised operation: ${message.payload.operation}`);
  }

  const table = message.channel; // or message.payload?.table;
  //console.log("table=", table);
  if (!table || !state.handlers[table] || state.handlers[table].length === 0) {
    return;
  }

  // Create a debounced runner per table if not exists
  if (!state.debouncedRunners) {
    state.debouncedRunners = {}; // Not reactive needed? Or use Vue.set
  }
  if (!state.debouncedRunners[table]) {
    const config = {
      wait: 300, // min silence in ms
      maxWait: 1000, // max wait before force run, adjustable
      trailing: true,
      leading: false
    };
    state.debouncedRunners[table] = debounce((lastMessage) => {
      const context = { commit, dispatch, state: rootState, rootState }; // Approximate action context
      state.handlers[table].forEach(handler => {
        try {
          //console.log("Trying handler:", handler);
          handler(context, lastMessage);
        } catch (e) {
          console.error(`Error in handler for table ${table}:`, e);
        }
      });
    }, config.wait, { maxWait: config.maxWait });
  }

  // Call the debounced function with the current message
  // Debounce will use the last call's argument if multiple
  state.debouncedRunners[table](message);
}

export default { registerHandler, unregisterHandler, processServerEvent };
