import { builder } from "../builder";
import { LeaderboardEntryType, UserGamificationType, AchievementType } from "../types/index";
import {
  user_stats,
  users,
  user_achievements,
  achievements,
  user_points,
} from "../../db/schema/index";
import { eq, desc, gt, count, isNotNull, and } from "drizzle-orm";

builder.queryField("leaderboard", (t) =>
  t.field({
    type: [LeaderboardEntryType],
    args: {
      limit: t.arg.int(),
      offset: t.arg.int(),
    },
    resolve: async (_root, args, ctx) => {
      const limit = Math.min(args.limit || 100, 500);
      const offset = args.offset || 0;

      const entries = await ctx.db
        .select({
          user_id: user_stats.user_id,
          display_name: users.artist_name,
          avatar: users.avatar,
          total_weighted_points: user_stats.total_weighted_points,
          total_raw_points: user_stats.total_raw_points,
          recordings_count: user_stats.recordings_count,
          playbacks_count: user_stats.playbacks_count,
          achievements_count: user_stats.achievements_count,
        })
        .from(user_stats)
        .leftJoin(users, eq(user_stats.user_id, users.id))
        .orderBy(desc(user_stats.total_weighted_points))
        .limit(limit)
        .offset(offset);

      return entries.map((e, i) => ({ ...e, rank: offset + i + 1 }));
    },
  }),
);

builder.queryField("userGamification", (t) =>
  t.field({
    type: UserGamificationType,
    nullable: true,
    args: {
      userId: t.arg.string({ required: true }),
    },
    resolve: async (_root, args, ctx) => {
      const stats = await ctx.db
        .select()
        .from(user_stats)
        .where(eq(user_stats.user_id, args.userId))
        .limit(1);

      let rank = 1;
      if (stats[0]) {
        const rankResult = await ctx.db
          .select({ count: count() })
          .from(user_stats)
          .where(gt(user_stats.total_weighted_points, stats[0].total_weighted_points || 0));
        rank = (rankResult[0]?.count || 0) + 1;
      }

      const userAchievements = await ctx.db
        .select({
          id: achievements.id,
          code: achievements.code,
          name: achievements.name,
          description: achievements.description,
          icon: achievements.icon,
          category: achievements.category,
          date_unlocked: user_achievements.date_unlocked,
          progress: user_achievements.progress,
          required_count: achievements.required_count,
        })
        .from(user_achievements)
        .leftJoin(achievements, eq(user_achievements.achievement_id, achievements.id))
        .where(
          and(
            eq(user_achievements.user_id, args.userId),
            isNotNull(user_achievements.date_unlocked),
          ),
        )
        .orderBy(desc(user_achievements.date_unlocked));

      const recentPoints = await ctx.db
        .select({
          action: user_points.action,
          points: user_points.points,
          date_created: user_points.date_created,
          recording_id: user_points.recording_id,
        })
        .from(user_points)
        .where(eq(user_points.user_id, args.userId))
        .orderBy(desc(user_points.date_created))
        .limit(10);

      return {
        stats: stats[0] ? { ...stats[0], rank } : null,
        achievements: userAchievements.map((a) => ({
          id: a.id!,
          code: a.code!,
          name: a.name!,
          description: a.description!,
          icon: a.icon!,
          category: a.category!,
          required_count: a.required_count!,
          progress: a.progress!,
          date_unlocked: a.date_unlocked!,
        })),
        recent_points: recentPoints,
      };
    },
  }),
);

builder.queryField("achievements", (t) =>
  t.field({
    type: [AchievementType],
    resolve: async (_root, _args, ctx) => {
      return ctx.db
        .select()
        .from(achievements)
        .where(eq(achievements.status, "published"))
        .orderBy(achievements.sort);
    },
  }),
);
