import { Inject, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, EventBus, type ICommandHandler } from '@nestjs/cqrs';
import { DomainException, NotFoundException, CacheService, CachePrefix, LoggerService } from '@modules/shared';
import { LISTING_REPOSITORY, type IListingRepository } from '../../../domain/repositories/listing.repository';
// eslint-disable-next-line @typescript-eslint/consistent-type-imports -- NestJS DI needs runtime reference
import { ModerationService } from '../../../domain/services/moderation.service';
import { ModerateListingCommand } from './moderate-listing.command';

@CommandHandler(ModerateListingCommand)
export class ModerateListingHandler implements ICommandHandler<ModerateListingCommand> {
  constructor(
    @Inject(LISTING_REPOSITORY) private readonly listingRepo: IListingRepository,
    private readonly eventBus: EventBus,
    private readonly cache: CacheService,
    private readonly moderationService: ModerationService,
    private readonly logger: LoggerService,
  ) {}

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

      this.moderationService.applyModeration(listing, {
        action: command.action,
        moderationScore: command.moderationScore,
        notes: command.notes,
      });

      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 };
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to moderate listing ${command.listingId}: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể kiểm duyệt tin đăng');
    }
  }
}
