import type { ApiMessage } from '../../../api/types';
import type { IAlbum, IDocumentGroup } from '../../../types';

import { getMessageOriginalId, isActionMessage } from '../../../global/helpers';
import { getDayStartAt } from '../../../util/dates/oldDateFormat';

type SenderGroup = (ApiMessage | IAlbum | IDocumentGroup)[];

const GROUP_INTERVAL_SECONDS = 600; // 10 minutes

export type MessageDateGroup = {
  originalDate: number;
  datetime: number;
  senderGroups: SenderGroup[];
};

export function isAlbum(messageOrAlbum: ApiMessage | IAlbum | IDocumentGroup): messageOrAlbum is IAlbum {
  return 'albumId' in messageOrAlbum;
}

export function isDocumentGroup(
  messageOrAlbum: ApiMessage | IAlbum | IDocumentGroup,
): messageOrAlbum is IDocumentGroup {
  return 'documentGroupId' in messageOrAlbum;
}

export function groupMessages(
  messages: ApiMessage[], firstUnreadId?: number, topMessageId?: number, isChatWithSelf?: boolean, withUsers?: boolean,
  splitBeforeMessageId?: number,
) {
  const initDateGroup: MessageDateGroup = {
    originalDate: messages[0].date,
    datetime: getDayStartAt(messages[0].date * 1000),
    senderGroups: [[]],
  };
  let currentAlbum: IAlbum | undefined;
  let currentDocumentGroup: IDocumentGroup | undefined;

  const dateGroups: MessageDateGroup[] = [initDateGroup];

  messages.forEach((message, index) => {
    const currentDateGroup = dateGroups[dateGroups.length - 1];
    const currentSenderGroup = currentDateGroup.senderGroups[currentDateGroup.senderGroups.length - 1];
    if (message.isInAlbum) {
      if (!currentAlbum) {
        currentAlbum = {
          albumId: message.groupedId!,
          messages: [message],
          mainMessage: message,
          hasMultipleCaptions: false,
          commentsMessage: message.hasComments ? message : undefined,
          captionMessage: message.content.text ? message : undefined,
        } satisfies IAlbum;
      } else {
        currentAlbum.messages.push(message);
        if (message.hasComments) {
          currentAlbum.commentsMessage = message;
        }
        if (message.content.text && !currentAlbum.hasMultipleCaptions) {
          if (currentAlbum.captionMessage) {
            currentAlbum.hasMultipleCaptions = true;
            currentAlbum.captionMessage = undefined;
          } else {
            currentAlbum.captionMessage = message;
          }
        }
      }
    } else if ((message.content.paidMedia?.extendedMedia.length || 0) > 1) {
      currentSenderGroup.push({
        albumId: `paid-${message.id}`,
        messages: [message],
        mainMessage: message,
        hasMultipleCaptions: false,
        isPaidMedia: true,
      } satisfies IAlbum);
    } else if (message.groupedId) {
      if (!currentDocumentGroup) {
        currentDocumentGroup = {
          documentGroupId: message.groupedId,
          messages: [message],
          firstMessageId: message.id,
          commentsMessage: message.hasComments ? message : undefined,
        } satisfies IDocumentGroup;
      } else {
        currentDocumentGroup.messages.push(message);
        if (message.hasComments) {
          currentDocumentGroup.commentsMessage = message;
        }
      }
    } else {
      currentSenderGroup.push(message);
    }

    const nextMessage = messages[index + 1];

    if (
      currentAlbum
      && (!nextMessage || !nextMessage.groupedId || nextMessage.groupedId !== currentAlbum.albumId)
    ) {
      currentSenderGroup.push(currentAlbum);
      currentAlbum = undefined;
    }

    if (
      currentDocumentGroup
      && (!nextMessage || !nextMessage.groupedId || nextMessage.groupedId !== currentDocumentGroup.documentGroupId)
    ) {
      currentSenderGroup.push(currentDocumentGroup);
      currentDocumentGroup = undefined;
    }

    const lastMessageInSenderGroup = currentSenderGroup[currentSenderGroup.length - 1];
    if (nextMessage && !currentAlbum && !currentDocumentGroup) {
      const nextMessageDayStartsAt = getDayStartAt(nextMessage.date * 1000);
      if (currentDateGroup.datetime !== nextMessageDayStartsAt) {
        const newDateGroup: MessageDateGroup = {
          originalDate: nextMessage.date,
          datetime: nextMessageDayStartsAt,
          senderGroups: [[]],
        };
        dateGroups.push(newDateGroup);
      } else if (
        nextMessage.id === firstUnreadId
        || (splitBeforeMessageId !== undefined && getMessageOriginalId(nextMessage) === splitBeforeMessageId)
        || message.senderId !== nextMessage.senderId
        || message.guestChatViaId !== nextMessage.guestChatViaId
        || (!withUsers && message.paidMessageStars)
        || (nextMessage.suggestedPostInfo)
        || message.isOutgoing !== nextMessage.isOutgoing
        || message.postAuthorTitle !== nextMessage.postAuthorTitle
        || (isActionMessage(message) && message.content.action?.type !== 'phoneCall')
        || (isActionMessage(nextMessage) && nextMessage.content.action?.type !== 'phoneCall')
        || message.inlineButtons
        || nextMessage.inlineButtons
        || (nextMessage.date - message.date) > GROUP_INTERVAL_SECONDS
        || (topMessageId
          && (message.id === topMessageId
            || (lastMessageInSenderGroup && (
              (isAlbum(lastMessageInSenderGroup) && lastMessageInSenderGroup.mainMessage.id === topMessageId)
              || (isDocumentGroup(lastMessageInSenderGroup) && lastMessageInSenderGroup.firstMessageId === topMessageId)
            )))
            && nextMessage.id !== topMessageId
            && !(message.groupedId && message.groupedId === nextMessage.groupedId))
          || (isChatWithSelf && message.forwardInfo?.fromId !== nextMessage.forwardInfo?.fromId)
      ) {
        currentDateGroup.senderGroups.push([]);
      }
    }
  });

  return dateGroups;
}
