/* global log, L, IITC, app */

/**
 * Chat-panel UI framework: tabs, input, scrolling and the channel-registration API.
 * The COMM data layer lives in comm.js
 *
 * @memberof IITC
 * @namespace chat
 */

// Create the IITC.chat namespace holding the chat-panel UI framework
IITC.chat = {};
const chat = IITC.chat;

/**
 * Template of a channel tab link shown in the chat controls.
 *
 * @type {string}
 * @memberof IITC.chat
 */
chat.channelTabTemplate = '<a data-channel="{id}" accesskey="{index}" title="[{index}]">{name}</a>';

/**
 * Template of a channel message container appended to the chat panel.
 *
 * @type {string}
 * @memberof IITC.chat
 */
chat.channelContainerTemplate = '<div id="chat{id}"><table></table></div>';

//
// common
//

/**
 * Adds a nickname to the chat input.
 *
 * @memberof IITC.chat
 * @param {string} nick - The nickname to add.
 */
chat.addNickname = (nick) => {
  const c = document.getElementById('chattext');
  c.value = `${[c.value.trim(), nick].join(' ').trim()} `;
  c.focus();
};

/**
 * Handles click events on nicknames in the chat.
 *
 * @memberof IITC.chat
 * @param {Event} event - The click event.
 * @param {string} nickname - The clicked nickname.
 * @returns {boolean} Always returns false.
 */
chat.nicknameClicked = (event, nickname) => {
  // suppress @ if coming from chat
  if (nickname.startsWith('@')) {
    nickname = nickname.slice(1);
  }
  const hookData = { event: event, nickname: nickname };

  if (window.runHooks('nicknameClicked', hookData)) {
    chat.addNickname(`@${nickname}`);
  }

  event.preventDefault();
  event.stopPropagation();
  return false;
};

// Per-channel-element UI flags (needsScrollTop, ignoreNextScroll, needsClearing)
const _channelState = new WeakMap();

/**
 * Returns the per-channel-element UI flag store for the given channel DOM element.
 * The native WeakMap store is the source of truth, but writes are mirrored into `$(el).data(key)`
 * and reads fall back to it, so legacy plugins that access these flags via jQuery `.data()`
 * keep working.
 *
 * @memberof IITC.chat
 * @param {HTMLElement} el - The channel DOM element.
 * @returns {Object} A proxy exposing the element's UI flags.
 */
chat.channelState = (el) => {
  let state = _channelState.get(el);
  if (!state) {
    state = new Proxy(
      {},
      {
        get(target, key) {
          if (key in target) return target[key];
          return $(el).data(key);
        },
        set(target, key, value) {
          target[key] = value;
          $(el).data(key, value);
          return true;
        },
      }
    );
    _channelState.set(el, state);
  }
  return state;
};

//
// Channels
//

// 'all' 'faction' and 'alerts' channels are hard coded in several places (including mobile app)
// dont change those channels since they refer to stock channels
// you can add channels from another source provider (message relay, logging from plugins...)

/**
 * Hold channel description
 *
 * See comm.js for examples
 * @typedef {Object} ChannelDescription
 * @property {string} id - uniq id, matches 'tab' parameter for server requests
 * @property {string} name - visible name
 * @property {string} [inputPrompt] - (optional) string for the input prompt
 * @property {string} [inputClass] - (optional) class to apply to #chatinput
 * @property {ChannelSendMessageFn} [sendMessage] - (optional) function to send the message
 * @property {ChannelRequestFn} [request] - (optional) function to call to request new message
 * @property {ChannelRenderFn} [render] - (optional) function to render channel content,, called on tab change
 * @property {boolean} [localBounds] - (optional) if true, reset on view change
 */
/**
 * @callback ChannelSendMessageFn
 * @param {string} id - channel id
 * @param {string} message - input message
 * @returns {void}
 */
/**
 * @callback ChannelRequestFn
 * @param {string} id - channel id
 * @param {boolean} getOlderMsgs - true if request data from a scroll to top
 * @param {boolean} isRetry
 * @returns {void}
 */
/**
 * @callback ChannelRenderFn
 * @param {string} id - channel id
 * @param {boolean} oldMsgsWereAdded - true if data has been added at the top (to preserve scroll position)
 * @returns {void}
 */

/**
 * Holds channels infos.
 *
 * @type {ChannelDescription[]}
 * @memberof IITC.chat
 */
chat.channels = [];

/**
 * Gets the name of the active chat tab.
 *
 * @memberof IITC.chat
 * @returns {string} The name of the active chat tab.
 */
