import prisma from "@/lib/prismaClient";
import { BigIntResolver } from "graphql-scalars";

//  Prisma
export const resolvers = {
  // scalars
  BigInt: BigIntResolver,
  Query: {
    getTotalGroups: async () => await prisma.groups.count(),
    getTodayStats: async () =>
      await prisma.dailyStats.findFirst({
        orderBy: {
          createdAt: "desc"
        }
      }),
    getStatsRange: async (
      _parent: unknown,
      data: { startDate: Date; endDate: Date }
      // _ctx: unknown
    ) => {
      const { startDate, endDate } = data;
      return await prisma.dailyStats.findMany({
        where: {
          createdAt: {
            gt: startDate,
            lte: endDate
          }
        },
        orderBy: {
          createdAt: "asc"
        }
      });
    },
    getTotalStats: async () =>
      await prisma.totalStats.findFirst({
        orderBy: {
          createdAt: "asc"
        }
      })
  },
  Mutation: {
    init: async () =>
      // _parent: unknown,
      // data: { newWeek: boolean; newMonth: boolean }
      // _ctx: unknown
      {
        const date = new Date().toISOString();
        let count = 0;

        if ((await prisma.dailyStats.count()) === 0) {
          await prisma.dailyStats.create({ data: { createdAt: date } });
          count++;
        }
        if ((await prisma.totalStats.count()) === 0) {
          await prisma.totalStats.create({ data: { createdAt: date } });
          count++;
        }

        return `${count} tables have been initialized with data.`;
      },
    cronJob: async () =>
      // _parent: unknown,
      // data: { newWeek: boolean; newMonth: boolean }
      // _ctx: unknown
      {
        const date = new Date().toISOString();

        await prisma.dailyStats.create({ data: { createdAt: date } });

        const allStats = await prisma.dailyStats.findMany({});

        const calculatedStats = allStats.reduce(
          (acc, curr) => {
            const links = (acc.linksDeleted += curr.linksDeleted);
            const commands = (acc.commandResponses += curr.commandResponses);
            const triggers = (acc.timesTriggered += curr.timesTriggered);

            return {
              linksDeleted: links,
              commandResponses: commands,
              timesTriggered: triggers
            };
          },
          {
            linksDeleted: 0,
            commandResponses: 0,
            timesTriggered: 0
          }
        );

        const totalStats = await prisma.totalStats.findFirst({
          orderBy: {
            createdAt: "desc"
          }
        });

        return await prisma.totalStats.update({
          where: {
            createdAt: totalStats?.createdAt
          },
          data: {
            ...calculatedStats
          }
        });
      },
    addGroup: async (
      _parent: unknown,
      data: { groupID: number; groupName: string; groupUsername: string }
      // _ctx: unknown
    ) => {
      const { groupID, groupName, groupUsername } = data;

      const existingGroup = await prisma.groups.findFirst({
        where: { telegramID: groupID }
      });

      if (existingGroup !== null) {
        if (
          existingGroup.name !== groupName ||
          existingGroup.username !== groupUsername
        ) {
          return await prisma.groups.update({
            where: {
              telegramID: existingGroup.telegramID
            },
            data: { name: groupName, username: groupUsername || "" }
          });
        }

        return existingGroup;
      }

      return await prisma.groups.create({
        data: {
          telegramID: groupID,
          name: groupName
        }
      });
    },
    incrementGroup: async (
      _parent: unknown,
      data: { groupID: number; linksDeleted: number }
      // _ctx: unknown
    ) => {
      const { groupID, linksDeleted } = data;

      return await prisma.groups.update({
        where: { telegramID: groupID },
        data: { linksDeleted: { increment: linksDeleted } }
      });
    },
    increment: async (
      _parent: unknown,
      data: { link: boolean; command: boolean; trigger: boolean }
      // _ctx: unknown
    ) => {
      const { link, command, trigger } = data;

      return await prisma.dailyStats
        .findFirst({
          orderBy: {
            createdAt: "desc"
          }
        })
        .then(async (todayStat) => {
          return await prisma.dailyStats.update({
            where: { createdAt: todayStat?.createdAt },
            data: {
              linksDeleted: { increment: link ? 1 : 0 },
              commandResponses: { increment: command ? 1 : 0 },
              timesTriggered: { increment: trigger ? 1 : 0 }
            }
          });
        });
    }
  }
};

export default resolvers;
