import { Inject, InternalServerErrorException } from '@nestjs/common';
import { CommandHandler, type ICommandHandler } from '@nestjs/cqrs';
// eslint-disable-next-line @typescript-eslint/consistent-type-imports -- NestJS DI requires value imports
import { DomainException, ForbiddenException, NotFoundException, EventBusService, LoggerService } from '@modules/shared';
import { ConversationReadEvent } from '../../../domain/events/conversation-read.event';
import {
  CONVERSATION_REPOSITORY,
  type IConversationRepository,
} from '../../../domain/repositories/conversation.repository';
import { MarkConversationReadCommand } from './mark-read.command';

@CommandHandler(MarkConversationReadCommand)
export class MarkConversationReadHandler implements ICommandHandler<MarkConversationReadCommand> {
  constructor(
    @Inject(CONVERSATION_REPOSITORY)
    private readonly conversationRepo: IConversationRepository,
    private readonly eventBus: EventBusService,
    private readonly logger: LoggerService,
  ) {}

  async execute(command: MarkConversationReadCommand): Promise<void> {
    try {
      const { conversationId, userId } = command;

      const conversation = await this.conversationRepo.findById(conversationId);
      if (!conversation) {
        throw new NotFoundException('Conversation', conversationId);
      }

      const isParticipant = conversation.participants.some((p) => p.userId === userId);
      if (!isParticipant) {
        throw new ForbiddenException('Bạn không phải là thành viên của hội thoại này');
      }

      await this.conversationRepo.resetUnreadCount(conversationId, userId);

      // Publish domain event so the gateway broadcasts read receipt
      this.eventBus.publish(
        new ConversationReadEvent(conversationId, conversationId, userId),
      );
    } catch (error) {
      if (error instanceof DomainException) throw error;
      this.logger.error(
        `Failed to mark conversation read: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined,
        this.constructor.name,
      );
      throw new InternalServerErrorException('Không thể đánh dấu đã đọc');
    }
  }
}
