import { Api as GramJs } from '../../../lib/gramjs';
import type { Entity } from '../../../lib/gramjs/types';

import type { ThreadReadState } from '../../../types';
import {
  type ApiBotCommand,
  type ApiChat,
  type ApiChatAdminRights,
  type ApiChatBannedRights,
  type ApiChatFolder,
  type ApiChatInviteImporter,
  type ApiChatInviteInfo,
  type ApiChatlistExportedInvite,
  type ApiChatlistInvite,
  type ApiChatMember,
  type ApiChatReactions,
  type ApiExportedInvite,
  type ApiMissingInvitedUser,
  type ApiRestrictionReason,
  type ApiSendAsPeerId,
  type ApiSponsoredMessageReportResult,
  type ApiSponsoredPeer,
  type ApiStarsSubscriptionPricing,
  type ApiThreadInfo,
  type ApiTypingStatus,
  MAIN_THREAD_ID,
} from '../../types';

import { omitUndefined, pickTruthy } from '../../../util/iteratees';
import { toJSNumber } from '../../../util/numbers';
import { getServerTime } from '../../../util/serverTime';
import { addPhotoToLocalDb, addUserToLocalDb } from '../helpers/localDb';
import { serializeBytes } from '../helpers/misc';
import {
  buildApiFormattedText, buildApiPhoto, buildApiUsernames,
} from './common';
import { omitVirtualClassFields } from './helpers';
import { buildApiRestrictionReasons } from './misc';
import {
  buildApiBotVerification,
  buildApiEmojiStatus,
  buildApiPeerColor,
  buildApiPeerId,
  buildAvatarPhotoId,
  getApiChatIdFromMtpPeer,
  isMtpPeerChat,
  isMtpPeerUser,
} from './peers';
import { buildApiReaction } from './reactions';

type PeerEntityApiChatFields = Omit<ApiChat, (
  'id' | 'type' | 'title' |
  'lastReadOutboxMessageId' | 'lastReadInboxMessageId' |
  'unreadCount' | 'unreadMentionsCount' | 'isMuted'
)>;

