import { Injectable, Logger } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';
import { NotificationType } from '@prisma/client';
import { NotificationsService } from './notifications.service';
import { NotificationSenderService } from './notification-sender.service';

/**
 * Payloads for notification trigger events.
 * Each method corresponds to a business event from another module.
 */
export interface ClientAssignedPayload {
  clubId: string;
  trainerId: string;
  clientId: string;
  clientName: string;
}

export interface ServiceBookedPayload {
  clubId: string;
  trainerId: string;
  clientId: string;
  clientName: string;
  serviceName: string;
}

export interface ServicePaidPayload {
  clubId: string;
  trainerId: string;
  clientId: string;
  clientName: string;
  amount: number;
}

export interface PackageTopupPayload {
  clubId: string;
  trainerId: string;
  clientId: string;
  clientName: string;
  packageName: string;
}

export interface BookingCancelledPayload {
  clubId: string;
  trainerId: string;
  clientId: string;
  clientName: string;
  scheduledAt: string;
}

export interface TrainingDeductedPayload {
  clubId: string;
  trainerId: string;
  clientId: string;
  clientName: string;
}

export interface TrainingsEndingPayload {
  clubId: string;
  trainerId: string;
  clientId: string;
  clientName: string;
  remainingSessions: number;
}

export interface ClientReturnedPayload {
  clubId: string;
  trainerId: string;
  clientId: string;
  clientName: string;
}

export interface ClientBirthdayPayload {
  clubId: string;
  trainerId: string;
  clientId: string;
  clientName: string;
}

@Injectable()
export class NotificationTriggersService {
  private readonly logger = new Logger(NotificationTriggersService.name);

  constructor(
    private readonly notificationsService: NotificationsService,
    private readonly senderService: NotificationSenderService,
  ) {}

  @OnEvent('funnel.assigned')
  async handleFunnelAssigned(event: { clubId: string; data: any }): Promise<void> {
    const { data } = event;
    if (!data.trainer || !data.client) return;
    await this.onClientAssigned({
      clubId: event.clubId,
      trainerId: data.trainer.id,
      clientId: data.client.id,
      clientName: `${data.client.firstName} ${data.client.lastName}`,
    });
  }

  async onClientAssigned(payload: ClientAssignedPayload): Promise<void> {
    await this.createIfEnabled(
      payload.clubId,
      payload.trainerId,
      NotificationType.CLIENT_ASSIGNED,
      'Новый клиент',
      `Вам назначен новый клиент: ${payload.clientName}`,
      { screen: 'client', clientId: payload.clientId },
    );
  }

  @OnEvent('training.created')
  async handleTrainingCreated(event: { clubId: string; data: any }): Promise<void> {
    const { data } = event;
    if (!data.trainer || !data.client || !data.service) return;
    await this.onServiceBooked({
      clubId: event.clubId,
      trainerId: data.trainer.id,
      clientId: data.client.id,
      clientName: `${data.client.firstName} ${data.client.lastName}`,
      serviceName: data.service.name,
    });
  }

  async onServiceBooked(payload: ServiceBookedPayload): Promise<void> {
    await this.createIfEnabled(
      payload.clubId,
      payload.trainerId,
      NotificationType.SERVICE_BOOKED,
      'Запись на услугу',
      `${payload.clientName} записался на ${payload.serviceName}`,
      { screen: 'schedule', clientId: payload.clientId },
    );
  }

  @OnEvent('sale.paid')
  async handleSalePaid(event: { clubId: string; data: any }): Promise<void> {
    const { data } = event;
    if (!data.trainer || !data.client) return;
    await this.onServicePaid({
      clubId: event.clubId,
      trainerId: data.trainer.id,
      clientId: data.client.id,
      clientName: `${data.client.firstName} ${data.client.lastName}`,
      amount: Number(data.amount),
    });
  }

  async onServicePaid(payload: ServicePaidPayload): Promise<void> {
    await this.createIfEnabled(
      payload.clubId,
      payload.trainerId,
      NotificationType.SERVICE_PAID,
      'Оплата услуги',
      `${payload.clientName} оплатил ${payload.amount} руб.`,
      { screen: 'client', clientId: payload.clientId },
    );
  }