chat.getActive = () => {
  return document.querySelector('#chatcontrols .active')?.dataset.channel;
};

/**
 * Converts a chat tab name to its corresponding channel object.
 *
 * @memberof IITC.chat
 * @param {string} tab - The name of the chat tab.
 * @returns {ChannelDescription} The corresponding channel name ('faction', 'alerts', or 'all').
 */
chat.getChannelDesc = (tab) => {
  return chat.channels.find((entry) => entry.id === tab) || null;
};

/**
 * Allows plugins to request and monitor COMM data streams in the background. This is useful for plugins
 * that need to process COMM data even when the user is not actively viewing the COMM channels.
 * It tracks the requested channels for each plugin instance and updates the global state accordingly.
 *
 * @memberof IITC.chat
 * @param {string} instance - A unique identifier for the plugin or instance requesting background COMM data.
 * @param {string} channel - The name of the COMM channel ('all', 'faction', or 'alerts').
 * @param {boolean} flag - Set to true to request data for the specified channel, false to stop requesting.
 */
chat.backgroundChannelData = (instance, channel, flag) => {
  // first, store the state for this instance
  if (!chat.backgroundInstanceChannel) chat.backgroundInstanceChannel = {};
  if (!chat.backgroundInstanceChannel[instance]) chat.backgroundInstanceChannel[instance] = {};
  chat.backgroundInstanceChannel[instance][channel] = flag;

  // now, to simplify the request code, merge the flags for all instances into one
  // 1. clear existing overall flags
  chat.backgroundChannels = {};
  // 2. for each instance monitoring COMM...
  Object.keys(chat.backgroundInstanceChannel).forEach((instance) => {
    // 3. and for each channel monitored by this instance...
    Object.keys(chat.backgroundInstanceChannel[instance]).forEach((channel) => {
      // 4. if it's monitored, set the channel flag
      if (chat.backgroundInstanceChannel[instance][channel]) chat.backgroundChannels[channel] = true;
    });
  });
};

/**
 * Requests chat messages for the currently active chat tab and background channels.
 * It calls the appropriate request function based on the active tab or background channels.
 *
 * @memberof IITC.chat
 */
chat.request = () => {
  const channel = chat.getActive();
  chat.channels.forEach((entry) => {
    if (channel === entry.id || (chat.backgroundChannels && chat.backgroundChannels[entry.id])) {
      if (entry.request) entry.request(entry.id, false);
    }
  });
};

/**
 * Checks if the currently selected chat tab needs more messages.
 * This function is triggered by scroll events and loads older messages when the user scrolls to the top.
 *
 * @memberof IITC.chat
 */
chat.needMoreMessages = () => {
  const activeTab = chat.getActive();
  const channel = chat.getChannelDesc(activeTab);
  if (!channel || !channel.request) return;

  const activeChat = Array.from(document.querySelectorAll('#chat > *')).find((el) => IITC.utils._isVisible(el));
  if (!activeChat) return;

  const hasScrollbar = window.scrollBottom(activeChat) !== 0 || activeChat.scrollTop !== 0;
  const nearTop = activeChat.scrollTop <= window.CHAT_REQUEST_SCROLL_TOP;
  if (hasScrollbar && !nearTop) return;

  channel.request(channel.id, false);
};

/**
 * Chooses and activates a specified chat tab.
 * Also triggers an early refresh of the chat data when switching tabs.
 *
 * @memberof IITC.chat
 * @param {string} tab - The name of the chat tab to activate ('all', 'faction', or 'alerts').
 */
chat.chooseTab = (tab) => {
  if (chat.channels.every((entry) => entry.id !== tab)) {
    const tabsAvalaible = chat.channels.map((entry) => `"${entry.id}"`).join(', ');
    log.warn(`chat tab "${tab}" requested - but only ${tabsAvalaible} are valid - assuming "all" wanted`);
    tab = 'all';
  }

  const oldTab = chat.getActive();

  localStorage['iitc-chat-tab'] = tab;

  const oldChannel = chat.getChannelDesc(oldTab);
  const channel = chat.getChannelDesc(tab);

  const chatInput = document.getElementById('chatinput');
  if (oldChannel && oldChannel.inputClass) chatInput.classList.remove(oldChannel.inputClass);
  if (channel.inputClass) chatInput.classList.add(channel.inputClass);

  chatInput.querySelector('mark').textContent = channel.inputPrompt || '';

  document.querySelector('#chatcontrols .active')?.classList.remove('active');
  document.querySelector(`#chatcontrols a[data-channel='${tab}']`)?.classList.add('active');

  if (tab !== oldTab) window.startRefreshTimeout(0.1 * 1000); // only chat uses the refresh timer stuff, so a perfect way of forcing an early refresh after a tab change

  document.querySelectorAll('#chat > div').forEach((div) => {
    div.style.display = 'none';
  });

  const elm = document.getElementById(`chat${tab}`);
  elm.style.display = '';

  if (channel.render) channel.render(tab);

  const state = chat.channelState(elm);
  if (state.needsScrollTop) {
    state.ignoreNextScroll = true;
    elm.scrollTop = state.needsScrollTop;
    state.needsScrollTop = null;
  }
};