function buildApiChatFieldsFromPeerEntity(
  peerEntity: Entity,
  isSupport = false,
): PeerEntityApiChatFields {
  const user = peerEntity instanceof GramJs.User ? peerEntity : undefined;
  const channel = peerEntity instanceof GramJs.Channel ? peerEntity : undefined;

  const userOrChannel = user || channel;

  // Shared fields
  const isMin = Boolean('min' in peerEntity && peerEntity.min);
  const accessHash = ('accessHash' in peerEntity) ? String(peerEntity.accessHash) : undefined;
  const hasVideoAvatar = 'photo' in peerEntity && peerEntity.photo && 'hasVideo' in peerEntity.photo
    && peerEntity.photo.hasVideo;
  const avatarPhotoId = ('photo' in peerEntity) && peerEntity.photo ? buildAvatarPhotoId(peerEntity.photo) : undefined;

  const usernames = buildApiUsernames(peerEntity);
  const hasUsername = usernames?.some((username) => username.isActive);

  // Chat and channel shared fields
  const isCallActive = 'callActive' in peerEntity && peerEntity.callActive;
  const isCallNotEmpty = 'callNotEmpty' in peerEntity && peerEntity.callNotEmpty;
  const creationDate = 'date' in peerEntity ? peerEntity.date : undefined;
  const membersCount = 'participantsCount' in peerEntity ? peerEntity.participantsCount : undefined;
  const isProtected = 'noforwards' in peerEntity && peerEntity.noforwards;
  const isCreator = 'creator' in peerEntity && peerEntity.creator;

  // User and channel shared fields
  const isScam = userOrChannel?.scam;
  const isFake = userOrChannel?.fake;
  const areStoriesHidden = userOrChannel?.storiesHidden;
  const maxStoryId = userOrChannel?.storiesMaxId?.maxId;
  const botVerificationIconId = userOrChannel?.botVerificationIcon?.toString();
  const storiesUnavailable = userOrChannel?.storiesUnavailable;
  const color = userOrChannel?.color ? buildApiPeerColor(userOrChannel.color) : undefined;
  const profileColor = userOrChannel?.profileColor ? buildApiPeerColor(userOrChannel.profileColor) : undefined;
  const emojiStatus = userOrChannel?.emojiStatus ? buildApiEmojiStatus(userOrChannel.emojiStatus) : undefined;
  const paidMessagesStars = userOrChannel?.sendPaidMessagesStars;
  const isVerified = userOrChannel?.verified;
  const isForum = channel?.forum || user?.botForumView;

  return {
    isMin,
    isLinkedInDiscussion: channel?.hasLink,
    areSignaturesShown: channel?.signatures,
    areProfilesShown: channel?.signatureProfiles,
    usernames,
    accessHash,
    hasVideoAvatar,
    avatarPhotoId,
    isVerified,
    isCallActive,
    isCallNotEmpty,
    creationDate,
    hasUsername,
    ...(membersCount !== undefined && { membersCount }),
    isProtected,
    isSupport: isSupport || undefined,
    isCreator,
    fakeType: isScam ? 'scam' : (isFake ? 'fake' : undefined),
    color,
    profileColor,
    isJoinToSend: channel?.joinToSend,
    isJoinRequest: channel?.joinRequest,
    isForum,
    isBotForum: user?.botForumView,
    isMonoforum: channel?.monoforum,
    linkedMonoforumId: channel?.linkedMonoforumId !== undefined
      ? buildApiPeerId(channel.linkedMonoforumId, 'channel') : undefined,
    areChannelMessagesAllowed: channel?.broadcastMessagesAllowed,
    areStoriesHidden,
    maxStoryId,
    hasStories: Boolean(maxStoryId) && !storiesUnavailable,
    emojiStatus,
    boostLevel: channel?.level,
    botVerificationIconId,
    hasGeo: channel?.hasGeo,
    subscriptionUntil: channel?.subscriptionUntilDate,
    paidMessagesStars: toJSNumber(paidMessagesStars),
    level: channel?.level,
    hasAutoTranslation: channel?.autotranslation,
    withForumTabs: channel?.forumTabs,

    ...buildApiChatPermissions(peerEntity),
    ...buildApiChatRestrictions(peerEntity),
    ...buildApiChatMigrationInfo(peerEntity),
  };
}

export function buildApiChatFromDialog(
  dialog: GramJs.Dialog,
  peerEntity: GramJs.TypeUser | GramJs.TypeChat,
): ApiChat {
  const {
    peer, folderId, viewForumAsMessages,
  } = dialog;

  return {
    id: getApiChatIdFromMtpPeer(peer),
    folderId,
    type: getApiChatTypeFromPeerEntity(peerEntity),
    title: getApiChatTitleFromMtpPeer(peer, peerEntity),
    isForumAsMessages: viewForumAsMessages,
    ...buildApiChatFieldsFromPeerEntity(peerEntity),
  };
}

export function buildApiChatFromSavedDialog(
  dialog: GramJs.SavedDialog,
  peerEntity: GramJs.TypeUser | GramJs.TypeChat,
): ApiChat {
  const { peer } = dialog;

  return {
    id: getApiChatIdFromMtpPeer(peer),
    type: getApiChatTypeFromPeerEntity(peerEntity),
    title: getApiChatTitleFromMtpPeer(peer, peerEntity),
    ...buildApiChatFieldsFromPeerEntity(peerEntity),
  };
}

