Source: lib/db/comments/writes.js

import { ObjectID } from "bson";
import {
  getCommentsCollection,
  getInboxCollection,
  getPostsCollection,
} from "../mongodb";
import { getPostById, getUserByEmail, getUserById } from "../reads";
import { v4 as uuid } from "uuid";

/**
 * This method is responsible for creating a comment.
 * It also creates an inbox message for the post owner.
 * If the post owner is the same as the user, no inbox message is created.
 * It has a special case for the AI user, which is a bot that creates comments.
 * The AI user doesn't have a database object, so it skips getting the user's database object.
 *
 * @param {object} data - The data object
 * @param {string} data.comment - The comment text
 * @param {string} data.postId - The post ID
 * @param {object} data.session - The session object
 * @param {object} data.session.user - The user object
 * @param {string} data.session.user.name - The user's name
 * @param {string} data.session.user.email - The user's email
 * @param {string} data.session.user.image - The user's image
 * @returns {Promise<{ insertedId: string }>}
 */
export async function createComment(data) {
  const { comment, dreamId: postId, session } = data;

  // Skip getting user's database object because it doesn't really exist.
  const isAIComment = session.user.name === "Sonia";

  if (isAIComment) {
    const [collection, inboxCollection] = await Promise.all([
      getCommentsCollection(),
      getInboxCollection(),
    ]);

    const post = await getPostById(postId);
    const postOwner = await getUserById(post.userId);

    const inboxKey = uuid();

    const [result, _] = await Promise.all([
      collection.insertOne({
        // Grab the user's name from the mocked session.
        userId: session.user.name,
        userName: session.user.name,
        userEmail: session.user.email,
        userImage: session.user.image,
        dreamId: ObjectID(postId),
        dreamOwnerUserId: ObjectID(post.userId),
        createdAt: new Date().toISOString(),
        text: comment,
        inboxKey,
      }),
      inboxCollection.insertOne({
        userId: session.user.name,
        userName: session.user.name,
        userEmail: session.user.email,
        userImage: session.user.image,
        dreamId: ObjectID(postId),
        dreamOwnerUserEmail: postOwner.email,
        createdAt: new Date().toISOString(),
        type: "comment",
        read: false,
        commentKey: inboxKey,
      }),
    ]);

    if (result.insertedId) {
      const postsCollection = await getPostsCollection();

      await postsCollection.updateOne(
        {
          _id: ObjectID(postId),
        },
        { $inc: { commentCount: 1 } }
      );
    }

    return result;
  }

  if (!isAIComment) {
    const [user, collection, inboxCollection] = await Promise.all([
      getUserByEmail(session.user.email),
      getCommentsCollection(),
      getInboxCollection(),
    ]);

    const post = await getPostById(postId);
    const postOwner = await getUserById(post.userId);

    let shouldCreateNewInbox = true;
    if (postOwner.email === user.email) {
      shouldCreateNewInbox = false;
    }

    const inboxKey = uuid();

    const [result, _] = await Promise.all([
      collection.insertOne({
        userId: ObjectID(user._id),
        userName: user.name,
        userEmail: user.email,
        userImage: user.image,
        dreamId: ObjectID(postId),
        dreamOwnerUserId: ObjectID(post.userId),
        createdAt: new Date().toISOString(),
        text: comment,
        inboxKey: shouldCreateNewInbox ? inboxKey : null,
      }),
      shouldCreateNewInbox
        ? inboxCollection.insertOne({
            userId: ObjectID(user._id),
            userName: user.name,
            userEmail: user.email,
            userImage: user.image,
            dreamId: ObjectID(postId),
            dreamOwnerUserEmail: postOwner.email,
            createdAt: new Date().toISOString(),
            type: "comment",
            read: false,
            commentKey: inboxKey,
          })
        : () => null,
    ]);

    if (result.insertedId) {
      const postsCollection = await getPostsCollection();

      await postsCollection.updateOne(
        {
          _id: ObjectID(postId),
        },
        { $inc: { commentCount: 1 } }
      );
    }

    return result;
  }
}

/**
 * This method is responsible for deleting a comment from a post.
 * It also deletes the inbox message for the post owner.
 *
 * @param {string} commentId - The comment ID
 * @param {string} postId - The post ID
 * @returns {Promise<any>}
 */
export async function deleteComment(commentId, postId) {
  const [collection, postsCollection, inboxCollection] = await Promise.all([
    getCommentsCollection(),
    getPostsCollection(),
    getInboxCollection(),
  ]);

  const comment = await getCommentById(commentId);

  return await Promise.all([
    collection.deleteOne({ _id: ObjectID(commentId) }),
    postsCollection.updateOne(
      {
        _id: ObjectID(postId),
      },
      { $inc: { commentCount: -1 } }
    ),
    inboxCollection.deleteOne({
      userEmail: session.user.email,
      commentKey: comment?.inboxKey,
    }),
  ]);
}