import { Injectable, Logger } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';
import { ConfigService } from '@nestjs/config';
import { PrismaService } from '../../database/prisma.service';
import { NotificationEvent } from '@prisma/client';

@Injectable()
export class NotificationsService {
  private readonly logger = new Logger(NotificationsService.name);
  private readonly isDev: boolean;

  constructor(
    private readonly prisma: PrismaService,
    private readonly config: ConfigService,
  ) {
    this.isDev = config.get('app.nodeEnv') !== 'production';
  }

  async send(
    userId: string,
    event: NotificationEvent,
    title: string,
    body: string,
    data?: Record<string, any>,
    familyId?: string,
  ) {
    // Salvar no banco
    const notification = await this.prisma.notification.create({
      data: { userId, familyId, event, title, body, data },
    });

    // Buscar FCM token do usuário (via devices vinculados)
    const user = await this.prisma.user.findUnique({
      where: { id: userId },
      include: {
        familyMemberships: {
          include: {
            child: { include: { devices: { where: { isActive: true, fcmToken: { not: null } } } } },
          },
        },
      },
    });

    const fcmTokens = user?.familyMemberships
      .flatMap((m) => m.child?.devices ?? [])
      .map((d) => d.fcmToken)
      .filter(Boolean) as string[];

    if (fcmTokens.length > 0 && !this.isDev) {
      await this.sendFcm(fcmTokens, title, body, data);
    } else {
      // Fallback dev: apenas log
      this.logger.log(
        `[Notification DEV] → ${userId} | ${event}\n  Title: ${title}\n  Body: ${body}`,
      );
    }

    return notification;
  }

  async getUnread(userId: string) {
    return this.prisma.notification.findMany({
      where: { userId, isRead: false },
      orderBy: { createdAt: 'desc' },
      take: 50,
    });
  }

  async markRead(notificationId: string, userId: string) {
    return this.prisma.notification.updateMany({
      where: { id: notificationId, userId },
      data: { isRead: true },
    });
  }

  async markAllRead(userId: string) {
    return this.prisma.notification.updateMany({
      where: { userId, isRead: false },
      data: { isRead: true },
    });
  }

  private async sendFcm(tokens: string[], title: string, body: string, data?: any) {
    // Integração FCM real — ativada quando FCM_PROJECT_ID estiver configurado
    // Em produção: usar firebase-admin SDK
    this.logger.log(`[FCM] Enviando para ${tokens.length} dispositivo(s): ${title}`);
  }

  // Ouvir eventos internos
  @OnEvent('time-request.created')
  async onTimeRequestCreated(payload: { request: any; childId: string }) {
    // Notificar guardiões
    const child = await this.prisma.child.findUnique({
      where: { id: payload.childId },
      include: {
        guardians: {
          include: { guardian: { include: { familyMember: { include: { user: true } } } } },
        },
        familyMember: { include: { user: true } },
      },
    });

    if (!child) return;

    for (const cg of child.guardians) {
      const userId = cg.guardian.familyMember.user.id;
      await this.send(
        userId,
        NotificationEvent.TIME_REQUEST,
        '⏱ Pedido de tempo extra',
        `${child.familyMember.user.name} pediu +${payload.request.requestedMin} minutos`,
        { requestId: payload.request.id, childId: payload.childId },
      );
    }
  }

  @OnEvent('time-request.approved')
  async onTimeRequestApproved(payload: { requestId: string; childId: string; minutes: number }) {
    const child = await this.prisma.child.findUnique({
      where: { id: payload.childId },
      include: { familyMember: { include: { user: true } } },
    });
    if (!child) return;

    await this.send(
      child.familyMember.userId,
      NotificationEvent.TIME_REQUEST_APPROVED,
      '✅ Tempo aprovado!',
      `+${payload.minutes} minutos foram liberados`,
      { requestId: payload.requestId },
    );
  }

  @OnEvent('time-request.denied')
  async onTimeRequestDenied(payload: { requestId: string; childId: string }) {
    const child = await this.prisma.child.findUnique({
      where: { id: payload.childId },
      include: { familyMember: { include: { user: true } } },
    });
    if (!child) return;

    await this.send(
      child.familyMember.userId,
      NotificationEvent.TIME_REQUEST_DENIED,
      'Pedido não aprovado',
      'Seu responsável não aprovou o tempo extra desta vez.',
    );
  }
}