  /**
   * Trigger: client topped up a package.
   */
  async onPackageTopup(payload: PackageTopupPayload): Promise<void> {
    await this.createIfEnabled(
      payload.clubId,
      payload.trainerId,
      NotificationType.PACKAGE_TOPUP,
      'Доплата пакета',
      `${payload.clientName} доплатил пакет "${payload.packageName}"`,
      { screen: 'client', clientId: payload.clientId },
    );
  }

  @OnEvent('training.cancelled')
  async handleTrainingCancelled(event: { clubId: string; data: any }): Promise<void> {
    const { data } = event;
    if (!data.trainer || !data.client) return;
    await this.onTrainingCancelled({
      clubId: event.clubId,
      trainerId: data.trainer.id,
      clientId: data.client.id,
      clientName: `${data.client.firstName} ${data.client.lastName}`,
      scheduledAt: data.scheduledAt,
    });
  }

  async onTrainingCancelled(
    payload: BookingCancelledPayload,
  ): Promise<void> {
    await this.createIfEnabled(
      payload.clubId,
      payload.trainerId,
      NotificationType.BOOKING_CANCELLED,
      'Отмена записи',
      `${payload.clientName} отменил запись на ${payload.scheduledAt}`,
      { screen: 'schedule', clientId: payload.clientId },
    );
  }

  @OnEvent('training.completed')
  async handleTrainingCompleted(event: { clubId: string; data: any }): Promise<void> {
    const { data } = event;
    if (!data.trainer || !data.client) return;
    await this.onTrainingCompleted({
      clubId: event.clubId,
      trainerId: data.trainer.id,
      clientId: data.client.id,
      clientName: `${data.client.firstName} ${data.client.lastName}`,
    });
  }

  async onTrainingCompleted(
    payload: TrainingDeductedPayload,
  ): Promise<void> {
    await this.createIfEnabled(
      payload.clubId,
      payload.trainerId,
      NotificationType.TRAINING_DEDUCTED,
      'Списание тренировки',
      `Тренировка с ${payload.clientName} списана`,
      { screen: 'client', clientId: payload.clientId },
    );
  }

  /**
   * Trigger: client's training sessions are ending.
   */
  async onTrainingsEnding(
    payload: TrainingsEndingPayload,
  ): Promise<void> {
    await this.createIfEnabled(
      payload.clubId,
      payload.trainerId,
      NotificationType.TRAININGS_ENDING,
      'Окончание тренировок',
      `У ${payload.clientName} осталось ${payload.remainingSessions} тренировок`,
      { screen: 'client', clientId: payload.clientId },
    );
  }

  /**
   * Trigger: client returned from administration.
   */
  async onClientReturned(payload: ClientReturnedPayload): Promise<void> {
    await this.createIfEnabled(
      payload.clubId,
      payload.trainerId,
      NotificationType.CLIENT_RETURNED,
      'Возврат клиента',
      `Клиент ${payload.clientName} возвращён от администрации`,
      { screen: 'client', clientId: payload.clientId },
    );
  }

  /**
   * Trigger: client birthday today.
   */
  async onClientBirthday(payload: ClientBirthdayPayload): Promise<void> {
    await this.createIfEnabled(
      payload.clubId,
      payload.trainerId,
      NotificationType.CLIENT_BIRTHDAY,
      'День рождения клиента',
      `Сегодня день рождения у ${payload.clientName}!`,
      { screen: 'client', clientId: payload.clientId },
    );
  }

  /**
   * Helper: check if notification type is enabled, apply custom text,
   * then create the notification.
   */
  private async createIfEnabled(
    clubId: string,
    userId: string,
    type: NotificationType,
    defaultTitle: string,
    defaultBody: string,
    data: Record<string, any>,
  ): Promise<void> {
    const enabled = await this.senderService.shouldSend(clubId, type);

    if (!enabled) {
      this.logger.debug(
        `Notification type ${type} is disabled for club ${clubId}, skipping`,
      );
      return;
    }

    const customText = await this.senderService.getCustomText(clubId, type);

    await this.notificationsService.create(clubId, {
      userId,
      type,
      title: defaultTitle,
      body: customText ?? defaultBody,
      data,
    });

    this.logger.log(
      `Notification triggered: type=${type}, userId=${userId}, clubId=${clubId}`,
    );
  }
}