function buildApiChatPermissions(peerEntity: GramJs.TypeUser | GramJs.TypeChat): {
  adminRights?: ApiChatAdminRights;
  currentUserBannedRights?: ApiChatBannedRights;
  defaultBannedRights?: ApiChatBannedRights;
} {
  if (!(peerEntity instanceof GramJs.Chat || peerEntity instanceof GramJs.Channel)) {
    return {};
  }

  return {
    adminRights: peerEntity.adminRights ? omitVirtualClassFields(peerEntity.adminRights) : undefined,
    currentUserBannedRights: 'bannedRights' in peerEntity && peerEntity.bannedRights
      ? omitVirtualClassFields(peerEntity.bannedRights)
      : undefined,
    defaultBannedRights: peerEntity.defaultBannedRights
      ? omitVirtualClassFields(peerEntity.defaultBannedRights)
      : undefined,
  };
}

function buildApiChatRestrictions(peerEntity: Entity): {
  isNotJoined?: boolean;
  isForbidden?: boolean;
  isRestricted?: boolean;
  restrictionReasons?: ApiRestrictionReason[];
} {
  if (peerEntity instanceof GramJs.ChatForbidden) {
    return {
      isForbidden: true,
    };
  }

  if (peerEntity instanceof GramJs.ChannelForbidden) {
    return {
      isRestricted: true,
    };
  }

  const restrictions: {
    isNotJoined?: boolean;
    isForbidden?: boolean;
    isRestricted?: boolean;
    restrictionReasons?: ApiRestrictionReason[];
  } = {};

  const isMin = 'min' in peerEntity && peerEntity.min;
  const hasRestricted = 'restricted' in peerEntity;

  if (!isMin) {
    Object.assign(restrictions, {
      isForbidden: undefined,
      isRestricted: undefined,
    });
  }

  if (hasRestricted && !isMin) {
    const restrictionReasons = buildApiRestrictionReasons(peerEntity.restrictionReason);

    Object.assign(restrictions, {
      restrictionReasons,
    });
  }

  if (peerEntity instanceof GramJs.Chat) {
    Object.assign(restrictions, {
      isNotJoined: peerEntity.left,
    });
  }

  if (peerEntity instanceof GramJs.Channel) {
    Object.assign(restrictions, {
      // `left` is weirdly set to `true` on all channels never joined before
      isNotJoined: peerEntity.left,
    });
  }

  return restrictions;
}

function buildApiChatMigrationInfo(peerEntity: Entity): {
  migratedTo?: {
    chatId: string;
    accessHash?: string;
  };
} {
  if (
    'migratedTo' in peerEntity
    && peerEntity.migratedTo
    && !(peerEntity.migratedTo instanceof GramJs.InputChannelEmpty)
  ) {
    return {
      migratedTo: {
        chatId: getApiChatIdFromMtpPeer(peerEntity.migratedTo),
        ...(peerEntity.migratedTo instanceof GramJs.InputChannel && {
          accessHash: String(peerEntity.migratedTo.accessHash),
        }),
      },
    };
  }

  return {};
}

export function buildApiChatFromPreview(
  preview: GramJs.TypeChat | GramJs.TypeUser,
  isSupport = false,
): ApiChat | undefined {
  if (preview instanceof GramJs.ChatEmpty || preview instanceof GramJs.UserEmpty) {
    return undefined;
  }
  const id = buildApiPeerId(
    preview.id,
    preview instanceof GramJs.User ? 'user'
      : (preview instanceof GramJs.Chat || preview instanceof GramJs.ChatForbidden) ? 'chat' : 'channel',
  );

  return {
    id,
    type: getApiChatTypeFromPeerEntity(preview),
    title: preview instanceof GramJs.User ? getUserName(preview) : preview.title,
    ...buildApiChatFieldsFromPeerEntity(preview, isSupport),
  };
}

export function getApiChatTypeFromPeerEntity(peerEntity: GramJs.TypeChat | GramJs.TypeUser) {
  if (peerEntity instanceof GramJs.User || peerEntity instanceof GramJs.UserEmpty) {
    return 'chatTypePrivate';
  } else if (
    peerEntity instanceof GramJs.Chat
    || peerEntity instanceof GramJs.ChatForbidden
    || peerEntity instanceof GramJs.ChatEmpty
  ) {
    return 'chatTypeBasicGroup';
  } else {
    return peerEntity.megagroup ? 'chatTypeSuperGroup' : 'chatTypeChannel';
  }
}

