/**
 * Infrastructure: InMemoryAnalyticsSnapshotRepository
 * 
 * In-memory implementation of IAnalyticsSnapshotRepository for development/testing.
 */

import { AnalyticsSnapshot, IAnalyticsSnapshotRepository, SnapshotEntityType, SnapshotPeriod } from '@core/analytics';
import { Logger } from '@core/shared/application';

export class InMemoryAnalyticsSnapshotRepository implements IAnalyticsSnapshotRepository {
  private snapshots: Map<string, AnalyticsSnapshot> = new Map();
  private readonly logger: Logger;

  constructor(logger: Logger) {
    this.logger = logger;
    this.logger.info('InMemoryAnalyticsSnapshotRepository initialized.');
  }

  async save(snapshot: AnalyticsSnapshot): Promise<void> {
    this.logger.debug(`Saving AnalyticsSnapshot: ${snapshot.id}`);
    try {
      this.snapshots.set(snapshot.id, snapshot);
      this.logger.info(`AnalyticsSnapshot ${snapshot.id} saved successfully.`);
    } catch (error) {
      this.logger.error(`Error saving AnalyticsSnapshot ${snapshot.id}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async findById(id: string): Promise<AnalyticsSnapshot | null> {
    this.logger.debug(`Finding AnalyticsSnapshot by ID: ${id}`);
    try {
      const snapshot = this.snapshots.get(id) ?? null;
      if (snapshot) {
        this.logger.info(`Found AnalyticsSnapshot with ID: ${id}`);
      } else {
        this.logger.warn(`AnalyticsSnapshot with ID ${id} not found.`);
      }
      return snapshot;
    } catch (error) {
      this.logger.error(`Error finding AnalyticsSnapshot by ID ${id}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async findByEntity(entityType: SnapshotEntityType, entityId: string): Promise<AnalyticsSnapshot[]> {
    this.logger.debug(`Finding AnalyticsSnapshots by Entity: ${entityType}, ${entityId}`);
    try {
      const snapshots = Array.from(this.snapshots.values()).filter(
        s => s.entityType === entityType && s.entityId === entityId
      );
      this.logger.info(`Found ${snapshots.length} AnalyticsSnapshots for entity ${entityId}.`);
      return snapshots;
    } catch (error) {
      this.logger.error(`Error finding AnalyticsSnapshots for entity ${entityId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async findByPeriod(
    entityType: SnapshotEntityType,
    entityId: string,
    period: SnapshotPeriod,
    startDate: Date,
    endDate: Date
  ): Promise<AnalyticsSnapshot | null> {
    this.logger.debug(`Finding AnalyticsSnapshot by Period for entity ${entityId}, period ${period}, from ${startDate.toISOString()} to ${endDate.toISOString()}`);
    try {
      const snapshot = Array.from(this.snapshots.values()).find(
        s => s.entityType === entityType &&
             s.entityId === entityId &&
             s.period === period &&
             s.startDate >= startDate &&
             s.endDate <= endDate
      ) ?? null;
      if (snapshot) {
        this.logger.info(`Found AnalyticsSnapshot for entity ${entityId}, period ${period}.`);
      } else {
        this.logger.warn(`No AnalyticsSnapshot found for entity ${entityId}, period ${period}, from ${startDate.toISOString()} to ${endDate.toISOString()}.`);
      }
      return snapshot;
    } catch (error) {
      this.logger.error(`Error finding AnalyticsSnapshot by period for entity ${entityId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async findLatest(
    entityType: SnapshotEntityType,
    entityId: string,
    period: SnapshotPeriod
  ): Promise<AnalyticsSnapshot | null> {
    this.logger.debug(`Finding latest AnalyticsSnapshot for entity ${entityId}, period ${period}`);
    try {
      const matching = Array.from(this.snapshots.values())
        .filter(s => s.entityType === entityType && s.entityId === entityId && s.period === period)
        .sort((a, b) => b.endDate.getTime() - a.endDate.getTime());
      
      const snapshot = matching[0] ?? null;
      if (snapshot) {
        this.logger.info(`Found latest AnalyticsSnapshot for entity ${entityId}, period ${period}.`);
      } else {
        this.logger.warn(`No latest AnalyticsSnapshot found for entity ${entityId}, period ${period}.`);
      }
      return snapshot;
    } catch (error) {
      this.logger.error(`Error finding latest AnalyticsSnapshot for entity ${entityId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async getHistoricalSnapshots(
    entityType: SnapshotEntityType,
    entityId: string,
    period: SnapshotPeriod,
    limit: number
  ): Promise<AnalyticsSnapshot[]> {
    this.logger.debug(`Getting historical AnalyticsSnapshots for entity ${entityId}, period ${period}, limit ${limit}`);
    try {
      const snapshots = Array.from(this.snapshots.values())
        .filter(s => s.entityType === entityType && s.entityId === entityId && s.period === period)
        .sort((a, b) => b.endDate.getTime() - a.endDate.getTime())
        .slice(0, limit);
      this.logger.info(`Found ${snapshots.length} historical AnalyticsSnapshots for entity ${entityId}, period ${period}.`);
      return snapshots;
    } catch (error) {
      this.logger.error(`Error getting historical AnalyticsSnapshots for entity ${entityId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

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

  // Helper for seeding demo data
  seed(snapshots: AnalyticsSnapshot[]): void {
    snapshots.forEach(s => this.snapshots.set(s.id, s));
  }
}