import { Injectable } from '@nestjs/common';
import { CommandBus } from '@nestjs/cqrs';
import { OnEvent } from '@nestjs/event-emitter';
import { LoggerService, PrismaService } from '@modules/shared';
import { SendNotificationCommand } from '../commands/send-notification/send-notification.command';

export interface InquiryReceivedEvent {
  readonly eventName: string;
  readonly aggregateId: string;
  readonly listingId: string;
  readonly senderId: string;
  readonly message: string;
}

@Injectable()
export class InquiryReceivedListener {
  constructor(
    private readonly commandBus: CommandBus,
    private readonly prisma: PrismaService,
    private readonly logger: LoggerService,
  ) {}

  @OnEvent('inquiry.received', { async: true })
  async handle(event: InquiryReceivedEvent): Promise<void> {
    this.logger.log(`Handling inquiry.received for listing ${event.listingId}`, 'InquiryReceivedListener');

    const listing = await this.prisma.listing.findUnique({
      where: { id: event.listingId },
      include: {
        property: { select: { title: true } },
        seller: { select: { id: true, email: true } },
        agent: { include: { user: { select: { id: true, email: true } } } },
      },
    });

    if (!listing) return;

    const sender = await this.prisma.user.findUnique({
      where: { id: event.senderId },
      select: { fullName: true, phone: true },
    });

    const senderName = sender?.fullName ?? sender?.phone ?? 'Khách hàng';
    const listingTitle = listing.property.title;
    const templateData = { senderName, listingTitle, message: event.message };

    // Notify the agent via email + push
    if (listing.agent?.user.email) {
      await this.commandBus.execute(
        new SendNotificationCommand(
          listing.agent.user.id,
          'EMAIL',
          'inquiry.received',
          templateData,
          listing.agent.user.email,
        ),
      );
    }

    // Notify agent via push if they have a token
    if (listing.agent?.user.id) {
      const token = await this.getFcmToken(listing.agent.user.id);
      if (token) {
        await this.commandBus.execute(
          new SendNotificationCommand(
            listing.agent.user.id,
            'PUSH',
            'inquiry.received',
            templateData,
            token,
          ),
        );
      }
    }

    // Also notify seller if different from agent
    if (listing.seller.email && listing.seller.id !== listing.agent?.user.id) {
      await this.commandBus.execute(
        new SendNotificationCommand(
          listing.seller.id,
          'EMAIL',
          'inquiry.received',
          templateData,
          listing.seller.email,
        ),
      );
    }
  }

  private async getFcmToken(userId: string): Promise<string | null> {
    const pref = await this.prisma.notificationPreference.findFirst({
      where: { userId, channel: 'PUSH', enabled: true },
    });
    // FCM token stored in metadata — for now return null until token storage is implemented
    // eslint-disable-next-line @typescript-eslint/no-explicit-any -- metadata shape is dynamic
    return (pref as any)?.metadata?.fcmToken ?? null;
  }
}
