import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { FirebaseService } from '../firebase/firebase.service';

@Injectable()
export class NotificationsService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly firebaseService: FirebaseService,
  ) {}

  private serializeBigInt(data: any): any {
    return JSON.parse(
      JSON.stringify(data, (_, v) => (typeof v === 'bigint' ? Number(v) : v)),
    );
  }

  async findAll(userId: number, unreadOnly?: boolean) {
    const where: any = { userId };

    if (unreadOnly) {
      where.isRead = false;
    }

    const notifications = await this.prisma.notification.findMany({
      where,
      orderBy: { createdAt: 'desc' },
    });

    return this.serializeBigInt(notifications);
  }

  async markAsRead(userId: number, id: number) {
    const existing = await this.prisma.notification.findFirst({
      where: { id, userId },
    });

    if (!existing) {
      throw new NotFoundException(`Notification with ID ${id} not found`);
    }

    const updated = await this.prisma.notification.update({
      where: { id },
      data: { isRead: true },
    });

    return this.serializeBigInt(updated);
  }

  async markAllAsRead(userId: number) {
    const result = await this.prisma.notification.updateMany({
      where: { userId, isRead: false },
      data: { isRead: true },
    });

    return { message: `${result.count} notifications marked as read` };
  }

  async remove(userId: number, id: number) {
    const existing = await this.prisma.notification.findFirst({
      where: { id, userId },
    });

    if (!existing) {
      throw new NotFoundException(`Notification with ID ${id} not found`);
    }

    await this.prisma.notification.delete({ where: { id } });

    return { message: `Notification with ID ${id} has been deleted` };
  }

  async registerFcmToken(userId: number, token: string) {
    await this.prisma.notificationSettings.upsert({
      where: { userId },
      update: {
        fcmToken: token,
        pushEnabled: true,
        fcmTokenUpdatedAt: new Date(),
      },
      create: {
        userId,
        fcmToken: token,
        pushEnabled: true,
        fcmTokenUpdatedAt: new Date(),
      },
    });
    return { message: 'FCM token registered' };
  }

  async removeFcmToken(userId: number) {
    await this.prisma.notificationSettings.upsert({
      where: { userId },
      update: {
        fcmToken: null,
        pushEnabled: false,
        fcmTokenUpdatedAt: new Date(),
      },
      create: { userId },
    });
    return { message: 'FCM token removed' };
  }

  async createAndPush(params: {
    userId: number;
    type: string;
    title: string;
    message?: string;
    link?: string;
  }) {
    const notification = await this.prisma.notification.create({
      data: {
        userId: params.userId,
        type: params.type,
        title: params.title,
        message: params.message,
        link: params.link,
      },
    });

    const settings = await this.prisma.notificationSettings.findUnique({
      where: { userId: params.userId },
    });

    if (settings?.pushEnabled && settings?.fcmToken) {
      const typeSettingMap: Record<string, boolean | undefined> = {
        settlement: settings.settlementAlerts,
        payment: settings.settlementAlerts,
        document: settings.documentAlerts,
        contract: settings.documentAlerts,
        estimate: settings.documentAlerts,
        tax: settings.taxAlerts,
      };

      const shouldSend = typeSettingMap[params.type] ?? true;
      if (shouldSend) {
        const success = await this.firebaseService.sendPush(
          settings.fcmToken,
          params.title,
          params.message || '',
          {
            link: params.link || '/app',
            notificationId: notification.id.toString(),
            type: params.type,
          },
        );

        if (!success) {
          await this.prisma.notificationSettings.update({
            where: { userId: params.userId },
            data: { fcmToken: null, pushEnabled: false },
          });
        }
      }
    }

    return this.serializeBigInt(notification);
  }
}
