import prisma from "@shieldai/db";
import { WatchListService } from "./watchlist/WatchListService";
import { HIBPService } from "./hibp/HIBPService";
import { MatchingEngine } from "./matching/MatchingEngine";
import { AlertPipeline } from "./alerts/AlertPipeline";
import { DataSource, ScanJobStatus } from "@shieldai/types";

export class ScanService {
  private watchList: WatchListService;
  private hibp: HIBPService;
  private matching: MatchingEngine;
  private alerts: AlertPipeline;

  constructor() {
    this.watchList = new WatchListService();
    this.hibp = new HIBPService(process.env.HIBP_API_KEY);
    this.matching = new MatchingEngine();
    this.alerts = new AlertPipeline();
  }

  async runScan(userId: string, source?: DataSource): Promise<number> {
    const job = await prisma.scanJob.create({
      data: {
        userId,
        status: ScanJobStatus.RUNNING,
        source: source || DataSource.HIBP,
      },
    });

    let resultCount = 0;

    try {
      const activeItems = await this.watchList.getActiveItems(userId);

      for (const item of activeItems) {
        if (item.identifierType === "EMAIL") {
          const breaches = await this.hibp.checkEmail(item.identifierValue);
          for (const breach of breaches) {
            const severity = this.hibp.getSeverity(breach);
            const matched = await this.matching.matchExposure(
              item.id,
              DataSource.HIBP,
              breach.name,
              breach.breachDate,
              breach.dataClasses,
              severity,
              `Breach: ${breach.title}. Domain: ${breach.domain}. PwnCount: ${breach.pwnCount}`
            );

            if (matched) {
              resultCount++;
              await this.alerts.createAlert(userId, matched.dataSource + ":" + breach.name, severity);
            }
          }
        }
      }

      await prisma.scanJob.update({
        where: { id: job.id },
        data: {
          status: ScanJobStatus.COMPLETED,
          resultCount,
          completedAt: new Date(),
        },
      });
    } catch (err) {
      const message = err instanceof Error ? err.message : String(err);
      await prisma.scanJob.update({
        where: { id: job.id },
        data: {
          status: ScanJobStatus.FAILED,
          errorMessage: message,
          completedAt: new Date(),
        },
      });
    }

    return resultCount;
  }

  async getScanHistory(userId: string, limit = 20) {
    return prisma.scanJob.findMany({
      where: { userId },
      orderBy: { createdAt: "desc" },
      take: limit,
    });
  }
}