/**
 * Toggles the chat window between expanded and collapsed states.
 * When expanded, the chat window covers a larger area of the screen.
 * This function also ensures that the chat is scrolled to the bottom when collapsed.
 *
 * @memberof IITC.chat
 */
chat.toggle = () => {
  const chatEl = document.getElementById('chat');
  const chatControls = document.getElementById('chatcontrols');
  if (chatEl.classList.contains('expand') || chatControls.classList.contains('expand')) {
    chatEl.classList.remove('expand');
    chatControls.classList.remove('expand');
    const div = Array.from(document.querySelectorAll('#chat > div')).find((el) => IITC.utils._isVisible(el));
    if (div) {
      chat.channelState(div).ignoreNextScroll = true;
      div.scrollTop = 99999999; // scroll to bottom
    }
    document.querySelectorAll('.leaflet-control').forEach((el) => {
      el.classList.remove('chat-expand');
    });
  } else {
    chatEl.classList.add('expand');
    chatControls.classList.add('expand');
    document.querySelectorAll('.leaflet-control').forEach((el) => {
      el.classList.add('chat-expand');
    });
    chat.needMoreMessages();
  }
};

/**
 * Displays the chat interface and activates a specified chat tab.
 *
 * @memberof IITC.chat
 * @param {string} name - The name of the chat tab to show and activate.
 */
chat.show = (name) => {
  if (IITC.utils.isSmartphone()) {
    IITC.statusbar.hide();
  } else {
    IITC.statusbar.show();
  }
  document.getElementById('chat').style.display = '';
  document.getElementById('chatinput').style.display = '';

  chat.chooseTab(name);
};

/**
 * Chat tab chooser handler.
 * This function is triggered by a click event on the chat tab. It reads the tab name from the event target
 * and activates the corresponding chat tab.
 *
 * @memberof IITC.chat
 * @param {Event} event - The event triggered by clicking a chat tab.
 */
chat.chooser = (event) => {
  const tab = event.target.dataset.channel;

  if (IITC.utils.isSmartphone() && !window.useAppPanes()) {
    window.show(tab);
  } else {
    chat.chooseTab(tab);
  }
};

/**
 * Maintains the scroll position of a chat box when new messages are added.
 * This function is designed to keep the scroll position fixed when old messages are loaded, and to automatically scroll
 * to the bottom when new messages are added if the user is already at the bottom of the chat.
 *
 * @memberof IITC.chat
 * @param {HTMLElement|jQuery} box - The chat box element (a jQuery object is also accepted for legacy callers).
 * @param {number} scrollBefore - The scroll position before new messages were added.
 * @param {boolean} isOldMsgs - Indicates if the added messages are older messages.
 */
chat.keepScrollPosition = (box, scrollBefore, isOldMsgs) => {
  // If scrolled down completely, keep it that way so new messages can
  // be seen easily. If scrolled up, only need to fix scroll position
  // when old messages are added. New messages added at the bottom don’t
  // change the view and enabling this would make the chat scroll down
  // for every added message, even if the user wants to read old stuff.

  const elm = box instanceof jQuery ? box[0] : box;
  const state = chat.channelState(elm);

  if (!IITC.utils._isVisible(elm) && !isOldMsgs) {
    state.needsScrollTop = 99999999;
    return;
  }

  if (scrollBefore === 0 || isOldMsgs) {
    state.ignoreNextScroll = true;
    elm.scrollTop = elm.scrollTop + (window.scrollBottom(elm) - scrollBefore);
  }
};

/**
 * Create and insert into the DOM/Mobile app the channel tab
 *
 * @param {ChannelDescription} channelDesc - channel description
 * @static
 */
