import { Inject } from '@nestjs/common';
import { CommandHandler, type EventBus, type ICommandHandler } from '@nestjs/cqrs';
import { NotFoundException } from '@modules/shared/domain/domain-exception';
import { CacheService, CachePrefix } from '@modules/shared/infrastructure/cache.service';
import { LISTING_REPOSITORY, type IListingRepository } from '../../../domain/repositories/listing.repository';
import { UpdateListingStatusCommand } from './update-listing-status.command';

@CommandHandler(UpdateListingStatusCommand)
export class UpdateListingStatusHandler implements ICommandHandler<UpdateListingStatusCommand> {
  constructor(
    @Inject(LISTING_REPOSITORY) private readonly listingRepo: IListingRepository,
    private readonly eventBus: EventBus,
    private readonly cache: CacheService,
  ) {}

  async execute(command: UpdateListingStatusCommand): Promise<{ status: string }> {
    const listing = await this.listingRepo.findById(command.listingId);
    if (!listing) {
      throw new NotFoundException('Listing', command.listingId);
    }

    if (command.newStatus === 'REJECTED' && command.moderationNotes) {
      listing.reject(command.moderationNotes);
    } else if (command.newStatus === 'ACTIVE' && listing.status === 'PENDING_REVIEW') {
      listing.approve();
    } else {
      listing.transitionTo(command.newStatus);
    }

    await this.listingRepo.update(listing);

    const events = listing.clearDomainEvents();
    for (const event of events) {
      this.eventBus.publish(event);
    }

    await Promise.all([
      this.cache.invalidate(CacheService.buildKey(CachePrefix.LISTING, command.listingId)),
      this.cache.invalidateByPrefix(CachePrefix.SEARCH),
    ]);

    return { status: listing.status };
  }
}
