import { type TFunction } from 'react-i18next';

import i18next from 'i18next';
import { uniqBy } from 'lodash-es';

import 'src/components/dashboard/chat/i18n';
import 'src/pages/dashboard/tickets/i18n';

import { CHAT_CONSTANTS } from 'src/constants/chats';
import { EventName } from 'src/types/amplitude';
import { FileTypes } from 'src/types/attachments';
import {
  type ChatListItem,
  ChatStatus,
  ChatType,
  type GroupDictionaryItem,
  GroupInfoMessagges,
  type Message,
  MessageStatus,
  MessageType,
  type MessageUser,
  type Sender,
  TicketUserStatus,
} from 'src/types/chats';
import { type MeInstance } from 'src/types/instance';
import { type Topic } from 'src/types/tickets';
import { type MeUser, type User } from 'src/types/user';
import { formatDateInChatMessages, isSameUTCDate } from 'src/utils/date';
import { getAttachment } from 'src/utils/files';
import { idMaker } from 'src/utils/idMaker';
import { getFullName } from 'src/utils/userUtils';

import { getMessage } from 'src/components/dashboard/chat/queries';

export type Values = {
  body: string;
  gif?: {
    type: string;
    externalReference: {
      id: string;
      origin: string;
    };
  };
  images?: any[];
  videos?: any[];
  files?: any[];
  audio?: any;
  messageToReply?: Message;
  resetBody?: boolean;
};

const idGen = idMaker();

export const createMessage = (
  user: MeUser,
  values: Values,
  status: MessageStatus,
  chatType: string,
  isChatMessage: boolean,
  chatId?: number,
  replyMessageId?: string | number,
): Message => ({
  id: `${idGen.next().value}-internal`,
  userId: user?.id,
  status,
  createdAt: new Date(),
  text: values.body,
  attachments: [
    ...values.files.map(getAttachment),
    ...values.images.map(getAttachment),
    ...values.videos.map(getAttachment),
    values.audio,
  ],
  type: values.body.length > 0 ? MessageType.TEXT : MessageType.FILE,
  reactions: [],
  user: getMessageUser(user),
  replyMessage: replyMessageId
    ? getMessage(chatId, replyMessageId, chatType, isChatMessage)
    : undefined,
  replyMessageId: replyMessageId ? Number(replyMessageId) : undefined,
});

export const isClosed = (text): boolean => {
  if (!text) return false;

  const [status] = text.split(',');
  return (
    status === TicketUserStatus.CLOSED ||
    status === TicketUserStatus.QUALIFIED ||
    status === TicketUserStatus.CANCELLED
  );
};

export const getInfo = text => {
  try {
    return getInfoParamsText(text);
  } catch (err) {
    return getInfoText(text);
  }
};

export const getInfoParamsText = text => {
  const { type, params } = JSON.parse(text);

  const {
    USER_CREATED_GROUP,
    USER_CHANGED_GROUP_TITLE,
    USER_CHANGED_GROUP_PICTURE,
    USER_LEFT,
    USERS_ADDED,
    USERS_REMOVED,
    CALL_FINISHED,
    CALL_INITIALIZED,
    CALL_MISSED,
    CALL_REJECTED,
  } = GroupInfoMessagges;

  switch (type) {
    case USER_CREATED_GROUP:
      return i18next.t(`CHAT:${USER_CREATED_GROUP}`, {
        user: params[0],
        group: params[1],
      });
    case USER_CHANGED_GROUP_TITLE:
      return i18next.t(`CHAT:${USER_CHANGED_GROUP_TITLE}`, {
        user: params[0],
        group: params[1],
      });
    case USER_CHANGED_GROUP_PICTURE:
      return i18next.t(`CHAT:${USER_CHANGED_GROUP_PICTURE}`, {
        user: params[0],
      });
    case USER_LEFT:
      return i18next.t(`CHAT:${USER_LEFT}`, {
        user: params[0],
      });
    case USERS_ADDED:
      return i18next.t(`CHAT:${USERS_ADDED}`, {
        user: params[0],
        added_users: params[1],
      });
    case USERS_REMOVED:
      return i18next.t(`CHAT:${USERS_REMOVED}`, {
        user: params[0],
        removed_users: params[1],
      });
    case CALL_FINISHED:
      return i18next.t(`CHAT:${CALL_FINISHED}`);
    case CALL_INITIALIZED:
      return i18next.t(`CHAT:${CALL_INITIALIZED}`, {
        user: params[0],
      });
    case CALL_MISSED:
      return i18next.t(`CHAT:${CALL_MISSED}`);
    case CALL_REJECTED:
      return i18next.t(`CHAT:${CALL_REJECTED}`);
    default:
      return '';
  }
};

