import { Module } from '@nestjs/common';

import { LoggingModule } from '../../domain/logging/LoggingModule';

import type { Logger } from '@core/shared/application/Logger';

import { InMemoryAchievementRepository } from '@adapters/identity/persistence/inmemory/InMemoryAchievementRepository';

import { ACHIEVEMENT_REPOSITORY_TOKEN } from '../achievement/AchievementPersistenceTokens';
import { Achievement, AchievementCategory } from '@core/identity/domain/entities/Achievement';
import { UserAchievement } from '@core/identity/domain/entities/UserAchievement';

// Adapter to convert between domain repository interface and application use case interface
class InMemoryAchievementRepositoryAdapter {
  constructor(private readonly inMemoryRepo: InMemoryAchievementRepository) {}

  // Application use case interface methods
  async save(achievement: Achievement): Promise<void> {
    await this.inMemoryRepo.createAchievement(achievement);
  }

  async findById(id: string): Promise<Achievement | null> {
    return await this.inMemoryRepo.findAchievementById(id);
  }

  // Delegate all other methods to the underlying in-memory repository
  async findAchievementById(id: string): Promise<Achievement | null> {
    return await this.inMemoryRepo.findAchievementById(id);
  }

  async findAllAchievements(): Promise<Achievement[]> {
    return await this.inMemoryRepo.findAllAchievements();
  }

  async findAchievementsByCategory(category: AchievementCategory): Promise<Achievement[]> {
    return await this.inMemoryRepo.findAchievementsByCategory(category);
  }

  async createAchievement(achievement: Achievement): Promise<Achievement> {
    return await this.inMemoryRepo.createAchievement(achievement);
  }

  async findUserAchievementById(id: string): Promise<UserAchievement | null> {
    return await this.inMemoryRepo.findUserAchievementById(id);
  }

  async findUserAchievementsByUserId(userId: string): Promise<UserAchievement[]> {
    return await this.inMemoryRepo.findUserAchievementsByUserId(userId);
  }

  async findUserAchievementByUserAndAchievement(userId: string, achievementId: string): Promise<UserAchievement | null> {
    return await this.inMemoryRepo.findUserAchievementByUserAndAchievement(userId, achievementId);
  }

  async hasUserEarnedAchievement(userId: string, achievementId: string): Promise<boolean> {
    return await this.inMemoryRepo.hasUserEarnedAchievement(userId, achievementId);
  }

  async createUserAchievement(userAchievement: UserAchievement): Promise<UserAchievement> {
    return await this.inMemoryRepo.createUserAchievement(userAchievement);
  }

  async updateUserAchievement(userAchievement: UserAchievement): Promise<UserAchievement> {
    return await this.inMemoryRepo.updateUserAchievement(userAchievement);
  }

  async getAchievementLeaderboard(limit: number): Promise<{ userId: string; points: number; count: number }[]> {
    return await this.inMemoryRepo.getAchievementLeaderboard(limit);
  }

  async getUserAchievementStats(userId: string): Promise<{
    total: number;
    points: number;
    byCategory: Record<AchievementCategory, number>;
  }> {
    return await this.inMemoryRepo.getUserAchievementStats(userId);
  }
}

@Module({
  imports: [LoggingModule],
  providers: [
    {
      provide: ACHIEVEMENT_REPOSITORY_TOKEN,
      useFactory: (logger: Logger) => 
        new InMemoryAchievementRepositoryAdapter(new InMemoryAchievementRepository(logger)),
      inject: ['Logger'],
    },
  ],
  exports: [ACHIEVEMENT_REPOSITORY_TOKEN],
})
export class InMemoryAchievementPersistenceModule {}