export function getPeerKey(peer: GramJs.TypePeer) {
  if (isMtpPeerUser(peer)) {
    return `user${peer.userId.toString()}`;
  } else if (isMtpPeerChat(peer)) {
    return `chat${peer.chatId.toString()}`;
  } else {
    return `chat${peer.channelId.toString()}`;
  }
}

export function getApiChatTitleFromMtpPeer(peer: GramJs.TypePeer, peerEntity: Entity) {
  if (isMtpPeerUser(peer)) {
    return getUserName(peerEntity as GramJs.User);
  } else {
    return (peerEntity as GramJs.Chat).title;
  }
}

function getUserName(user: GramJs.User) {
  return user.firstName
    ? `${user.firstName}${user.lastName ? ` ${user.lastName}` : ''}`
    : (user.lastName || '');
}

export function buildChatMember(
  member: GramJs.TypeChatParticipant | GramJs.TypeChannelParticipant,
): ApiChatMember | undefined {
  const userId = (member instanceof GramJs.ChannelParticipantBanned || member instanceof GramJs.ChannelParticipantLeft)
    ? getApiChatIdFromMtpPeer(member.peer)
    : buildApiPeerId(member.userId, 'user');

  return {
    userId,
    rank: 'rank' in member ? member.rank : undefined,
    inviterId: 'inviterId' in member && member.inviterId
      ? buildApiPeerId(member.inviterId, 'user')
      : undefined,
    joinedDate: 'date' in member ? member.date : undefined,
    kickedByUserId: 'kickedBy' in member && member.kickedBy ? buildApiPeerId(member.kickedBy, 'user') : undefined,
    promotedByUserId: 'promotedBy' in member && member.promotedBy
      ? buildApiPeerId(member.promotedBy, 'user')
      : undefined,
    bannedRights: 'bannedRights' in member ? omitVirtualClassFields(member.bannedRights) : undefined,
    adminRights: 'adminRights' in member ? omitVirtualClassFields(member.adminRights) : undefined,
    isViaRequest: 'viaRequest' in member ? member.viaRequest : undefined,
    ...((member instanceof GramJs.ChannelParticipantAdmin || member instanceof GramJs.ChatParticipantAdmin) && {
      isAdmin: true,
    }),
    ...((member instanceof GramJs.ChannelParticipantCreator || member instanceof GramJs.ChatParticipantCreator) && {
      isOwner: true,
    }),
  };
}

export function buildChatMembers(
  participants: GramJs.TypeChatParticipants | GramJs.channels.ChannelParticipants,
) {
  // Duplicate code because of TS union-type shenanigans
  if (participants instanceof GramJs.ChatParticipants) {
    return participants.participants.map(buildChatMember).filter(Boolean);
  }
  if (participants instanceof GramJs.channels.ChannelParticipants) {
    return participants.participants.map(buildChatMember).filter(Boolean);
  }

  return undefined;
}

