import { ExternalGameRatingProfile } from '@core/identity/domain/entities/ExternalGameRatingProfile';
import { ExternalGameRatingRepository, PaginatedQueryOptions, PaginatedResult } from '@core/identity/domain/repositories/ExternalGameRatingRepository';

/**
 * In-Memory Implementation: IExternalGameRatingRepository
 * 
 * For testing and development purposes.
 */
export class InMemoryExternalGameRatingRepository implements ExternalGameRatingRepository {
  private profiles: Map<string, ExternalGameRatingProfile> = new Map();

  private getKey(userId: string, gameKey: string): string {
    return `${userId}|${gameKey}`;
  }

  async findByUserIdAndGameKey(
    userId: string,
    gameKey: string
  ): Promise<ExternalGameRatingProfile | null> {
    const key = this.getKey(userId, gameKey);
    return this.profiles.get(key) || null;
  }

  async findByUserId(userId: string): Promise<ExternalGameRatingProfile[]> {
    return Array.from(this.profiles.values()).filter(
      p => p.userId.toString() === userId
    );
  }

  async findByGameKey(gameKey: string): Promise<ExternalGameRatingProfile[]> {
    return Array.from(this.profiles.values()).filter(
      p => p.gameKey.toString() === gameKey
    );
  }

  async save(profile: ExternalGameRatingProfile): Promise<ExternalGameRatingProfile> {
    const key = this.getKey(profile.userId.toString(), profile.gameKey.toString());
    this.profiles.set(key, profile);
    return profile;
  }

  async saveMany(profiles: ExternalGameRatingProfile[]): Promise<ExternalGameRatingProfile[]> {
    for (const profile of profiles) {
      await this.save(profile);
    }
    return profiles;
  }

  async delete(userId: string, gameKey: string): Promise<boolean> {
    const key = this.getKey(userId, gameKey);
    return this.profiles.delete(key);
  }

  async exists(userId: string, gameKey: string): Promise<boolean> {
    const key = this.getKey(userId, gameKey);
    return this.profiles.has(key);
  }

  async findProfilesPaginated(userId: string, options?: PaginatedQueryOptions): Promise<PaginatedResult<ExternalGameRatingProfile>> {
    const allProfiles = await this.findByUserId(userId);
    
    // Apply filters
    let filtered = allProfiles;
    if (options?.filter) {
      const filter = options.filter;
      if (filter.gameKeys) {
        filtered = filtered.filter(p => filter.gameKeys!.includes(p.gameKey.toString()));
      }
      if (filter.sources) {
        filtered = filtered.filter(p => filter.sources!.includes(p.provenance.source));
      }
      if (filter.verified !== undefined) {
        filtered = filtered.filter(p => p.provenance.verified === filter.verified);
      }
      if (filter.lastSyncedAfter) {
        filtered = filtered.filter(p => p.provenance.lastSyncedAt >= filter.lastSyncedAfter!);
      }
    }

    const total = filtered.length;
    const limit = options?.limit ?? 10;
    const offset = options?.offset ?? 0;
    const items = filtered.slice(offset, offset + limit);
    const hasMore = offset + limit < total;
    const nextOffset = hasMore ? offset + limit : undefined;

    const result: PaginatedResult<ExternalGameRatingProfile> = {
      items,
      total,
      limit,
      offset,
      hasMore
    };
    
    if (nextOffset !== undefined) {
      result.nextOffset = nextOffset;
    }

    return result;
  }

  // Helper method for testing
  clear(): void {
    this.profiles.clear();
  }

  // Helper method for testing
  getAll(): ExternalGameRatingProfile[] {
    return Array.from(this.profiles.values());
  }
}