export const getInfoText = text => {
  const [status, ...nameArray] = text.split(',');

  const STATUS = {
    ASSIGNED_QUERY: 'CHAT:ASSIGNED_QUERY',
    CLOSED: 'CHAT:FINALIZED_QUERY',
    CHANGED_TOPIC: 'CHAT:CHANGED_TOPIC',
  };

  return i18next.t(STATUS[status], {
    responsible: nameArray.join(','),
  });
};

export const getAction = status => {
  const STATUS = {
    UNASSIGNED: 'ASSIGNED',
    ASSIGNED: 'CLOSED',
    CLOSED: 'QUALIFIED',
  };

  return STATUS[status];
};

export const iAmResponsible = (
  ticket: ChatListItem,
  id: number,
  otherUser: User,
): boolean =>
  id === ticket?.responsibleId ||
  (otherUser && otherUser.id !== ticket.responsibleId);

export const canMakeAction = (
  action: string,
  ticket: ChatListItem,
  id: number,
  otherUser: User,
): boolean => {
  if (!ticket) return false;

  if (getAction(ticket.status) !== action) return false;
  if (action === 'QUALIFIED') return !iAmResponsible(ticket, id, otherUser);

  return iAmResponsible(ticket, id, otherUser);
};

export const isTopicResponsible = (topic: Topic, id: number): boolean =>
  topic.responsibles.some(({ responsible }) => responsible.id === id);

export const isGroupChatAdmin = (participants: User[], id: number): boolean => {
  if (!(participants?.length > 0)) return false;

  const participant = participants.find(user => user.id === id);
  if (!participant) return false;

  return participant.isAdmin;
};

// El chatItem debe ser del evento de socket: CHAT_CREATED
export const isChatCreator = (
  chatItem: ChatListItem,
  userId: number,
): boolean => {
  if (!chatItem) return false;

  const { chat, chatType } = chatItem;

  if (chatType === ChatType.REGULAR) {
    return chat?.otherUser?.id !== userId;
  }
  if (chatType === ChatType.REGULAR_GROUP) {
    return isGroupChatAdmin(chat?.otherUsers, userId);
  }

  return true;
};

export const addLastMessage = (oldData, chatItem) => {
  oldData = {
    ...chatItem,
    chat: {
      ...oldData.chat,
      lastMessage: chatItem.chat.lastMessage,
      messages: [chatItem.chat.lastMessage, ...oldData.chat.messages],
    },
  };

  return oldData;
};

export const addLastMessageChat = (oldData, chatItem) => {
  oldData = [chatItem.chat.lastMessage, ...(oldData || [])];
  return oldData;
};

export const isManuallyCreatedMessage = (message: Message) =>
  !message.id || message.id.toString().includes('internal');

export const isSameMessage = (a: Message, b: Message) =>
  a.userId === b.userId &&
  a.type === b.type &&
  (a.text === b.text || (!a.text && !b.text)) &&
  ((!hasAttachment(a) && !hasAttachment(b)) ||
    a.attachments?.length === b.attachments?.length);