function createChannelTab(channelDesc) {
  const chatControls = document.getElementById('chatcontrols');
  const chatDiv = document.getElementById('chat');
  const accessLink = L.Util.template(chat.channelTabTemplate, channelDesc);
  chatControls.insertAdjacentHTML('beforeend', accessLink);
  chatControls.lastElementChild.addEventListener('click', chat.chooser);

  const channelDiv = L.Util.template(chat.channelContainerTemplate, channelDesc);
  chatDiv.insertAdjacentHTML('beforeend', channelDiv);
  const elm = chatDiv.lastElementChild;
  if (channelDesc.request) {
    elm.addEventListener('scroll', () => {
      const state = chat.channelState(elm);
      if (state.ignoreNextScroll) {
        state.ignoreNextScroll = false;
        return;
      }
      if (elm.scrollTop < window.CHAT_REQUEST_SCROLL_TOP) channelDesc.request(channelDesc.id, true);
      if (window.scrollBottom(elm) === 0) channelDesc.request(channelDesc.id, false);
    });
  }

  // pane
  if (window.useAndroidPanes()) {
    // exlude hard coded panes
    if (channelDesc.id !== 'all' && channelDesc.id !== 'faction' && channelDesc.id !== 'alerts') {
      app.addPane(channelDesc.id, channelDesc.name, 'ic_action_view_as_list');
    }
  }
}

let isTabsSetup = false;
/**
 * Add to the channel list a new channel description
 *
 * If tabs are already created, a tab is created for this channel as well
 *
 * @memberof IITC.chat
 * @param {ChannelDescription} channelDesc - channel description
 */
chat.addChannel = (channelDesc) => {
  // deny reserved name
  if (channelDesc.id === 'info' || channelDesc.id === 'map') {
    log.warn(`could not add channel "${channelDesc.id}": reserved`);
    return false;
  }
  if (chat.getChannelDesc(channelDesc.id)) {
    log.warn(`could not add channel "${channelDesc.id}": already exist`);
    return false;
  }

  chat.channels.push(channelDesc);
  channelDesc.index = chat.channels.length;

  if (isTabsSetup) createChannelTab(channelDesc);

  return true;
};

//
// setup
//

/**
 * Sets up all channels starting from intel COMM
 *
 * @memberof IITC.chat
 */
chat.setupTabs = () => {
  isTabsSetup = true;

  // insert at the begining the comm channels
  chat.channels.splice(0, 0, ...IITC.comm.channels);

  chat.channels.forEach((entry, i) => {
    entry.index = i + 1;
    createChannelTab(entry);
  });

  // legacy compatibility
  chat._public = IITC.comm._channelsData.all;
  chat._faction = IITC.comm._channelsData.faction;
  chat._alerts = IITC.comm._channelsData.alerts;

  /**
   * Initiates a request for public chat data.
   *
   * @memberof IITC.chat
   * @param {boolean} getOlderMsgs - Whether to retrieve older messages.
   * @param {boolean} [isRetry=false] - Whether the request is a retry.
   */
  chat.requestPublic = (getOlderMsgs, isRetry) => {
    return IITC.comm.requestChannel('all', getOlderMsgs, isRetry);
  };

  /**
   * Requests faction chat messages.
   *
   * @memberof IITC.chat
   * @param {boolean} getOlderMsgs - Flag to determine if older messages are being requested.
   * @param {boolean} [isRetry=false] - Flag to indicate if this is a retry attempt.
   */
  chat.requestFaction = (getOlderMsgs, isRetry) => {
    return IITC.comm.requestChannel('faction', getOlderMsgs, isRetry);
  };

  /**
   * Initiates a request for alerts chat data.
   *
   * @memberof IITC.chat
   * @param {boolean} getOlderMsgs - Whether to retrieve older messages.
   * @param {boolean} [isRetry=false] - Whether the request is a retry.
   */
  chat.requestAlerts = (getOlderMsgs, isRetry) => {
    return IITC.comm.requestChannel('alerts', getOlderMsgs, isRetry);
  };

  /**
   * Renders public chat in the UI.
   *
   * @memberof IITC.chat
   * @param {boolean} oldMsgsWereAdded - Indicates if older messages were added to the chat.
   */
  chat.renderPublic = (oldMsgsWereAdded) => {
    return IITC.comm.renderChannel('all', oldMsgsWereAdded);
  };

  /**
   * Renders faction chat.
   *
   * @memberof IITC.chat
   * @param {boolean} oldMsgsWereAdded - Indicates if old messages were added in the current rendering.
   */
  chat.renderFaction = (oldMsgsWereAdded) => {
    return IITC.comm.renderChannel('faction', oldMsgsWereAdded);
  };

  /**
   * Renders alerts chat in the UI.
   *
   * @memberof IITC.chat
   * @param {boolean} oldMsgsWereAdded - Indicates if older messages were added to the chat.
   */
  chat.renderAlerts = (oldMsgsWereAdded) => {
    return IITC.comm.renderChannel('alerts', oldMsgsWereAdded);
  };
};

