/**
 * Infrastructure Adapter: InMemoryMediaRepository
 * 
 * In-memory implementation of MediaRepository for testing purposes.
 * Stores media entities in memory for fast, deterministic testing.
 */

import type { Media } from '@core/media/domain/entities/Media';
import type { MediaRepository } from '@core/media/domain/repositories/MediaRepository';
import type { Logger } from '@core/shared/domain/Logger';

export class InMemoryMediaRepository implements MediaRepository {
  private media: Map<string, Media> = new Map();
  private uploadedByMedia: Map<string, Media[]> = new Map();

  constructor(private readonly logger: Logger) {
    this.logger.info('[InMemoryMediaRepository] Initialized.');
  }

  async save(media: Media): Promise<void> {
    this.logger.debug(`[InMemoryMediaRepository] Saving media: ${media.id} for uploader: ${media.uploadedBy}`);
    
    // Store by ID
    this.media.set(media.id, media);
    
    // Store by uploader
    if (!this.uploadedByMedia.has(media.uploadedBy)) {
      this.uploadedByMedia.set(media.uploadedBy, []);
    }
    
    const uploaderMedia = this.uploadedByMedia.get(media.uploadedBy)!;
    const existingIndex = uploaderMedia.findIndex(m => m.id === media.id);
    
    if (existingIndex > -1) {
      uploaderMedia[existingIndex] = media;
    } else {
      uploaderMedia.push(media);
    }
    
    this.logger.info(`Media ${media.id} for uploader ${media.uploadedBy} saved successfully.`);
  }

  async findById(id: string): Promise<Media | null> {
    this.logger.debug(`[InMemoryMediaRepository] Finding media by ID: ${id}`);
    const media = this.media.get(id) ?? null;
    
    if (media) {
      this.logger.info(`Found media by ID: ${id}`);
    } else {
      this.logger.warn(`Media with ID ${id} not found.`);
    }
    
    return media;
  }

  async findByUploadedBy(uploadedBy: string): Promise<Media[]> {
    this.logger.debug(`[InMemoryMediaRepository] Finding all media for uploader: ${uploadedBy}`);
    
    const uploaderMedia = this.uploadedByMedia.get(uploadedBy) ?? [];
    this.logger.info(`Found ${uploaderMedia.length} media files for uploader ${uploadedBy}.`);
    
    return uploaderMedia;
  }

  async delete(id: string): Promise<void> {
    this.logger.debug(`[InMemoryMediaRepository] Deleting media with ID: ${id}`);
    
    const mediaToDelete = this.media.get(id);
    if (!mediaToDelete) {
      this.logger.warn(`Media with ID ${id} not found for deletion.`);
      return;
    }
    
    // Remove from media map
    this.media.delete(id);
    
    // Remove from uploader media
    const uploaderMedia = this.uploadedByMedia.get(mediaToDelete.uploadedBy);
    if (uploaderMedia) {
      const filtered = uploaderMedia.filter(media => media.id !== id);
      if (filtered.length > 0) {
        this.uploadedByMedia.set(mediaToDelete.uploadedBy, filtered);
      } else {
        this.uploadedByMedia.delete(mediaToDelete.uploadedBy);
      }
    }
    
    this.logger.info(`Media ${id} deleted successfully.`);
  }

  /**
   * Clear all media from the repository
   */
  clear(): void {
    this.media.clear();
    this.uploadedByMedia.clear();
    this.logger.info('[InMemoryMediaRepository] All media cleared.');
  }

  /**
   * Get the total number of media files stored
   */
  get size(): number {
    return this.media.size;
  }
}