export function buildChatTypingStatus(
  update: GramJs.UpdateUserTyping | GramJs.UpdateChatUserTyping | GramJs.UpdateChannelUserTyping,
): ApiTypingStatus | undefined {
  const action = update.action;
  const timestamp = getServerTime();
  const buildTypingStatus = (
    type: Exclude<ApiTypingStatus['type'], 'watchingAnimations'>,
  ): ApiTypingStatus => ({
    timestamp,
    type,
  });

  if (action instanceof GramJs.SendMessageCancelAction) {
    return undefined;
  }
  if (action instanceof GramJs.SendMessageTypingAction) {
    return buildTypingStatus('typing');
  }
  if (action instanceof GramJs.SendMessageRecordVideoAction) {
    return buildTypingStatus('recordVideo');
  }
  if (action instanceof GramJs.SendMessageUploadVideoAction) {
    return buildTypingStatus('uploadVideo');
  }
  if (action instanceof GramJs.SendMessageRecordAudioAction) {
    return buildTypingStatus('recordAudio');
  }
  if (action instanceof GramJs.SendMessageUploadAudioAction) {
    return buildTypingStatus('uploadAudio');
  }
  if (action instanceof GramJs.SendMessageUploadPhotoAction) {
    return buildTypingStatus('uploadPhoto');
  }
  if (action instanceof GramJs.SendMessageUploadDocumentAction) {
    return buildTypingStatus('uploadFile');
  }
  if (action instanceof GramJs.SendMessageGeoLocationAction) {
    return buildTypingStatus('chooseLocation');
  }
  if (action instanceof GramJs.SendMessageChooseContactAction) {
    return buildTypingStatus('chooseContact');
  }
  if (action instanceof GramJs.SendMessageGamePlayAction) {
    return buildTypingStatus('playingGame');
  }
  if (action instanceof GramJs.SendMessageRecordRoundAction) {
    return buildTypingStatus('recordRound');
  }
  if (action instanceof GramJs.SendMessageUploadRoundAction) {
    return buildTypingStatus('uploadRound');
  }
  if (action instanceof GramJs.SendMessageChooseStickerAction) {
    return buildTypingStatus('chooseSticker');
  }
  if (action instanceof GramJs.SpeakingInGroupCallAction) {
    return undefined;
  }
  if (action instanceof GramJs.SendMessageEmojiInteractionSeen) {
    return {
      timestamp,
      type: 'watchingAnimations',
      emoji: action.emoticon,
    };
  }
  if (action instanceof GramJs.SendMessageEmojiInteraction) {
    return undefined;
  }

  return undefined;
}

export function buildApiChatFolder(filter: GramJs.DialogFilter | GramJs.DialogFilterChatlist): ApiChatFolder {
  if (filter instanceof GramJs.DialogFilterChatlist) {
    return {
      ...pickTruthy(filter, [
        'id', 'emoticon',
      ]),
      excludedChatIds: [],
      includedChatIds: filter.includePeers.map(getApiChatIdFromMtpPeer).filter(Boolean),
      pinnedChatIds: filter.pinnedPeers.map(getApiChatIdFromMtpPeer).filter(Boolean),
      hasMyInvites: filter.hasMyInvites,
      isChatList: true,
      noTitleAnimations: filter.titleNoanimate,
      color: filter.color,
      title: buildApiFormattedText(filter.title),
    };
  }

  return {
    ...pickTruthy(filter, [
      'id', 'emoticon', 'contacts', 'nonContacts', 'groups', 'bots',
      'excludeMuted', 'excludeRead', 'excludeArchived',
    ]),
    channels: filter.broadcasts,
    pinnedChatIds: filter.pinnedPeers.map(getApiChatIdFromMtpPeer).filter(Boolean),
    includedChatIds: filter.includePeers.map(getApiChatIdFromMtpPeer).filter(Boolean),
    excludedChatIds: filter.excludePeers.map(getApiChatIdFromMtpPeer).filter(Boolean),
    color: filter.color,
    title: buildApiFormattedText(filter.title),
    noTitleAnimations: filter.titleNoanimate,
  };
}

export function buildApiChatFolderFromSuggested({
  filter, description,
}: {
  filter: GramJs.TypeDialogFilter;
  description: string;
}): ApiChatFolder | undefined {
  if (!(filter instanceof GramJs.DialogFilter || filter instanceof GramJs.DialogFilterChatlist)) return undefined;
  return {
    ...buildApiChatFolder(filter),
    description,
  };
}

export function buildApiChatBotCommands(botInfos: GramJs.BotInfo[]) {
  return botInfos.reduce((botCommands, botInfo) => {
    const botId = buildApiPeerId(botInfo.userId!, 'user');

    if (botInfo.commands) {
      botCommands = botCommands.concat(botInfo.commands.map((mtpCommand) => ({
        botId,
        ...omitVirtualClassFields(mtpCommand),
      })));
    }

    return botCommands;
  }, [] as ApiBotCommand[]);
}