export const canAddMessage = (
  newChatItem: ChatListItem,
  messages: Message[],
): boolean =>
  !messages?.some(message => {
    if (!isManuallyCreatedMessage(message)) {
      return message.id === newChatItem.chat?.lastMessageId;
    }

    if (isSameMessage(message, newChatItem.chat?.lastMessage)) {
      return message.status === MessageStatus.PENDING;
    }

    return false;
  });

export const getGroupsForSectionList = (
  groups: ChatListItem[],
  oldGroups: GroupDictionaryItem[] = [],
): GroupDictionaryItem[] => {
  let response = [...oldGroups];

  groups.forEach(group => {
    if (response.length === 0) {
      response = [
        {
          character: group.title.charAt(0).toUpperCase(),
          groups: [group],
        },
      ];
    } else {
      const findGroup = response.find(
        res => res.character === group.title.charAt(0).toUpperCase(),
      );
      if (findGroup) {
        findGroup.groups.push(group);
      } else {
        response = [
          ...response,
          {
            character: group.title.charAt(0).toUpperCase(),
            groups: [group],
          },
        ];
      }
    }
  });

  response.forEach(res =>
    res.groups.sort((first, second) => (first.title > second.title ? 1 : -1)),
  );

  return response;
};

export const getEventNameChat = chatType => {
  if (chatType === ChatType.REGULAR_GROUP) return EventName.CHAT_GROUP_TSPENT;
  if (chatType === ChatType.REGULAR) return EventName.CHAT_SINGLE_TSPENT;
  return null;
};

export const showMessageUserName = (
  messageUserId: number,
  chatType: string,
): boolean => !!messageUserId && chatType === ChatType.REGULAR_GROUP;

export const getMessages = messages => {
  const messagesArray =
    messages?.pages.flatMap(messageList => messageList?.data?.items) || [];

  return uniqBy<Message>(messagesArray, 'id').reverse();
};

export const getLastPage = data => {
  if (!data?.pages[data?.pages?.length - 1]?.data) return undefined;

  return data.pages[data.pages.length - 1].data.page;
};

export const isReadOnlyChat = (
  chatStatus: string,
  chatType: string,
  isResponsible: boolean = false,
  topicDeleted: boolean = false,
): boolean => {
  const action = getAction(chatStatus);
  const toAssign = action === 'ASSIGNED';

  const isReadOnlyTicket =
    chatType === ChatType.TICKET &&
    (topicDeleted || isClosed(chatStatus) || (toAssign && isResponsible));

  const isReadOnlyForm =
    chatType === ChatType.FORM && (isClosed(chatStatus) || toAssign);

  const isReadOnlyRegular =
    (chatType === ChatType.REGULAR || chatType === ChatType.REGULAR_GROUP) &&
    isClosed(chatStatus);

  return isReadOnlyTicket || isReadOnlyForm || isReadOnlyRegular;
};

export const hasMenu = (
  chatType: string,
  status?: string,
  isChatMessage?: boolean,
): boolean =>
  chatType === ChatType.REGULAR_GROUP ||
  chatType === ChatType.REGULAR ||
  (chatType === ChatType.TICKET && status === ChatStatus.ASSIGNED) ||
  (chatType === ChatType.FORM && status === ChatStatus.ASSIGNED) ||
  (chatType === ChatType.FORM && isChatMessage);

export const hasReactionPicker = (
  contentType: string,
  messageStatus: MessageStatus,
  chatStatus: string,
  chatType: string,
  isResponsible: boolean = false,
): boolean => {
  const isCorrectType =
    contentType === MessageType.FILE ||
    contentType === MessageType.TEXT ||
    contentType === MessageType.AUDIO;

  const isDeleted = messageStatus === MessageStatus.DELETED;

  return (
    isCorrectType &&
    !isDeleted &&
    !isReadOnlyChat(chatStatus, chatType, isResponsible)
  );
};

