/**
 * @copyright 2026 NHCarrigan
 * @license Naomi's Public License
 * @author Naomi Carrigan
 */

import type {
  LeaderboardResponse,
  SuggestionsLeaderboard,
  LikesLeaderboard,
  CommentsLeaderboard,
  OverallLeaderboard,
} from "@library/shared-types";
import { prisma } from "../lib/prisma";

export class LeaderboardService {
  private prisma = prisma;

  constructor() {}

  /**
   * Get top users by suggestions submitted and accepted.
   */
  async getTopSuggestions(limit = 25): Promise<SuggestionsLeaderboard[]> {
    const users = await this.prisma.user.findMany({
      where: { profilePublic: true, isBanned: false },
      include: {
        suggestions: {
          select: {
            status: true,
          },
        },
      },
    });

    const leaderboard = users
      .map((user) => {
        const totalSuggestions = user.suggestions.length;
        const acceptedSuggestions = user.suggestions.filter(
          (s) => s.status === "ACCEPTED"
        ).length;
        const acceptanceRate =
          totalSuggestions > 0
            ? Math.round((acceptedSuggestions / totalSuggestions) * 100)
            : 0;

        return {
          id: user.id,
          username: user.username,
          slug: user.slug,
          avatar: user.avatar,
          primaryBadge: user.primaryBadge,
          isVip: user.isVip,
          isMod: user.isMod,
          isStaff: user.isStaff,
          createdAt: user.createdAt,
          totalSuggestions,
          acceptedSuggestions,
          acceptanceRate,
        };
      })
      .filter((user) => user.totalSuggestions > 0)
      .sort((a, b) => {
        if (b.totalSuggestions !== a.totalSuggestions) {
          return b.totalSuggestions - a.totalSuggestions;
        }
        return b.acceptanceRate - a.acceptanceRate;
      })
      .slice(0, limit);

    return leaderboard;
  }

  /**
   * Get top users by likes given.
   */
  async getTopLikes(limit = 25): Promise<LikesLeaderboard[]> {
    const users = await this.prisma.user.findMany({
      where: { profilePublic: true, isBanned: false },
      include: {
        likes: true,
      },
    });

    const leaderboard = users
      .map((user) => ({
        id: user.id,
        username: user.username,
        slug: user.slug,
        avatar: user.avatar,
        primaryBadge: user.primaryBadge,
        isVip: user.isVip,
        isMod: user.isMod,
        isStaff: user.isStaff,
        createdAt: user.createdAt,
        totalLikes: user.likes.length,
      }))
      .filter((user) => user.totalLikes > 0)
      .sort((a, b) => b.totalLikes - a.totalLikes)
      .slice(0, limit);

    return leaderboard;
  }

  /**
   * Get top users by comments posted.
   */
  async getTopComments(limit = 25): Promise<CommentsLeaderboard[]> {
    const users = await this.prisma.user.findMany({
      where: { profilePublic: true, isBanned: false },
      include: {
        comments: true,
      },
    });

    const leaderboard = users
      .map((user) => ({
        id: user.id,
        username: user.username,
        slug: user.slug,
        avatar: user.avatar,
        primaryBadge: user.primaryBadge,
        isVip: user.isVip,
        isMod: user.isMod,
        isStaff: user.isStaff,
        createdAt: user.createdAt,
        totalComments: user.comments.length,
      }))
      .filter((user) => user.totalComments > 0)
      .sort((a, b) => b.totalComments - a.totalComments)
      .slice(0, limit);

    return leaderboard;
  }

  /**
   * Get overall leaderboard based on combined engagement.
   */
  async getOverallLeaderboard(limit = 25): Promise<OverallLeaderboard[]> {
    const users = await this.prisma.user.findMany({
      where: { profilePublic: true, isBanned: false },
      include: {
        suggestions: true,
        likes: true,
        comments: true,
        userAchievements: true,
      },
    });

    const leaderboard = users
      .map((user) => {
        const totalSuggestions = user.suggestions.length;
        const totalLikes = user.likes.length;
        const totalComments = user.comments.length;
        const achievementCount = user.userAchievements.length;

        const diversityScore =
          (totalSuggestions > 0 ? 1 : 0) +
          (totalLikes > 0 ? 1 : 0) +
          (totalComments > 0 ? 1 : 0);

        return {
          id: user.id,
          username: user.username,
          slug: user.slug,
          avatar: user.avatar,
          primaryBadge: user.primaryBadge,
          isVip: user.isVip,
          isMod: user.isMod,
          isStaff: user.isStaff,
          createdAt: user.createdAt,
          totalSuggestions,
          totalLikes,
          totalComments,
          achievementCount,
          achievementPoints: user.achievementPoints,
          currentStreak: user.currentStreak,
          diversityScore,
        };
      })
      .filter(
        (user) =>
          user.totalSuggestions > 0 ||
          user.totalLikes > 0 ||
          user.totalComments > 0
      )
      .sort((a, b) => {
        if (b.achievementPoints !== a.achievementPoints) {
          return b.achievementPoints - a.achievementPoints;
        }
        if (b.diversityScore !== a.diversityScore) {
          return b.diversityScore - a.diversityScore;
        }
        const totalA = a.totalSuggestions + a.totalLikes + a.totalComments;
        const totalB = b.totalSuggestions + b.totalLikes + b.totalComments;
        return totalB - totalA;
      })
      .slice(0, limit);

    return leaderboard;
  }

  /**
   * Get all leaderboards at once.
   */
  async getAllLeaderboards(limit = 25): Promise<LeaderboardResponse> {
    const [topSuggestions, topLikes, topComments, topOverall] =
      await Promise.all([
        this.getTopSuggestions(limit),
        this.getTopLikes(limit),
        this.getTopComments(limit),
        this.getOverallLeaderboard(limit),
      ]);

    return {
      topSuggestions,
      topLikes,
      topComments,
      topOverall,
    };
  }
}
