import {InsertReaction, SelectReaction} from '@modules/chats/db/interfaces';
import {
  HuDataMember,
  Reaction,
  ReactionWithUser,
  ReactionEvent,
  ReactionInfo,
  UserReaction,
} from '@modules/chats/interfaces';
import {persistedUserId} from '@services/localStorage';
import {getUlid} from '@shared/utils';

import {getReactionText} from '../reactions';

export const mapReactionWithUserInfo = ({
  serviceData,
  users,
}: {
  serviceData: Reaction[];
  users: Record<number, HuDataMember>;
}): ReactionWithUser[] => {
  return serviceData.map(reaction => ({
    name: reaction.name,
    count: reaction.count,
    users: reaction.users.map(user => users[Number(user)]),
  }));
};

export const mapReactionToDB = (
  reaction: Reaction,
  messageId: string,
): InsertReaction[] => {
  return reaction.users.map(user => ({
    message_id: messageId,
    user_id: Number(user),
    name: reaction.name,
    ts: getUlid(),
  }));
};

export const mapUserReactionToDB = (
  reaction: UserReaction,
  messageId: string,
): InsertReaction => {
  return {
    message_id: messageId,
    user_id: reaction.userId,
    name: reaction.reactionName,
    ts: getUlid(),
  };
};

export const mapReactionFromEvent = (
  event: Pick<ReactionEvent, 'reactions'>,
  users: Record<number, HuDataMember>,
): ReactionWithUser[] => {
  return event.reactions.map(reaction => ({
    name: reaction.name,
    count: reaction.count,
    users: reaction.users.map(user => users[Number(user)]),
  }));
};

export const mapReactionsFromServer = (
  reactions: ReactionWithUser[],
): Reaction[] => {
  return reactions.map(reaction => ({
    name: reaction.name,
    count: reaction.count,
    users: reaction.users.map(user => user.id.toString()),
  }));
};

export const mapReactionToStore = ({
  reactionsWithUser,
  reactions,
}: {
  reactionsWithUser?: ReactionWithUser[];
  reactions?: Reaction[];
}): ReactionInfo => {
  const result: ReactionInfo = {
    summary: [],
    userReactions: [],
    list: [],
  };
  const isProcessingReactionsWithUser = reactionsWithUser !== undefined;

  const reactionsToProcess = reactionsWithUser || reactions || [];

  for (const reaction of reactionsToProcess) {
    for (const user of reaction.users) {
      const isUserInfo = typeof user === 'object';
      if (
        (isUserInfo && user.id === persistedUserId) ||
        (typeof user === 'string' && Number(user) === persistedUserId)
      ) {
        result.userReactions.push(reaction.name);
      }
    }

    result.summary.push({
      name: reaction.name,
      count: reaction.count,
      text: getReactionText(reaction),
      hasUserReaction: result.userReactions.includes(reaction.name),
    });

    if (isProcessingReactionsWithUser) {
      result.list.push(reaction as ReactionWithUser);
    }
  }

  return result;
};

export const mapReactionsFromDB = (reactions: SelectReaction[]): Reaction[] => {
  const result: Record<string, Reaction> = {};
  for (const reaction of reactions) {
    if (!result[reaction.name]) {
      result[reaction.name] = {
        name: reaction.name,
        count: 0,
        users: [],
      };
    }
    result[reaction.name].count += 1;
    result[reaction.name].users.push(reaction.user_id.toString());
  }
  return Object.values(result);
};

export const mapReactionWithUserToDB = (
  reactions: ReactionWithUser[],
  messageId: string,
): InsertReaction[] => {
  const result: InsertReaction[] = [];
  reactions.forEach(reaction => {
    reaction.users.forEach(user => {
      result.push({
        message_id: messageId,
        user_id: user.id,
        name: reaction.name,
        ts: getUlid(),
      });
    });
  });
  return result;
};