export const hasReactionList = (
  contentType: string,
  messageStatus: MessageStatus,
): boolean => {
  const isCorrectType =
    contentType === MessageType.FILE ||
    contentType === MessageType.TEXT ||
    contentType === MessageType.AUDIO;

  const isDeleted = messageStatus === MessageStatus.DELETED;

  return isCorrectType && !isDeleted;
};

// el primer parametro es que que aumento el segundo es fijo
export const getChatRefIndex = (messageLength, messagesPerPage) => {
  if (messageLength % messagesPerPage === 0) {
    return messagesPerPage;
  }
  return messageLength % messagesPerPage;
};

export const getMessageRef = (
  index: number,
  message: Message,
  messageToScrollTo: Message,
  messageToScrollToRef,
  lastMessageRef,
) => {
  let indexRef;

  if (index === CHAT_CONSTANTS.MESSAGES_LIMIT_PER_PAGE - 1) {
    indexRef = lastMessageRef;
  } else if (messageToScrollTo && message.id === messageToScrollTo.id) {
    indexRef = messageToScrollToRef;
  } else {
    indexRef = null;
  }
  return indexRef;
};

export const disabledDragAndDrop = (
  status,
  isResponsible,
  allowAttachmentsInChats,
  isTicket,
) =>
  (!allowAttachmentsInChats && !isTicket) ||
  (!isResponsible && status === ChatStatus.CLOSED) ||
  (!isResponsible && status === ChatStatus.QUALIFIED) ||
  (isResponsible && status === ChatStatus.UNASSIGNED) ||
  (isResponsible && status === ChatStatus.QUALIFIED) ||
  (isResponsible && status === ChatStatus.CLOSED);

export const allowAttachments = (instance: MeInstance, chatType: ChatType) => {
  const isTicket = chatType === ChatType.TICKET;
  return instance.allowAttachmentsInChats || isTicket;
};

export const getChatModuleName = (
  canViewTickets,
  canViewConversations,
  canViewChats,
  showArchived = false,
) => {
  if (showArchived) {
    return i18next.t('CHAT:ARCHIVED');
  }
  if (canViewConversations) {
    return i18next.t('CHAT:CHATS');
  }
  if (canViewTickets && canViewChats) {
    return i18next.t('CHAT:CHAT_AND_TICKETS');
  }
  if (canViewTickets && !canViewChats) {
    return i18next.t('TICKETS:TICKETS_NAME');
  }

  return i18next.t('CHAT:CHATS');
};

export const isGroupOrRegular = chatType =>
  [ChatType.REGULAR_GROUP, ChatType.REGULAR].includes(chatType);

export const canSendMessage = (chatType, canViewChats, canViewTickets) => {
  if (
    (chatType === 'REGULAR' || chatType === 'REGULAR_GROUP') &&
    !canViewChats
  ) {
    return false;
  }
  if (chatType === 'TICKET' && !canViewTickets) {
    return false;
  }
  return true;
};

export const isInfo = (message: Message): boolean =>
  message.type === MessageType.INFO || message.type === MessageType.INFO_PARAMS;

export const getSender = (
  messageUser: MessageUser,
  messageUserId: number,
  isResponsible: boolean,
  loggedUser: MeUser,
): { sender: User; senderType: Sender } => {
  let senderType;
  let sender;

  if (messageUserId === null) {
    senderType = isResponsible ? 'user' : 'contact';
    sender = null;
  } else if (messageUserId === loggedUser.id) {
    senderType = 'user';
    sender = loggedUser;
  } else {
    senderType = 'contact';
    sender = messageUser;
  }

  return { sender, senderType };
};

export const getDateToShow = (
  index: number,
  actualMessageDate,
  previousMessageDate,
  user: MeUser,
): string | null => {
  if (index === 0 || !isSameUTCDate(actualMessageDate, previousMessageDate)) {
    return formatDateInChatMessages(actualMessageDate, user);
  }

  return null;
};

