import { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor';
import { SponsorRepository } from '@core/racing/domain/repositories/SponsorRepository';
import { Logger } from '@core/shared/domain';

export class InMemorySponsorRepository implements SponsorRepository {
  private sponsors: Map<string, Sponsor> = new Map();
  private emailIndex: Map<string, string> = new Map(); // contactEmail -> sponsorId

  constructor(private readonly logger: Logger, initialSponsors: Sponsor[] = []) {
    this.logger.info('InMemorySponsorRepository initialized.');
    for (const sponsor of initialSponsors) {
      this.sponsors.set(sponsor.id.toString(), sponsor);
      this.emailIndex.set(sponsor.contactEmail.toString().toLowerCase(), sponsor.id.toString());
      this.logger.debug(`Seeded sponsor: ${sponsor.id} (${sponsor.name}).`);
    }
  }

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

  async findAll(): Promise<Sponsor[]> {
    this.logger.debug('[InMemorySponsorRepository] Finding all sponsors.');
    return Promise.resolve(Array.from(this.sponsors.values()));
  }

  async findByEmail(email: string): Promise<Sponsor | null> {
    this.logger.debug(`[InMemorySponsorRepository] Finding sponsor by email: ${email}`);
    const sponsorId = this.emailIndex.get(email.toLowerCase());
    if (!sponsorId) {
      this.logger.warn(`Sponsor with email ${email} not found.`);
      return Promise.resolve(null);
    }
    return this.findById(sponsorId);
  }

  async create(sponsor: Sponsor): Promise<Sponsor> {
    this.logger.debug(`[InMemorySponsorRepository] Creating sponsor: ${sponsor.id} (${sponsor.name})`);
    if (this.sponsors.has(sponsor.id.toString())) {
      this.logger.warn(`Sponsor with ID ${sponsor.id} already exists.`);
      throw new Error('Sponsor already exists');
    }
    if (this.emailIndex.has(sponsor.contactEmail.toString().toLowerCase())) {
      this.logger.warn(`Sponsor with email ${sponsor.contactEmail} already exists.`);
      throw new Error('Sponsor with this email already exists');
    }
    this.sponsors.set(sponsor.id.toString(), sponsor);
    this.emailIndex.set(sponsor.contactEmail.toString().toLowerCase(), sponsor.id.toString());
    this.logger.info(`Sponsor ${sponsor.id} (${sponsor.name}) created successfully.`);
    return Promise.resolve(sponsor);
  }

  async update(sponsor: Sponsor): Promise<Sponsor> {
    this.logger.debug(`[InMemorySponsorRepository] Updating sponsor: ${sponsor.id} (${sponsor.name})`);
    if (!this.sponsors.has(sponsor.id.toString())) {
      this.logger.warn(`Sponsor with ID ${sponsor.id} not found for update.`);
      throw new Error('Sponsor not found');
    }
    const existingSponsor = this.sponsors.get(sponsor.id.toString());
    // If email changed, update index
    if (existingSponsor && existingSponsor.contactEmail.toString().toLowerCase() !== sponsor.contactEmail.toString().toLowerCase()) {
      if (this.emailIndex.has(sponsor.contactEmail.toString().toLowerCase()) && this.emailIndex.get(sponsor.contactEmail.toString().toLowerCase()) !== sponsor.id.toString()) {
        this.logger.warn(`Cannot update sponsor ${sponsor.id} to email ${sponsor.contactEmail} as it's already taken.`);
        throw new Error('Sponsor with this email already exists');
      }
      this.emailIndex.delete(existingSponsor.contactEmail.toString().toLowerCase());
      this.emailIndex.set(sponsor.contactEmail.toString().toLowerCase(), sponsor.id.toString());
    }
    this.sponsors.set(sponsor.id.toString(), sponsor);
    this.logger.info(`Sponsor ${sponsor.id} (${sponsor.name}) updated successfully.`);
    return Promise.resolve(sponsor);
  }

  async delete(id: string): Promise<void> {
    this.logger.debug(`[InMemorySponsorRepository] Deleting sponsor with ID: ${id}`);
    const sponsor = this.sponsors.get(id);
    if (sponsor) {
      this.sponsors.delete(id);
      this.emailIndex.delete(sponsor.contactEmail.toString().toLowerCase());
      this.logger.info(`Sponsor ${id} deleted successfully.`);
    } else {
      this.logger.warn(`Sponsor with ID ${id} not found for deletion.`);
    }
    return Promise.resolve();
  }

  async exists(id: string): Promise<boolean> {
    this.logger.debug(`[InMemorySponsorRepository] Checking existence of sponsor with ID: ${id}`);
    return Promise.resolve(this.sponsors.has(id));
  }

  clear(): void {
    this.sponsors.clear();
    this.emailIndex.clear();
  }
}