export function buildApiExportedInvite(invite: GramJs.ChatInviteExported): ApiExportedInvite {
  const {
    revoked,
    date,
    expireDate,
    link,
    permanent,
    startDate,
    usage,
    usageLimit,
    requested,
    requestNeeded,
    title,
    adminId,
  } = invite;
  return {
    isRevoked: revoked,
    date,
    expireDate,
    link,
    isPermanent: permanent,
    startDate,
    usage,
    usageLimit,
    isRequestNeeded: requestNeeded,
    requested,
    title,
    adminId: buildApiPeerId(adminId, 'user'),
  };
}

export function buildChatInviteImporter(importer: GramJs.ChatInviteImporter): ApiChatInviteImporter {
  const {
    userId,
    date,
    about,
    requested,
    viaChatlist,
  } = importer;
  return {
    userId: buildApiPeerId(userId, 'user'),
    date,
    about,
    isRequested: requested,
    isFromChatList: viaChatlist,
  };
}

export function buildApiChatReactions(chatReactions?: GramJs.TypeChatReactions): ApiChatReactions | undefined {
  if (chatReactions instanceof GramJs.ChatReactionsAll) {
    return {
      type: 'all',
      areCustomAllowed: chatReactions.allowCustom,
    };
  }
  if (chatReactions instanceof GramJs.ChatReactionsSome) {
    return {
      type: 'some',
      allowed: chatReactions.reactions.map((r) => buildApiReaction(r)).filter(Boolean),
    };
  }

  return undefined;
}

export function buildApiSendAsPeerId(sendAs: GramJs.SendAsPeer): ApiSendAsPeerId {
  return {
    id: getApiChatIdFromMtpPeer(sendAs.peer),
    isPremium: sendAs.premiumRequired,
  };
}

export function buildApiChatlistInvite(
  invite: GramJs.chatlists.TypeChatlistInvite | undefined, slug: string,
): ApiChatlistInvite | undefined {
  if (invite instanceof GramJs.chatlists.ChatlistInvite) {
    return {
      slug,
      title: buildApiFormattedText(invite.title),
      noTitleAnimations: invite.titleNoanimate,
      emoticon: invite.emoticon,
      peerIds: invite.peers.map(getApiChatIdFromMtpPeer).filter(Boolean),
    };
  }

  if (invite instanceof GramJs.chatlists.ChatlistInviteAlready) {
    return {
      slug,
      folderId: invite.filterId,
      missingPeerIds: invite.missingPeers.map(getApiChatIdFromMtpPeer).filter(Boolean),
      alreadyPeerIds: invite.alreadyPeers.map(getApiChatIdFromMtpPeer).filter(Boolean),
    };
  }

  return undefined;
}

export function buildApiChatlistExportedInvite(
  invite: GramJs.TypeExportedChatlistInvite | undefined,
): ApiChatlistExportedInvite | undefined {
  if (!(invite instanceof GramJs.ExportedChatlistInvite)) return undefined;

  const {
    title,
    url,
    peers,
  } = invite;

  return {
    title,
    url,
    peerIds: peers.map(getApiChatIdFromMtpPeer).filter(Boolean),
  };
}

export function buildApiMissingInvitedUser(
  user: GramJs.TypeMissingInvitee,
): ApiMissingInvitedUser {
  return {
    id: user.userId.toString(),
    isRequiringPremiumToMessage: user.premiumRequiredForPm,
    isRequiringPremiumToInvite: user.premiumWouldAllowInvite,
  };
}

