import {useState} from 'react';
import {ApiErrors} from '@config/api';
import {BlockType, Message, MessageStatus} from '@modules/chats/interfaces';
import {forwardMessage as forwardMessageService} from '@modules/chats/services';
import {asyncMap, getUlid} from '@shared/utils';

import {OrchestratorUpdaterService} from '../instances/updaters';
import {LOCAL_INITIAL_VERSION} from '../constants';
import {messagesQueue} from '../instances/MessagesQueue';

export const useForwardMessage = () => {
  const [isLoading, setIsLoading] = useState(false);

  /**
   * Save message in the DB and store it in the local queue to be sent when the user goes online.
   * If the target message is a current user message, it will be sent as a normal message.
   * @param message - Message to save
   * @param params - Parameters for saving
   * @returns void
   */
  const saveForwardMessage = async (
    message: Message,
    params: {
      destinationChannelIds: string[];
      destinationUserIds: number[];
    },
  ) => {
    const blocks = message.blocks || [];

    blocks.push({
      type: BlockType.MessageForwarded,
      original_message_ts: message.ts,
      original_channel_ts: message.channel,
    });

    await asyncMap(params.destinationChannelIds, async channelId => {
      const id = getUlid();
      const newMessage: Message = {
        ...message,
        channel: channelId,
        ts: id,
        client_msg_id: id,
        status: MessageStatus.Sending,
        version: LOCAL_INITIAL_VERSION,
        blocks,
      };

      await OrchestratorUpdaterService.processMessage(newMessage);
      messagesQueue.addMessage(newMessage);
    });
  };

  /**
   * Forward message to destination channels and users.
   * If the target message is a current user message, it will be sent as a normal message.
   * @param message - Message to forward
   * @param params - Parameters for forwarding
   * @returns void
   */
  const forwardMessage = async (
    message: Message,
    params: {
      destinationChannelIds: string[];
      destinationUserIds: number[];
    },
  ) => {
    setIsLoading(true);
    try {
      // Forward message to destination channels and users
      const {data} = await forwardMessageService({
        channel: message.channel,
        messageId: message.ts,
        destinationChannelIds: params.destinationChannelIds,
        destinationUserIds: params.destinationUserIds,
        idempotencyKey: getUlid(),
        text: message.formatted_text || message.text,
        attachments: message.attachments,
      });

      await asyncMap(data, async item => {
        item.status = MessageStatus.Sent;
        await OrchestratorUpdaterService.processMessage(item);
      });
    } catch (error) {
      if ((error as Error).message === ApiErrors.NETWORK_ERROR) {
        // Network error. Save the message in the local queue to be sent when the user goes online.
        await saveForwardMessage(message, params);
      }
    }

    setIsLoading(false);
  };

  return {forwardMessage, isLoading};
};
