import { GraphQLError } from "graphql";
import { builder } from "../builder";
import { CommentType, AdminCommentListType } from "../types/index";
import { comments, users } from "../../db/schema/index";
import { eq, and, desc, ilike, count } from "drizzle-orm";
import { requireOwnerOrAdmin, requireAdmin } from "../../lib/acl";
import { gamificationQueue } from "../../queues/index";

builder.queryField("commentsForVideo", (t) =>
  t.field({
    type: [CommentType],
    args: {
      videoId: t.arg.string({ required: true }),
    },
    resolve: async (_root, args, ctx) => {
      const commentList = await ctx.db
        .select()
        .from(comments)
        .where(and(eq(comments.collection, "videos"), eq(comments.item_id, args.videoId)))
        .orderBy(desc(comments.date_created));

      return Promise.all(
        commentList.map(async (c) => {
          const user = await ctx.db
            .select({
              id: users.id,
              first_name: users.first_name,
              last_name: users.last_name,
              artist_name: users.artist_name,
              avatar: users.avatar,
            })
            .from(users)
            .where(eq(users.id, c.user_id))
            .limit(1);
          return { ...c, user: user[0] || null };
        }),
      );
    },
  }),
);

builder.mutationField("createCommentForVideo", (t) =>
  t.field({
    type: CommentType,
    args: {
      videoId: t.arg.string({ required: true }),
      comment: t.arg.string({ required: true }),
    },
    resolve: async (_root, args, ctx) => {
      if (!ctx.currentUser) throw new GraphQLError("Unauthorized");

      const newComment = await ctx.db
        .insert(comments)
        .values({
          collection: "videos",
          item_id: args.videoId,
          comment: args.comment,
          user_id: ctx.currentUser.id,
        })
        .returning();

      await gamificationQueue.add("awardPoints", {
        job: "awardPoints",
        userId: ctx.currentUser.id,
        action: "COMMENT_CREATE",
      });
      await gamificationQueue.add("checkAchievements", {
        job: "checkAchievements",
        userId: ctx.currentUser.id,
        category: "social",
      });

      const user = await ctx.db
        .select({
          id: users.id,
          first_name: users.first_name,
          last_name: users.last_name,
          artist_name: users.artist_name,
          avatar: users.avatar,
        })
        .from(users)
        .where(eq(users.id, ctx.currentUser.id))
        .limit(1);

      return { ...newComment[0], user: user[0] || null };
    },
  }),
);

builder.mutationField("deleteComment", (t) =>
  t.field({
    type: "Boolean",
    args: {
      id: t.arg.int({ required: true }),
    },
    resolve: async (_root, args, ctx) => {
      const comment = await ctx.db.select().from(comments).where(eq(comments.id, args.id)).limit(1);
      if (!comment[0]) throw new GraphQLError("Comment not found");
      requireOwnerOrAdmin(ctx, comment[0].user_id);
      await ctx.db.delete(comments).where(eq(comments.id, args.id));

      await gamificationQueue.add("revokePoints", {
        job: "revokePoints",
        userId: comment[0].user_id,
        action: "COMMENT_CREATE",
      });
      await gamificationQueue.add("checkAchievements", {
        job: "checkAchievements",
        userId: comment[0].user_id,
        category: "social",
      });

      return true;
    },
  }),
);

builder.queryField("adminListComments", (t) =>
  t.field({
    type: AdminCommentListType,
    args: {
      search: t.arg.string(),
      limit: t.arg.int(),
      offset: t.arg.int(),
    },
    resolve: async (_root, args, ctx) => {
      requireAdmin(ctx);
      const limit = args.limit ?? 50;
      const offset = args.offset ?? 0;

      const conditions = args.search ? [ilike(comments.comment, `%${args.search}%`)] : [];
      const where = conditions.length > 0 ? and(...conditions) : undefined;

      const [commentList, totalRows] = await Promise.all([
        ctx.db
          .select()
          .from(comments)
          .where(where)
          .orderBy(desc(comments.date_created))
          .limit(limit)
          .offset(offset),
        ctx.db.select({ total: count() }).from(comments).where(where),
      ]);

      const items = await Promise.all(
        commentList.map(async (c) => {
          const user = await ctx.db
            .select({
              id: users.id,
              first_name: users.first_name,
              last_name: users.last_name,
              artist_name: users.artist_name,
              avatar: users.avatar,
            })
            .from(users)
            .where(eq(users.id, c.user_id))
            .limit(1);
          return { ...c, user: user[0] || null };
        }),
      );

      return { items, total: totalRows[0]?.total ?? 0 };
    },
  }),
);
