import admin from 'firebase-admin';
import { loadNotificationConfig } from '../config/notification.config';
import type { PushNotification, NotificationResult } from '../types/notification.types';

const config = loadNotificationConfig();

let fcmApp: admin.app.App | null = null;

function getFCMApp(): admin.app.App {
  if (!fcmApp) {
    fcmApp = admin.initializeApp({
      credential: admin.credential.cert({
        projectId: config.fcm.projectId,
        clientEmail: config.fcm.clientEmail,
        privateKey: config.fcm.privateKey.replace(/\\n/g, '\n'),
      }),
    });
  }
  return fcmApp;
}

export class PushService {
  private static instance: PushService;
  private sentCount = new Map<string, number>();
  private cleanupInterval: NodeJS.Timeout;

  private constructor() {
    this.cleanupInterval = setInterval(() => {
      const now = Date.now();
      for (const [key, timestamp] of this.sentCount.entries()) {
        if (now - timestamp > 60000) {
          this.sentCount.delete(key);
        }
      }
    }, 60000);
  }

  static getInstance(): PushService {
    if (!PushService.instance) {
      PushService.instance = new PushService();
    }
    return PushService.instance;
  }

  async send(notification: PushNotification): Promise<NotificationResult> {
    const rateLimitKey = `push:${notification.userId}`;
    const currentCount = this.sentCount.get(rateLimitKey) || 0;

    if (currentCount >= config.rateLimits.pushPerMinute) {
      throw new Error(`Push rate limit exceeded for user ${notification.userId}`);
    }

    try {
      const fcmApp = getFCMApp();
      const messaging = admin.messaging(fcmApp);

      const message: admin.messaging.Message = {
        notification: {
          title: notification.title,
          body: notification.body,
        },
        data: notification.data ? 
          Object.fromEntries(
            Object.entries(notification.data).map(([k, v]) => [k, String(v)])
          ) : undefined,
        token: notification.userId,
        apns: {
          payload: {
            aps: {
              badge: notification.badge,
              sound: notification.sound || 'default',
              category: notification.category,
            },
          },
        },
      };

      const response = await messaging.send(message);

      this.sentCount.set(rateLimitKey, currentCount + 1);

      return {
        notificationId: `push-${response}`,
        channel: 'push',
        status: 'sent',
        externalId: response,
        deliveredAt: new Date(),
      };
    } catch (error) {
      return {
        notificationId: `push-${Date.now()}`,
        channel: 'push',
        status: 'failed',
        error: error instanceof Error ? error.message : 'Unknown error',
      };
    }
  }

  async sendBatch(notifications: PushNotification[]): Promise<NotificationResult[]> {
    const results = await Promise.all(
      notifications.map(n => this.send(n))
    );
    return results;
  }

  getRateLimitStatus(): { remaining: number; limit: number } {
    return {
      remaining: config.rateLimits.pushPerMinute - this.sentCount.size,
      limit: config.rateLimits.pushPerMinute,
    };
  }
}
