// src/services/gamificationService.ts

import { gamificationRepo } from './db/index.db';
import type { Logger } from 'pino';
import { ForeignKeyConstraintError } from './db/errors.db';

class GamificationService {
  /**
   * Awards a specific achievement to a user.
   * @param userId The ID of the user to award the achievement.
   * @param achievementName The name of the achievement to award.
   * @param log The logger instance.
   */
  async awardAchievement(userId: string, achievementName: string, log: Logger): Promise<void> {
    try {
      await gamificationRepo.awardAchievement(userId, achievementName, log);
    } catch (error) {
      if (error instanceof ForeignKeyConstraintError) {
        // This is an expected error (e.g., achievement name doesn't exist),
        // which the repository layer should have already logged with appropriate context.
        // We re-throw it so the calling layer (e.g., an admin route) can handle it.
        throw error;
      }
      // For unexpected, generic errors, we log them at the service level before re-throwing.
      log.error(
        { error, userId, achievementName },
        'Error awarding achievement via admin endpoint:',
      );
      throw error;
    }
  }

  /**
   * Retrieves the master list of all available achievements.
   * @param log The logger instance.
   */
  async getAllAchievements(log: Logger) {
    try {
      return await gamificationRepo.getAllAchievements(log);
    } catch (error) {
      log.error({ error }, 'Error in getAllAchievements service method');
      throw error;
    }
  }

  /**
   * Retrieves the public leaderboard of top users by points.
   * @param limit The number of users to fetch.
   * @param log The logger instance.
   */
  async getLeaderboard(limit: number, log: Logger) {
    try {
      return await gamificationRepo.getLeaderboard(limit, log);
    } catch (error) {
      log.error({ error, limit }, 'Error fetching leaderboard in service method.');
      throw error;
    }
  }

  /**
   * Retrieves all achievements earned by a specific user.
   * @param userId The ID of the user.
   * @param log The logger instance.
   */
  async getUserAchievements(userId: string, log: Logger) {
    try {
      return await gamificationRepo.getUserAchievements(userId, log);
    } catch (error) {
      log.error({ error, userId }, 'Error fetching user achievements in service method.');
      throw error;
    }
  }
}

export const gamificationService = new GamificationService();