/**
 * Infrastructure: InMemorySponsorAccountRepository
 * 
 * In-memory implementation of ISponsorAccountRepository for development/testing.
 */

import type { ISponsorAccountRepository } from '../../domain/repositories/ISponsorAccountRepository';
import type { SponsorAccount } from '../../domain/entities/SponsorAccount';
import type { UserId } from '../../domain/value-objects/UserId';
import { Logger } from '@core/shared/application';

export class InMemorySponsorAccountRepository implements ISponsorAccountRepository {
  private accounts: Map<string, SponsorAccount> = new Map();
  private readonly logger: Logger;

  constructor(logger: Logger, seedData?: SponsorAccount[]) {
    this.logger = logger;
    this.logger.info('InMemorySponsorAccountRepository initialized.');
    if (seedData) {
      this.seed(seedData);
    }
  }

  async save(account: SponsorAccount): Promise<void> {
    this.logger.debug(`Saving sponsor account: ${account.getId().value}`);
    try {
      this.accounts.set(account.getId().value, account);
      this.logger.info(`Sponsor account ${account.getId().value} saved successfully.`);
    } catch (error) {
      this.logger.error(`Error saving sponsor account ${account.getId().value}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

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

  async findBySponsorId(sponsorId: string): Promise<SponsorAccount | null> {
    this.logger.debug(`Finding sponsor account by sponsor id: ${sponsorId}`);
    try {
      const account = Array.from(this.accounts.values()).find(
        a => a.getSponsorId() === sponsorId
      ) ?? null;
      if (account) {
        this.logger.info(`Found sponsor account for sponsor id: ${sponsorId}.`);
      } else {
        this.logger.warn(`Sponsor account for sponsor id ${sponsorId} not found.`);
      }
      return account;
    } catch (error) {
      this.logger.error(`Error finding sponsor account by sponsor id ${sponsorId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async findByEmail(email: string): Promise<SponsorAccount | null> {
    this.logger.debug(`Finding sponsor account by email: ${email}`);
    try {
      const normalizedEmail = email.toLowerCase().trim();
      const account = Array.from(this.accounts.values()).find(
        a => a.getEmail().toLowerCase() === normalizedEmail
      ) ?? null;
      if (account) {
        this.logger.info(`Found sponsor account by email: ${email}.`);
      } else {
        this.logger.warn(`Sponsor account with email ${email} not found.`);
      }
      return account;
    } catch (error) {
      this.logger.error(`Error finding sponsor account by email ${email}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  async delete(id: UserId): Promise<void> {
    this.logger.debug(`Deleting sponsor account: ${id.value}`);
    try {
      if (this.accounts.delete(id.value)) {
        this.logger.info(`Sponsor account ${id.value} deleted successfully.`);
      } else {
        this.logger.warn(`Sponsor account with id ${id.value} not found for deletion.`);
      }
    } catch (error) {
      this.logger.error(`Error deleting sponsor account ${id.value}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  // Helper for testing
  clear(): void {
    this.logger.debug('Clearing all sponsor accounts.');
    this.accounts.clear();
    this.logger.info('All sponsor accounts cleared.');
  }

  // Helper for seeding demo data
  seed(accounts: SponsorAccount[]): void {
    this.logger.debug(`Seeding ${accounts.length} sponsor accounts.`);
    try {
      accounts.forEach(a => {
        this.accounts.set(a.getId().value, a);
        this.logger.debug(`Seeded sponsor account: ${a.getId().value}.`);
      });
      this.logger.info(`Successfully seeded ${accounts.length} sponsor accounts.`);
    } catch (error) {
      this.logger.error(`Error seeding sponsor accounts:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }
}