import clientPromise, { objectId, database } from "@/db.config";
import { normalizeMongoDoc } from "./helper";
import { isEmptyObject } from "@/utils/library";

export const increaseAnalytics = async (id) => {
  const client = await clientPromise;
  const db = client.db(database);
  const analytics = db.collection("analytics");

  const data = await analytics.findOne({ uid: id });

  if (!data)
    await analytics.insertOne({ uid: id, count: 1, timestamp: new Date() });
  else await analytics.updateOne({ uid: id }, { $inc: { count: 1 } });

  const doc = await analytics.findOne({ uid: id });
  return normalizeMongoDoc(doc);
};

/**
 *
 * @param {string} timeline - year, month, day, hour (default: hour)
 * @returns {Promise<[]>}
 */
export const getAnalytics = async (timeline = "month", year = null) => {
  if (!timeline) timeline = "month";
  if (!year) year = new Date().getFullYear();
  const client = await clientPromise;
  const db = client.db(database);
  const analytics = db.collection("analytics");

  const role = [
    ["year", { $year: "$timestamp" }],
    ["month", { $month: "$timestamp" }],
    ["day", { $dayOfMonth: "$timestamp" }],
    ["hour", { $hour: "$timestamp" }],
  ];

  const roleOption = Object.fromEntries(
    role.slice(0, role.findIndex((item) => item[0] === timeline) + 1)
  );
  if (isEmptyObject(roleOption)) return null;

  const result = await analytics
    .aggregate([
      { $match: { $expr: { $eq: [{ $year: "$timestamp" }, year] } } },
      {
        $group: {
          _id: roleOption,
          uniqueVisitor: { $sum: 1 },
          visitor: { $sum: "$count" },
        },
      },
      { $sort: { "_id.year": 1, "_id.month": 1, "_id.day": 1 } },
    ])
    .toArray();
  const analyticsData = result.map((data) => ({
    ...data,
    key: (() => {
      const roleKey = ["day", "month", "year", "hour"];
      const availableKey = roleKey
        .map((key) => {
          if (!data._id[key]) return null;
          if (key === "month") {
            const current = new Date();
            current.setMonth(data._id[key] - 1);
            return current.toLocaleString("default", { month: "long" });
          }
          if (key === "hour") return `${data._id[key]}:00`;

          return data._id[key];
        })
        .filter((key) => key);

      return availableKey.join(" ");
    })(),
  }));

  return normalizeMongoDoc(analyticsData);
};

export const totalPostPublished = async () => {
  const client = await clientPromise;
  const db = client.db(database);
  const post = db.collection("posts");
  const result = await post.countDocuments({ status: "published" });

  return result;
};

export const totalCategories = async () => {
  const client = await clientPromise;
  const db = client.db(database);
  const categories = db.collection("categories");
  const result = await categories.countDocuments();

  return result;
};

export const totalDraft = async () => {
  const client = await clientPromise;
  const db = client.db(database);
  const post = db.collection("posts_maintain");
  const result = await post.countDocuments({ status: "draft" });

  return result;
};

export const totalPost = async () => {
  const client = await clientPromise;
  const db = client.db(database);
  const post = db.collection("posts_maintain");
  const result = await post.countDocuments();

  return result;
};

export const popularPost = async () => {
  const client = await clientPromise;
  const db = client.db(database);
  const post = db.collection("posts");
  const result = await post
    .aggregate([
      { $match: { status: "published" } },
      { $sort: { views: -1 } },
      { $limit: 10 },
      {
        $lookup: {
          from: "users",
          localField: "author",
          foreignField: "_id",
          as: "author",
        },
      },
      { $unwind: "$author" },
      {
        $project: {
          title: 1,
          slug: 1,
          views: 1,
          "author.name": 1,
          modifiedAt: 1,
        },
      },
    ])
    .toArray();

  return normalizeMongoDoc(result);
};

export const newestPost = async () => {
  const client = await clientPromise;
  const db = client.db(database);
  const post = db.collection("posts_maintain");
  const result = await post.find().sort({ modifiedAt: -1 }).limit(5).toArray();

  return normalizeMongoDoc(result);
};
