import { SponsorableEntityType, SponsorshipRequest, SponsorshipRequestStatus } from '@core/racing/domain/entities/SponsorshipRequest';
import { SponsorshipRequestRepository } from '@core/racing/domain/repositories/SponsorshipRequestRepository';
import { Logger } from '@core/shared/domain';

export class InMemorySponsorshipRequestRepository implements SponsorshipRequestRepository {
  private requests: Map<string, SponsorshipRequest> = new Map();

  constructor(private readonly logger: Logger, initialRequests: SponsorshipRequest[] = []) {
    this.logger.info('InMemorySponsorshipRequestRepository initialized.');
    for (const req of initialRequests) {
      this.requests.set(req.id, req);
      this.logger.debug(`Seeded sponsorship request: ${req.id}.`);
    }
  }

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

  async findByEntity(entityType: SponsorableEntityType, entityId: string): Promise<SponsorshipRequest[]> {
    this.logger.debug(`[InMemorySponsorshipRequestRepository] Finding requests for entity ${entityType}:${entityId}.`);
    const requests = Array.from(this.requests.values()).filter(req => req.entityType === entityType && req.entityId === entityId);
    this.logger.info(`Found ${requests.length} requests for entity ${entityType}:${entityId}.`);
    return Promise.resolve(requests);
  }

  async findPendingByEntity(entityType: SponsorableEntityType, entityId: string): Promise<SponsorshipRequest[]> {
    this.logger.debug(`[InMemorySponsorshipRequestRepository] Finding pending requests for entity ${entityType}:${entityId}.`);
    const requests = Array.from(this.requests.values()).filter(req => req.entityType === entityType && req.entityId === entityId && req.status === 'pending');
    this.logger.info(`Found ${requests.length} pending requests for entity ${entityType}:${entityId}.`);
    return Promise.resolve(requests);
  }

  async findBySponsorId(sponsorId: string): Promise<SponsorshipRequest[]> {
    this.logger.debug(`[InMemorySponsorshipRequestRepository] Finding requests by sponsor ID: ${sponsorId}.`);
    const requests = Array.from(this.requests.values()).filter(req => req.sponsorId === sponsorId);
    this.logger.info(`Found ${requests.length} requests by sponsor ID: ${sponsorId}.`);
    return Promise.resolve(requests);
  }

  async findByStatus(status: SponsorshipRequestStatus): Promise<SponsorshipRequest[]> {
    this.logger.debug(`[InMemorySponsorshipRequestRepository] Finding requests by status: ${status}.`);
    const requests = Array.from(this.requests.values()).filter(req => req.status === status);
    this.logger.info(`Found ${requests.length} requests with status: ${status}.`);
    return Promise.resolve(requests);
  }

  async findBySponsorIdAndStatus(sponsorId: string, status: SponsorshipRequestStatus): Promise<SponsorshipRequest[]> {
    this.logger.debug(`[InMemorySponsorshipRequestRepository] Finding requests by sponsor ID ${sponsorId} and status ${status}.`);
    const requests = Array.from(this.requests.values()).filter(req => req.sponsorId === sponsorId && req.status === status);
    this.logger.info(`Found ${requests.length} requests by sponsor ID ${sponsorId} and status ${status}.`);
    return Promise.resolve(requests);
  }

  async hasPendingRequest(sponsorId: string, entityType: SponsorableEntityType, entityId: string): Promise<boolean> {
    this.logger.debug(`[InMemorySponsorshipRequestRepository] Checking for pending request for sponsor ${sponsorId}, entity ${entityType}:${entityId}.`);
    const exists = Array.from(this.requests.values()).some(req => req.sponsorId === sponsorId && req.entityType === entityType && req.entityId === entityId && req.status === 'pending');
    this.logger.info(`Pending request for sponsor ${sponsorId}, entity ${entityType}:${entityId} exists: ${exists}.`);
    return Promise.resolve(exists);
  }

  async countPendingByEntity(entityType: SponsorableEntityType, entityId: string): Promise<number> {
    this.logger.debug(`[InMemorySponsorshipRequestRepository] Counting pending requests for entity ${entityType}:${entityId}.`);
    const count = Array.from(this.requests.values()).filter(req => req.entityType === entityType && req.entityId === entityId && req.status === 'pending').length;
    this.logger.info(`Count of pending requests for entity ${entityType}:${entityId}: ${count}.`);
    return Promise.resolve(count);
  }

  async create(request: SponsorshipRequest): Promise<SponsorshipRequest> {
    this.logger.debug(`[InMemorySponsorshipRequestRepository] Creating request: ${request.id}.`);
    if (this.requests.has(request.id)) {
      this.logger.warn(`Request with ID ${request.id} already exists.`);
      throw new Error('Sponsorship request already exists');
    }
    this.requests.set(request.id, request);
    this.logger.info(`Sponsorship request ${request.id} created successfully.`);
    return Promise.resolve(request);
  }

  async update(request: SponsorshipRequest): Promise<SponsorshipRequest> {
    this.logger.debug(`[InMemorySponsorshipRequestRepository] Updating request: ${request.id}.`);
    if (!this.requests.has(request.id)) {
      this.logger.warn(`Request with ID ${request.id} not found for update.`);
      throw new Error('Sponsorship request not found');
    }
    this.requests.set(request.id, request);
    this.logger.info(`Sponsorship request ${request.id} updated successfully.`);
    return Promise.resolve(request);
  }

  async delete(id: string): Promise<void> {
    this.logger.debug(`[InMemorySponsorshipRequestRepository] Deleting request with ID: ${id}.`);
    if (this.requests.delete(id)) {
      this.logger.info(`Sponsorship request ${id} deleted successfully.`);
    } else {
      this.logger.warn(`Request with ID ${id} not found for deletion.`);
    }
    return Promise.resolve();
  }

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

  clear(): void {
    this.requests.clear();
  }
}
