/**
 * In-Memory Implementation: InMemoryPenaltyRepository
 *
 * Provides an in-memory storage implementation for penalties.
 */

import type { Penalty } from '@core/racing/domain/entities/Penalty';
import type { IPenaltyRepository } from '@core/racing/domain/repositories/IPenaltyRepository';
import type { Logger } from '@core/shared/application';

export class InMemoryPenaltyRepository implements IPenaltyRepository {
  private penalties: Map<string, Penalty> = new Map();
  private readonly logger: Logger;

  constructor(logger: Logger, initialPenalties: Penalty[] = []) {
    this.logger = logger;
    this.logger.info('InMemoryPenaltyRepository initialized.');
    initialPenalties.forEach(penalty => {
      this.penalties.set(penalty.id, penalty);
      this.logger.debug(`Seeded penalty: ${penalty.id}`);
    });
  }

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

  async findByRaceId(raceId: string): Promise<Penalty[]> {
    this.logger.debug(`Finding penalties by race id: ${raceId}`);
    try {
      const penalties = Array.from(this.penalties.values()).filter(
        penalty => penalty.raceId === raceId
      );
      this.logger.info(`Found ${penalties.length} penalties for race id: ${raceId}.`);
      return penalties;
    } catch (error) {
      this.logger.error(`Error finding penalties by race id ${raceId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async findByDriverId(driverId: string): Promise<Penalty[]> {
    this.logger.debug(`Finding penalties by driver id: ${driverId}`);
    try {
      const penalties = Array.from(this.penalties.values()).filter(
        penalty => penalty.driverId === driverId
      );
      this.logger.info(`Found ${penalties.length} penalties for driver id: ${driverId}.`);
      return penalties;
    } catch (error) {
      this.logger.error(`Error finding penalties by driver id ${driverId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async findByProtestId(protestId: string): Promise<Penalty[]> {
    this.logger.debug(`Finding penalties by protest id: ${protestId}`);
    try {
      const penalties = Array.from(this.penalties.values()).filter(
        penalty => penalty.protestId === protestId
      );
      this.logger.info(`Found ${penalties.length} penalties for protest id: ${protestId}.`);
      return penalties;
    } catch (error) {
      this.logger.error(`Error finding penalties by protest id ${protestId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async findPending(): Promise<Penalty[]> {
    this.logger.debug('Finding pending penalties.');
    try {
      const penalties = Array.from(this.penalties.values()).filter(
        penalty => penalty.isPending()
      );
      this.logger.info(`Found ${penalties.length} pending penalties.`);
      return penalties;
    } catch (error) {
      this.logger.error('Error finding pending penalties:', error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async findIssuedBy(stewardId: string): Promise<Penalty[]> {
    this.logger.debug(`Finding penalties issued by steward: ${stewardId}`);
    try {
      const penalties = Array.from(this.penalties.values()).filter(
        penalty => penalty.issuedBy === stewardId
      );
      this.logger.info(`Found ${penalties.length} penalties issued by steward: ${stewardId}.`);
      return penalties;
    } catch (error) {
      this.logger.error(`Error finding penalties issued by steward ${stewardId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async create(penalty: Penalty): Promise<void> {
    this.logger.debug(`Creating penalty: ${penalty.id}`);
    try {
      if (this.penalties.has(penalty.id)) {
        this.logger.warn(`Penalty with ID ${penalty.id} already exists.`);
        throw new Error(`Penalty with ID ${penalty.id} already exists`);
      }
      this.penalties.set(penalty.id, penalty);
      this.logger.info(`Penalty ${penalty.id} created successfully.`);
    } catch (error) {
      this.logger.error(`Error creating penalty ${penalty.id}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async update(penalty: Penalty): Promise<void> {
    this.logger.debug(`Updating penalty: ${penalty.id}`);
    try {
      if (!this.penalties.has(penalty.id)) {
        this.logger.warn(`Penalty with ID ${penalty.id} not found for update.`);
        throw new Error(`Penalty with ID ${penalty.id} not found`);
      }
      this.penalties.set(penalty.id, penalty);
      this.logger.info(`Penalty ${penalty.id} updated successfully.`);
    } catch (error) {
      this.logger.error(`Error updating penalty ${penalty.id}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async exists(id: string): Promise<boolean> {
    this.logger.debug(`Checking existence of penalty with id: ${id}`);
    try {
      const exists = this.penalties.has(id);
      this.logger.debug(`Penalty ${id} exists: ${exists}.`);
      return exists;
    } catch (error) {
      this.logger.error(`Error checking existence of penalty with id ${id}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }
}