import { prisma, AlertType, AlertSeverity } from '@shieldsai/shared-db';
import {
  NotificationService,
  NotificationPriority,
  loadNotificationConfig,
} from '@shieldsai/shared-notifications';

const ALERT_DEDUP_WINDOW_MS = 24 * 60 * 60 * 1000;

export class AlertPipeline {
  private notificationService: NotificationService;

  constructor() {
    this.notificationService = new NotificationService(loadNotificationConfig());
  }

  async processNewExposures(exposureIds: string[]) {
    const exposures = await prisma.exposure.findMany({
      where: { id: { in: exposureIds }, isFirstTime: true },
      include: {
        subscription: {
          select: {
            id: true,
            userId: true,
            tier: true,
          },
        },
        watchlistItem: true,
      },
    });

    const alertsCreated: Awaited<ReturnType<typeof prisma.alert.create>>[] = [];

    for (const exposure of exposures) {
      const dedupKey = `exposure:${exposure.subscriptionId}:${exposure.source}:${exposure.identifierHash}`;

      const recentAlert = await prisma.alert.findFirst({
        where: {
          subscriptionId: exposure.subscriptionId,
          type: AlertType.exposure_detected,
          createdAt: {
            gte: new Date(Date.now() - ALERT_DEDUP_WINDOW_MS),
          },
        },
        orderBy: { createdAt: 'desc' },
      });

      if (recentAlert) {
        continue;
      }

      const alert = await prisma.alert.create({
        data: {
          subscriptionId: exposure.subscriptionId,
          userId: exposure.subscription.userId,
          exposureId: exposure.id,
          type: AlertType.exposure_detected,
          title: this.buildTitle(exposure),
          message: this.buildMessage(exposure),
          severity: this.mapSeverity(exposure.severity),
          channel: this.getChannelsForTier(exposure.subscription.tier),
        },
      });

      alertsCreated.push(alert);

      await this.dispatchNotification(alert, exposure);
    }

    return alertsCreated;
  }

  async dispatchScanCompleteAlert(
    subscriptionId: string,
    userId: string,
    exposuresFound: number
  ) {
    const subscription = await prisma.subscription.findUnique({
      where: { id: subscriptionId },
      select: { tier: true },
    });

    if (!subscription) return;

    const alert = await prisma.alert.create({
      data: {
        subscriptionId,
        userId,
        type: AlertType.scan_complete,
        title: 'DarkWatch Scan Complete',
        message: `Scan found ${exposuresFound} new exposure${exposuresFound === 1 ? '' : 's'}.`,
        severity: exposuresFound > 0 ? 'warning' : 'info',
        channel: this.getChannelsForTier(subscription.tier),
      },
    });

    await this.dispatchNotification(alert, {
      source: 'hibp',
      severity: 'info',
      identifier: '',
      dataType: 'email',
    } as any);

    return alert;
  }

  private async dispatchNotification(
    alert: {
      userId: string;
      channel: string[];
      title: string;
      message: string;
      severity: AlertSeverity;
    },
    exposure: { source: string; severity: string; identifier: string; dataType: string }
  ) {
    try {
      if (!this.notificationService.isFullyConfigured()) return;

      await this.notificationService.sendMultiChannelNotification(
        {
          userId: alert.userId,
        },
        alert.channel as any,
        alert.title,
        `<p>${alert.message}</p>
          <p><strong>Source:</strong> ${exposure.source}</p>
          <p><strong>Severity:</strong> ${exposure.severity}</p>
          <p><strong>Type:</strong> ${exposure.dataType}</p>`,
        alert.severity === 'critical'
          ? NotificationPriority.HIGH
          : NotificationPriority.NORMAL
      );
    } catch (error) {
      console.error('[AlertPipeline] Notification dispatch error:', error);
    }
  }

  private buildTitle(exposure: {
    source: string;
    dataType: string;
    severity: string;
  }): string {
    return `${exposure.severity.toUpperCase()}: ${exposure.dataType} exposure on ${exposure.source}`;
  }

  private buildMessage(exposure: {
    identifier: string;
    source: string;
    severity: string;
    dataType: string;
  }): string {
    const masked = exposure.identifier.includes('@')
      ? exposure.identifier.replace(/(?<=.{2}).*(?=@)/, '***')
      : exposure.identifier.slice(0, 3) + '***';

    return `Your ${exposure.dataType} (${masked}) was found in a ${exposure.source} breach with ${exposure.severity} severity.`;
  }

  private mapSeverity(severity: string): AlertSeverity {
    return severity as AlertSeverity;
  }

  private getChannelsForTier(tier: string): string[] {
    const channelMap: Record<string, string[]> = {
      basic: ['email'],
      plus: ['email', 'push'],
      premium: ['email', 'push', 'sms'],
    };
    return channelMap[tier] || ['email'];
  }
}

export const alertPipeline = new AlertPipeline();