export const hasAttachment = (message: Message): boolean =>
  message && message.attachments?.length > 0;

export const canReply = (type: string): boolean =>
  type === MessageType.AUDIO ||
  type === MessageType.FILE ||
  type === MessageType.TEXT;

export const getMessageUser = (
  user: MeUser,
  hasLeftChat: boolean = false,
): MessageUser | undefined => {
  if (!user) return undefined;

  return {
    hasLeftChat,
    fullName: getFullName(user),
    color: user.color,
    deleted: user.deleted,
  };
};

export const addMessageUser = (
  message: Message,
  user: MeUser,
  chatType: string,
  isChatMessage: boolean,
  chatId?: number,
  replyMessageId?: string | number,
): void => {
  if (!message || !user) return;

  message.user = getMessageUser(user);
  message.replyMessage = replyMessageId
    ? getMessage(chatId, replyMessageId, chatType, isChatMessage)
    : null;
};

export const updateMessage = (message: Message, newMessage: Message): void => {
  if (!message || !newMessage) return;

  message.attachments = newMessage.attachments;
  message.status = newMessage.status;
  message.text =
    message.status === MessageStatus.DELETED ? '' : newMessage.text;
};

export const buildParamsToGetChatsService = (pageParam, query) => {
  if (query) {
    return { page: pageParam, q: query, types: 'REGULAR,REGULAR_GROUP' };
  }
  return { page: pageParam };
};

export const createMultimediaBody = multimedia => {
  if (multimedia.type === FileTypes.IMAGE)
    return {
      images: [multimedia],
      videos: [],
      files: [],
    };
  if (multimedia.type === FileTypes.VIDEO)
    return {
      videos: [multimedia],
      images: [],
      files: [],
    };
  if (multimedia.type === FileTypes.FILE)
    return {
      videos: [],
      images: [],
      files: [multimedia],
    };
};

const textRegex = /[a-zA-Z0-9]+/;
const emojiRegex = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;

const fontSizeByAmount = {
  1: '48px',
  2: '36px',
  3: '24px',
  4: '20px',
};

export const getTextFontSize = body => {
  const hasText = textRegex.test(body);
  if (hasText) return '14px';

  const emojiCount = (body.match(emojiRegex) || []).length;
  return fontSizeByAmount[Math.min(emojiCount, 4)];
};

export const getStringFromParticipantsArray: (
  participants?: User[],
  currentUser?: MeUser,
  t?: TFunction,
) => string = (participants, currentUser, t) => {
  if (participants && participants.length > 0 && currentUser) {
    const participantsFullName = participants.reduce(
      (participantList, participant) =>
        participantList +
        (participant.id !== currentUser.id
          ? `${participant.firstName} ${participant.lastName}, `
          : ''),
      '',
    );
    return `${participantsFullName} ${t('ME')}`;
  }
  return '';
};

export const getIsMessageWithAction = (status: MessageStatus) =>
  [
    MessageStatus.DELETED,
    MessageStatus.FORWARDED,
    MessageStatus.EDITED,
  ].includes(status);

export const getShowMessageInfoCenter = (
  contentType: string,
  status: MessageStatus,
  replyMessage: Message,
  withoutReactions: boolean,
): boolean =>
  (contentType === MessageType.TEXT || status === MessageStatus.DELETED) &&
  !replyMessage &&
  ![MessageStatus.FORWARDED, MessageStatus.EDITED].includes(status) &&
  withoutReactions;

export const getShowMessageInfoForFiles = (
  contentType: string,
  status: MessageStatus,
  notFileAndAudioAttachment: boolean,
  withoutReactions: boolean,
): boolean =>
  contentType === MessageType.FILE &&
  withoutReactions &&
  notFileAndAudioAttachment &&
  ![MessageStatus.DELETED, MessageStatus.FORWARDED].includes(status);