/**
 * Sets up the chat interface.
 *
 * @memberof IITC.chat
 */
chat.setup = () => {
  chat.setupTabs();

  if (localStorage['iitc-chat-tab']) {
    chat.chooseTab(localStorage['iitc-chat-tab']);
  }

  ['chatcontrols', 'chat', 'chatinput'].forEach((id) => {
    document.getElementById(id).style.display = '';
  });

  document.querySelector('#chatcontrols a').addEventListener('click', chat.toggle);

  document.getElementById('chatinput').addEventListener('click', () => {
    document.querySelector('#chatinput input').focus();
  });

  chat.setupTime();
  chat.setupPosting();

  window.requests.addRefreshFunction(chat.request);

  const cls = window.PLAYER.team === 'RESISTANCE' ? 'res' : 'enl';
  document.querySelector('#chatinput mark').classList.add(cls);

  document.addEventListener('click', (event) => {
    const nickname = event.target.closest('.nickname');
    if (nickname) return chat.nicknameClicked(event, nickname.textContent);
  });
};

/**
 * Sets up the time display in the chat input box.
 * This function updates the time displayed next to the chat input field every minute to reflect the current time.
 *
 * @memberof IITC.chat
 */
chat.setupTime = () => {
  const inputTime = document.querySelector('#chatinput time');
  const updateTime = () => {
    if (window.isIdle()) return;
    const d = new Date();
    let h = `${d.getHours()}`;
    if (h.length === 1) h = `0${h}`;
    let m = `${d.getMinutes()}`;
    if (m.length === 1) m = `0${m}`;
    inputTime.textContent = `${h}:${m}`;
    // update ON the minute (1ms after)
    setTimeout(updateTime, (60 - d.getSeconds()) * 1000 + 1);
  };
  updateTime();
  window.addResumeFunction(updateTime);
};

//
// posting
//

/**
 * Handles tab completion in chat input.
 *
 * @memberof IITC.chat
 */
chat.handleTabCompletion = () => {
  const el = document.querySelector('#chatinput input');
  const curPos = el.selectionStart;
  const text = el.value;
  const word = text
    .slice(0, curPos)
    .replace(/.*\b([a-z0-9-_])/, '$1')
    .toLowerCase();

  let list = [];
  document.querySelectorAll('#chat > div').forEach((div) => {
    if (!IITC.utils._isVisible(div)) return;
    div.querySelectorAll('mark').forEach((mark) => {
      list.push(mark.textContent);
    });
  });
  list = window.uniqueArray(list);

  let nick = null;
  for (let i = 0; i < list.length; i++) {
    if (!list[i].toLowerCase().startsWith(word)) continue;
    if (nick && nick !== list[i]) {
      log.warn(`More than one nick matches, aborting. (${list[i]} vs ${nick})`);
      return;
    }
    nick = list[i];
  }
  if (!nick) {
    return;
  }

  const posStart = curPos - word.length;
  let newText = text.substring(0, posStart);
  const atPresent = text.substring(posStart - 1, posStart) === '@';
  newText += `${atPresent ? '' : '@'}${nick} `;
  newText += text.substring(curPos);
  el.value = newText;
};

/**
 * Posts a chat message to the currently active chat tab.
 *
 * @memberof IITC.chat
 */
chat.postMsg = () => {
  const c = chat.getActive();
  const channel = chat.getChannelDesc(c);

  const input = document.querySelector('#chatinput input');
  const msg = (input.value || '').trim();
  if (!msg || msg === '') return;

  if (channel.sendMessage) {
    input.value = '';
    return channel.sendMessage(c, msg);
  }
};

/**
 * Sets up the chat message posting functionality.
 *
 * @memberof IITC.chat
 */
chat.setupPosting = () => {
  if (!IITC.utils.isSmartphone()) {
    document.querySelector('#chatinput input').addEventListener('keydown', (event) => {
      try {
        const kc = event.keyCode ? event.keyCode : event.which;
        if (kc === 13) {
          // enter
          chat.postMsg();
          event.preventDefault();
        } else if (kc === 9) {
          // tab
          event.preventDefault();
          chat.handleTabCompletion();
        }
      } catch (e) {
        log.error(e);
        // if (e.stack) { console.error(e.stack); }
      }
    });
  }

  document.getElementById('chatinput').addEventListener('submit', (event) => {
    event.preventDefault();
    chat.postMsg();
  });
};

