/**
 * Infrastructure Adapter: InMemoryUserRatingRepository
 * 
 * In-memory implementation of IUserRatingRepository
 */

import { UserRating } from '@core/identity/domain/value-objects/UserRating';
import type { UserRatingRepository } from '@core/identity/domain/repositories/UserRatingRepository';
import type { Logger } from '@core/shared/domain/Logger';

export class InMemoryUserRatingRepository implements UserRatingRepository {
  private ratings: Map<string, UserRating> = new Map();
  private readonly logger: Logger;

  constructor(logger: Logger, seedData?: UserRating[]) {
    this.logger = logger;
    this.logger.info('InMemoryUserRatingRepository initialized.');
    if (seedData) {
      seedData.forEach(rating => this.ratings.set(rating.userId, rating));
      this.logger.debug(`Seeded ${seedData.length} user ratings.`);
    }
  }

  async findByUserId(userId: string): Promise<UserRating | null> {
    this.logger.debug(`Finding user rating for user id: ${userId}`);
    try {
      const rating = this.ratings.get(userId) ?? null;
      if (rating) {
        this.logger.info(`Found user rating for user id: ${userId}.`);
      } else {
        this.logger.warn(`User rating for user id ${userId} not found.`);
      }
      return rating;
    } catch (error) {
      this.logger.error(`Error finding user rating for user id ${userId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async findByUserIds(userIds: string[]): Promise<UserRating[]> {
    this.logger.debug(`Finding user ratings for user ids: ${userIds.join(', ')}`);
    try {
      const results: UserRating[] = [];
      for (const userId of userIds) {
        const rating = this.ratings.get(userId);
        if (rating) {
          results.push(rating);
        } else {
          this.logger.warn(`User rating for user id ${userId} not found.`);
        }
      }
      this.logger.info(`Found ${results.length} user ratings for ${userIds.length} requested users.`);
      return results;
    } catch (error) {
      this.logger.error(`Error finding user ratings for user ids ${userIds.join(', ')}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async save(rating: UserRating): Promise<UserRating> {
    this.logger.debug(`Saving user rating for user id: ${rating.userId}`);
    try {
      if (this.ratings.has(rating.userId)) {
        this.logger.debug(`Updating existing user rating for user id: ${rating.userId}.`);
      } else {
        this.logger.debug(`Creating new user rating for user id: ${rating.userId}.`);
      }
      this.ratings.set(rating.userId, rating);
      this.logger.info(`User rating for user id ${rating.userId} saved successfully.`);
      return rating;
    } catch (error) {
      this.logger.error(`Error saving user rating for user id ${rating.userId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async getTopDrivers(limit: number): Promise<UserRating[]> {
    this.logger.debug(`Getting top ${limit} drivers.`);
    try {
      const topDrivers = Array.from(this.ratings.values())
        .filter(r => r.driver.sampleSize > 0)
        .sort((a, b) => b.driver.value - a.driver.value)
        .slice(0, limit);
      this.logger.info(`Retrieved ${topDrivers.length} top drivers.`);
      return topDrivers;
    } catch (error) {
      this.logger.error(`Error getting top drivers:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async getTopTrusted(limit: number): Promise<UserRating[]> {
    this.logger.debug(`Getting top ${limit} trusted users.`);
    try {
      const topTrusted = Array.from(this.ratings.values())
        .filter(r => r.trust.sampleSize > 0)
        .sort((a, b) => b.trust.value - a.trust.value)
        .slice(0, limit);
      this.logger.info(`Retrieved ${topTrusted.length} top trusted users.`);
      return topTrusted;
    } catch (error) {
      this.logger.error(`Error getting top trusted users:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async getEligibleStewards(): Promise<UserRating[]> {
    this.logger.debug('Getting eligible stewards.');
    try {
      const eligibleStewards = Array.from(this.ratings.values())
        .filter(r => r.canBeSteward());
      this.logger.info(`Found ${eligibleStewards.length} eligible stewards.`);
      return eligibleStewards;
    } catch (error) {
      this.logger.error(`Error getting eligible stewards:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async findByDriverTier(tier: 'rookie' | 'amateur' | 'semi-pro' | 'pro' | 'elite'): Promise<UserRating[]> {
    this.logger.debug(`Finding user ratings by driver tier: ${tier}`);
    try {
      const ratingsByTier = Array.from(this.ratings.values())
        .filter(r => r.getDriverTier() === tier);
      this.logger.info(`Found ${ratingsByTier.length} user ratings for driver tier: ${tier}.`);
      return ratingsByTier;
    } catch (error) {
      this.logger.error(`Error finding user ratings by driver tier ${tier}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async delete(userId: string): Promise<void> {
    this.logger.debug(`Deleting user rating for user id: ${userId}`);
    try {
      if (this.ratings.delete(userId)) {
        this.logger.info(`User rating for user id ${userId} deleted successfully.`);
      } else {
        this.logger.warn(`User rating for user id ${userId} not found for deletion.`);
      }
    } catch (error) {
      this.logger.error(`Error deleting user rating for user id ${userId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  // Test helper
  clear(): void {
    this.logger.debug('Clearing all user ratings.');
    this.ratings.clear();
    this.logger.info('All user ratings cleared.');
  }
}