"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.useSendMessage = void 0;
var _react = require("react");
var _uuid = require("uuid");
var _xmppProvider = require("../context/xmppProvider");
var _reactRedux = require("react-redux");
var _roomsSlice = require("../roomStore/roomsSlice");
var _roomHeapSlice = require("../roomStore/roomHeapSlice");
var _auth = require("../networking/api-requests/auth.api");
var _useEventHandlers = require("./useEventHandlers");
// Monotonic counter for stanza ids. Bumped on each send within a single
// process. Two rapid sends in the same millisecond used to collide on
// `send-text-message-${Date.now()}`; that collision made
// insertMessageWithDelimiter dedup the second optimistic message into
// the first by id, so 10 spam-taps visually collapsed into 1 bubble
// whose body was whatever the last dispatch wrote.
let __sendIdSeq = 0;
const nextStanzaId = prefix => `${prefix}-${Date.now()}-${__sendIdSeq = __sendIdSeq + 1 >>> 0}`;
const useSendMessage = _configOverride => {
  const {
    client
  } = (0, _xmppProvider.useXmppClient)();
  const dispatch = (0, _reactRedux.useDispatch)();

  // Split selectors so each returns a primitive/stable reference — the
  // single-object selector above caused a "returned a different result
  // when called with the same parameters" warning and unnecessary
  // rerenders on every redux update.
  const user = (0, _reactRedux.useSelector)(state => state.chatSettingStore.user);
  const config = (0, _reactRedux.useSelector)(state => state.chatSettingStore.config);
  const editAction = (0, _reactRedux.useSelector)(state => state.rooms.editAction);
  const rooms = (0, _reactRedux.useSelector)(state => state.rooms.rooms);
  const {
    handleMessageSent,
    handleMessageFailed,
    handleMessageEdited
  } = (0, _useEventHandlers.useEventHandlers)(config);
  const sendMessage = (0, _react.useCallback)(async (message, activeRoomJID, isReply, isChecked, mainMessage) => {
    if (editAction?.isEdit) {
      try {
        client?.editMessageStanza(editAction.roomJid, editAction.messageId, message);
        handleMessageEdited({
          messageId: editAction.messageId,
          newMessage: message,
          roomJID: editAction.roomJid,
          user
        });
      } catch (error) {
        handleMessageFailed({
          message,
          roomJID: editAction.roomJid,
          error: error,
          messageType: 'text'
        });
      }
      dispatch((0, _roomsSlice.setEditAction)({
        isEdit: false
      }));
      return;
    }

    // Critical-send hint to the QoS scheduler.
    client?.onCriticalSend?.(activeRoomJID);

    // Optimistic pending render — push the message into redux
    // immediately with `pending: true` so the bubble shows
    // "sending..." while the stanza is in flight. The server echoes
    // it back with the same id and insertMessageWithDelimiter
    // dedupes by id and flips `pending: false` → DoubleTick renders.
    // Without this, the user taps send and sees nothing for ~200ms
    // until the echo lands, which feels broken.
    const optimisticId = nextStanzaId('send-text-message');
    const optimisticDate = new Date().toISOString();
    const selfId = user?.xmppUsername || user?.walletAddress || '';
    const optimisticMessage = {
      id: optimisticId,
      // Also set xmppId so the echo (which carries our outer stanza
      // id as xmppId via getDataFromXml) can be matched and dedup'd
      // by insertMessageWithDelimiter (`msg.xmppId === message.id`
      // branch).
      xmppId: optimisticId,
      body: message,
      roomJid: activeRoomJID,
      date: optimisticDate,
      pending: true,
      isDeleted: false,
      user: {
        ...user,
        id: selfId,
        name: `${user?.firstName || ''} ${user?.lastName || ''}`.trim() || selfId
      }
    };
    if (!config?.disableSentLogic) {
      dispatch((0, _roomsSlice.addRoomMessage)({
        roomJID: activeRoomJID,
        message: optimisticMessage
      }));
    }
    try {
      if (!client) {
        throw new Error('No XMPP client');
      }
      // Pass the optimistic id as the stanza id so the server echoes
      // it back with the same value — the reducer's dedupe lookup
      // matches and the bubble flips from pending → delivered in-place
      // (instead of rendering two copies, which is what happens when
      // ids don't match).
      client.sendMessage(activeRoomJID, user.firstName, user.lastName, '', user.walletAddress, message, '', isReply || false, isChecked || false, mainMessage || '', optimisticId);
      await handleMessageSent({
        message,
        roomJID: activeRoomJID,
        user,
        messageType: 'text'
      });
    } catch (error) {
      handleMessageFailed({
        message,
        roomJID: activeRoomJID,
        error: error,
        messageType: 'text'
      });
    }
  }, [editAction, client, user, dispatch, handleMessageSent, handleMessageEdited, handleMessageFailed]);
  const sendMedia = (0, _react.useCallback)(async (data, type, activeRoomJID, isReply = false, isChecked = false, mainMessage = '') => {
    client?.onCriticalSend?.(activeRoomJID);
    const id = `send-media-message:${(0, _uuid.v4)()}`;
    const optimisticTimestamp = Date.now();
    const optimisticDate = new Date(optimisticTimestamp).toISOString();
    const selfId = user?.xmppUsername || user?.walletAddress || '';
    const displayName = `${user?.firstName || ''} ${user?.lastName || ''}`.trim() || selfId;
    const fileSizeStr = data?.size != null ? String(data.size) : '';
    if (!config?.disableSentLogic) {
      dispatch((0, _roomsSlice.addRoomMessage)({
        roomJID: activeRoomJID,
        message: {
          id: id,
          body: 'media',
          roomJid: activeRoomJID,
          date: optimisticDate,
          messageTimestampMs: optimisticTimestamp,
          user: {
            ...user,
            id: selfId,
            name: displayName
          },
          pending: true,
          isDeleted: false,
          xmppId: id,
          xmppFrom: `${activeRoomJID}/${selfId}`,
          isSystemMessage: 'false',
          isMediafile: 'true',
          fileName: data?.name,
          location: '',
          locationPreview: '',
          mimetype: type,
          originalName: data?.name,
          size: fileSizeStr,
          isReply,
          showInChannel: `${isChecked}`,
          mainMessage
        }
      }));
      dispatch((0, _roomHeapSlice.addMessageToHeap)({
        id: id,
        user: {
          ...user,
          id: selfId,
          name: displayName
        },
        date: optimisticDate,
        messageTimestampMs: optimisticTimestamp,
        body: 'media',
        roomJid: activeRoomJID,
        xmppFrom: `${activeRoomJID}/${selfId}`,
        isReply,
        showInChannel: `${isChecked}`,
        mainMessage
      }));
    }
    try {
      const mediaData = new FormData();
      mediaData.append('files', data);
      const response = await (0, _auth.uploadFile)(mediaData);
      for (const item of response.data.results) {
        const messagePayload = {
          firstName: user.firstName,
          lastName: user.lastName,
          walletAddress: user.walletAddress,
          createdAt: item.createdAt,
          expiresAt: item.expiresAt,
          fileName: item.filename,
          isVisible: item?.isVisible,
          location: item.location,
          locationPreview: item.locationPreview,
          mimetype: item.mimetype,
          originalName: item?.originalname,
          ownerKey: item?.ownerKey,
          size: item.size,
          duration: item?.duration,
          updatedAt: item?.updatedAt,
          userId: item?.userId,
          attachmentId: item?._id,
          wrappable: true,
          roomJid: activeRoomJID,
          showInChannel: isChecked,
          isReply,
          mainMessage,
          isPrivate: item?.isPrivate,
          __v: item.__v
        };
        // Stanza id == placeholder id so the MUC echo's outer
        // <message id="..."> matches xmppId on the placeholder and
        // insertMessageWithDelimiter merges in place + flips pending.
        client?.sendMediaMessageStanza(activeRoomJID, messagePayload, id);
      }
      await handleMessageSent({
        message: 'media',
        roomJID: activeRoomJID,
        user,
        messageType: 'media',
        metadata: {
          isReply,
          isChecked,
          mainMessage,
          fileData: data,
          fileType: type,
          messageId: id,
          uploadResults: response.data.results
        }
      });
    } catch (error) {
      // Surface the real server payload so we can see why the upload
      // was rejected (axios collapses the message to "Request failed
      // with status code N"; the actual reason lives in
      // `error.response.data`).
      console.error('upload failed', {
        status: error?.response?.status,
        statusText: error?.response?.statusText,
        serverBody: error?.response?.data,
        requestUrl: error?.config?.url,
        axiosMessage: error?.message
      });
      handleMessageFailed({
        message: 'media',
        roomJID: activeRoomJID,
        error: error,
        messageType: 'media'
      });
    }
  }, [client, config, user, dispatch, handleMessageSent, handleMessageFailed]);

  // ChatRoom/ThreadWrapper consume this as the "edit branch" of send.
  // It mirrors the edit path inside `sendMessage` so callers can wire it
  // up directly when `editAction.isEdit` is true.
  const sendEditMessage = (0, _react.useCallback)(async (message, _activeRoomJID) => {
    if (!editAction?.isEdit || !editAction.roomJid || !editAction.messageId) {
      return;
    }
    try {
      client?.editMessageStanza(editAction.roomJid, editAction.messageId, message);
      handleMessageEdited({
        messageId: editAction.messageId,
        newMessage: message,
        roomJID: editAction.roomJid,
        user
      });
    } catch (error) {
      handleMessageFailed({
        message,
        roomJID: editAction.roomJid,
        error: error,
        messageType: 'text'
      });
    }
    dispatch((0, _roomsSlice.setEditAction)({
      isEdit: false
    }));
  }, [client, editAction, user, dispatch, handleMessageEdited, handleMessageFailed]);

  // True when the most recent message in the given room is from the
  // current user and still in a pending state (i.e. not yet ack'd by
  // the server). Used by SendInput to disable rapid re-sends.
  const isLastMessageFromUserAndProcessing = (0, _react.useCallback)(roomJID => {
    if (!roomJID) {
      return false;
    }
    const msgs = rooms?.[roomJID]?.messages;
    if (!msgs || msgs.length === 0) {
      return false;
    }
    const last = msgs[msgs.length - 1];
    if (!last?.pending) {
      return false;
    }
    const selfId = user?.xmppUsername || user?.walletAddress;
    if (!selfId) {
      return false;
    }
    return last.user?.id === selfId;
  }, [rooms, user?.xmppUsername, user?.walletAddress]);
  return {
    sendMessage,
    sendMedia,
    sendEditMessage,
    isLastMessageFromUserAndProcessing
  };
};
exports.useSendMessage = useSendMessage;
//# sourceMappingURL=useSendMessage.js.map