/**
 * Legacy function for rendering chat messages. Used for backward compatibility with plugins.
 *
 * @deprecated
 * @memberof IITC.chat
 * @param {string} msg - The chat message.
 * @param {string} nick - The nickname of the player who sent the message.
 * @param {number} time - The timestamp of the message.
 * @param {string} team - The team of the player who sent the message.
 * @param {boolean} msgToPlayer - Flag indicating if the message is directed to the player.
 * @param {boolean} systemNarrowcast - Flag indicating if the message is a system narrowcast.
 * @returns {string} The HTML string representing a chat message row.
 */
chat.renderMsg = (msg, nick, time, team, msgToPlayer, systemNarrowcast) => {
  // Imitating data usually derived from processing raw chat data
  const fakeData = {
    guid: `legacyguid-${Math.random()}`,
    time: time,
    public: !systemNarrowcast,
    secure: systemNarrowcast,
    alert: msgToPlayer,
    msgToPlayer: msgToPlayer,
    type: systemNarrowcast ? 'SYSTEM_NARROWCAST' : 'PLAYER_GENERATED',
    narrowcast: systemNarrowcast,
    auto: false, // Assuming the message is player-generated if it's not a system broadcast
    team: team,
    player: {
      name: nick,
      team: team,
    },
    markup: [
      ['TEXT', { plain: msg }], // A simple message with no special markup
    ],
  };

  // Use existing IITC functions to render a chat message row
  return IITC.comm.renderMsgRow(fakeData);
};

/**
 * Legacy function for converts a chat tab name to its corresponding COMM channel name.
 * Used for backward compatibility with plugins.
 *
 * @deprecated
 * @memberof IITC.chat
 * @param {string} tab - The name of the chat tab.
 * @returns {string} The corresponding channel name ('faction', 'alerts', or 'all').
 */
chat.tabToChannel = (tab) => {
  if (tab === 'faction') return 'faction';
  if (tab === 'alerts') return 'alerts';
  return 'all';
};

// List of functions to track for synchronization between chat and comm
const legacyFunctions = [
  'genPostData',
  'updateOldNewHash',
  'parseMsgData',
  'writeDataToHash',
  'renderText',
  'getChatPortalName',
  'renderPortal',
  'renderFactionEnt',
  'renderPlayer',
  'renderMarkupEntity',
  'renderMarkup',
  'renderTimeCell',
  'renderNickCell',
  'renderMsgCell',
  'renderMsgRow',
  'renderDivider',
  'renderData',
];
const newCommApi = [
  '_genPostData',
  '_updateOldNewHash',
  'parseMsgData',
  '_writeDataToHash',
  'renderText',
  'getChatPortalName',
  'renderPortal',
  'renderFactionEnt',
  'renderPlayer',
  'renderMarkupEntity',
  'renderMarkup',
  'renderTimeCell',
  'renderNickCell',
  'renderMsgCell',
  'renderMsgRow',
  'renderDivider',
  'renderData',
];

// Function to map legacy function names to their new names in comm
function mapLegacyFunctionNameToCommApi(functionName) {
  const index = legacyFunctions.indexOf(functionName);
  return index !== -1 ? newCommApi[index] : functionName;
}

// Create a proxy for chat to ensure backward compatibility of migrated functions from chat to comm
window.chat = new Proxy(chat, {
  get(target, prop, receiver) {
    if (prop in target) {
      // Return the property from chat if it's defined
      return target[prop];
    } else if (legacyFunctions.includes(prop)) {
      // Map the legacy function name to its new name in comm and return the corresponding function
      const commProp = mapLegacyFunctionNameToCommApi(prop);
      return window.IITC.comm[commProp];
    }
    // Return default value if the property is not found
    return Reflect.get(target, prop, receiver);
  },
  set(target, prop, value) {
    if (legacyFunctions.includes(prop)) {
      // Map the legacy function name to its new name in comm and redirect the assignment there,
      // so IITC.chat (the proxy target) never gains its own copy of a comm-owned function
      const commProp = mapLegacyFunctionNameToCommApi(prop);
      window.IITC.comm[commProp] = value;
      return true;
    }
    // Update or add the property in chat
    target[prop] = value;
    return true; // Indicates that the assignment was successful
  },
});