export function buildApiSponsoredMessageReportResult(
  result: GramJs.channels.TypeSponsoredMessageReportResult,
): ApiSponsoredMessageReportResult {
  if (result instanceof GramJs.channels.SponsoredMessageReportResultReported) {
    return {
      type: 'reported',
    };
  }

  if (result instanceof GramJs.channels.SponsoredMessageReportResultAdsHidden) {
    return {
      type: 'hidden',
    };
  }

  const title = result.title;
  const options = result.options.map((option) => ({
    text: option.text,
    option: serializeBytes(option.option),
  }));

  return {
    type: 'selectOption',
    title,
    options,
  };
}

export function buildApiChatInviteInfo(invite: GramJs.ChatInvite): ApiChatInviteInfo {
  const {
    color, participants, participantsCount, photo, title, about, scam, fake, verified, megagroup, channel, broadcast,
    requestNeeded, subscriptionFormId, subscriptionPricing, canRefulfillSubscription, botVerification,
  } = invite;

  let apiPhoto;
  if (photo instanceof GramJs.Photo) {
    addPhotoToLocalDb(photo);
    apiPhoto = buildApiPhoto(photo);
  }

  participants?.forEach(addUserToLocalDb);

  return {
    title,
    about,
    isFake: fake,
    isScam: scam,
    isVerified: verified,
    isSuperGroup: megagroup,
    isPublic: invite.public,
    participantsCount,
    color,
    isChannel: channel,
    isBroadcast: broadcast,
    isRequestNeeded: requestNeeded,
    photo: apiPhoto,
    subscriptionFormId: subscriptionFormId?.toString(),
    subscriptionPricing: subscriptionPricing && buildApiStarsSubscriptionPricing(subscriptionPricing),
    canRefulfillSubscription,
    participantIds: participants?.map((participant) => buildApiPeerId(participant.id, 'user')).filter(Boolean),
    botVerification: botVerification && buildApiBotVerification(botVerification),
  };
}

export function buildApiStarsSubscriptionPricing(
  pricing: GramJs.StarsSubscriptionPricing,
): ApiStarsSubscriptionPricing {
  return {
    period: pricing.period,
    amount: toJSNumber(pricing.amount),
  };
}

export function buildApiSponsoredPeer(sponsoredPeer: GramJs.SponsoredPeer): ApiSponsoredPeer {
  const {
    peer, randomId, additionalInfo, sponsorInfo,
  } = sponsoredPeer;

  return {
    peerId: getApiChatIdFromMtpPeer(peer),
    randomId: serializeBytes(randomId),
    additionalInfo,
    sponsorInfo,
  };
}

export function buildThreadReadState(
  input: GramJs.Dialog | GramJs.MonoForumDialog | GramJs.ForumTopic | GramJs.messages.DiscussionMessage,
): ThreadReadState {
  const { unreadCount, readInboxMaxId, readOutboxMaxId } = input;
  const dialog = input instanceof GramJs.Dialog ? input : undefined;
  const monoForumDialog = input instanceof GramJs.MonoForumDialog ? input : undefined;
  const forumTopic = input instanceof GramJs.ForumTopic ? input : undefined;

  const { unreadReactionsCount } = dialog || monoForumDialog || forumTopic || {};
  const { unreadMentionsCount, unreadPollVotesCount } = dialog || forumTopic || {};
  const { unreadMark } = dialog || monoForumDialog || {};

  return omitUndefined<ThreadReadState>({
    unreadCount,
    lastReadInboxMessageId: readInboxMaxId,
    lastReadOutboxMessageId: readOutboxMaxId,
    unreadReactionsCount,
    unreadPollVotesCount,
    unreadMentionsCount,
    hasUnreadMark: unreadMark,
  });
}

export function buildApiThreadInfoFromDialog(
  chatId: string, dialog: GramJs.Dialog | GramJs.SavedDialog,
): ApiThreadInfo {
  const isSavedDialog = dialog instanceof GramJs.SavedDialog;
  const { topMessage } = dialog;
  return {
    isCommentsInfo: false,
    chatId,
    threadId: isSavedDialog ? getApiChatIdFromMtpPeer(dialog.peer) : MAIN_THREAD_ID,
    lastMessageId: topMessage,
  };
}
