import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PrismaService } from '../../prisma/prisma.service';
import { Notification, NotificationType } from '@prisma/client';

@Injectable()
export class NotificationSenderService implements OnModuleInit {
  private readonly logger = new Logger(NotificationSenderService.name);
  private firebaseApp: any = null;
  private messaging: any = null;

  constructor(
    private readonly prisma: PrismaService,
    private readonly config: ConfigService,
  ) {}

  async onModuleInit(): Promise<void> {
    const serviceAccountJson = this.config.get<string>(
      'FIREBASE_SERVICE_ACCOUNT_JSON',
    );

    if (!serviceAccountJson) {
      this.logger.warn(
        'FIREBASE_SERVICE_ACCOUNT_JSON not set — push notifications will be logged only',
      );
      return;
    }

    try {
      const admin = await import('firebase-admin');
      const serviceAccount = JSON.parse(serviceAccountJson);

      this.firebaseApp = admin.default.initializeApp({
        credential: admin.default.credential.cert(serviceAccount),
      });
      this.messaging = this.firebaseApp.messaging();

      this.logger.log('Firebase Admin SDK initialized — push notifications enabled');
    } catch (error) {
      this.logger.error(
        `Failed to initialize Firebase: ${error instanceof Error ? error.message : error}`,
      );
    }
  }

  /**
   * Send a push notification to all active devices of a user.
   * Uses Firebase Cloud Messaging if configured, otherwise logs only.
   */
  async sendPush(userId: string, notification: Notification): Promise<void> {
    const tokens = await this.prisma.pushToken.findMany({
      where: { userId, isActive: true },
    });

    if (tokens.length === 0) {
      this.logger.debug(
        `No active push tokens for user ${userId}, skipping push`,
      );
      return;
    }

    for (const token of tokens) {
      if (this.messaging) {
        try {
          await this.messaging.send({
            token: token.token,
            notification: {
              title: notification.title,
              body: notification.body ?? undefined,
            },
            data: {
              notificationId: notification.id,
              type: notification.type,
            },
            android: {
              priority: 'high' as const,
              notification: { sound: 'default' },
            },
            apns: {
              payload: {
                aps: { sound: 'default', badge: 1 },
              },
            },
          });
          this.logger.debug(
            `Push sent to ${token.platform} device=${token.deviceId ?? 'unknown'}`,
          );
        } catch (error: any) {
          const errorCode = error?.code ?? error?.errorInfo?.code ?? '';
          if (
            errorCode === 'messaging/invalid-registration-token' ||
            errorCode === 'messaging/registration-token-not-registered'
          ) {
            this.logger.warn(
              `Invalid token for device=${token.deviceId}, deactivating`,
            );
            await this.prisma.pushToken.update({
              where: { id: token.id },
              data: { isActive: false },
            });
          } else {
            this.logger.error(
              `Push failed for device=${token.deviceId}: ${error?.message ?? error}`,
            );
          }
        }
      } else {
        this.logger.log(
          `[PUSH-DRY] ${token.platform} device=${token.deviceId ?? 'unknown'}: ` +
            `title="${notification.title}", body="${notification.body}"`,
        );
      }
    }

    this.logger.log(
      `Push dispatched to ${tokens.length} device(s) for user ${userId}` +
        (this.messaging ? '' : ' (dry-run, Firebase not configured)'),
    );
  }

  /**
   * Check if a notification type is enabled for a club.
   * Returns true if no setting exists (enabled by default).
   */
  async shouldSend(
    clubId: string,
    type: NotificationType,
  ): Promise<boolean> {
    const setting = await this.prisma.notificationSetting.findUnique({
      where: {
        clubId_notificationType: {
          clubId,
          notificationType: type,
        },
      },
    });

    if (!setting) {
      return true;
    }

    return setting.enabled;
  }

  /**
   * Get custom title/body text for a notification type from club settings.
   * Returns null if no custom text is configured.
   */
  async getCustomText(
    clubId: string,
    type: NotificationType,
  ): Promise<string | null> {
    const setting = await this.prisma.notificationSetting.findUnique({
      where: {
        clubId_notificationType: {
          clubId,
          notificationType: type,
        },
      },
    });

    return setting?.customText ?? null;
  }
}
