import { NextResponse } from "next/server";
import { prisma } from "@capakraken/db";
import { createNotificationsForUsers } from "@capakraken/api";
import { logger } from "@capakraken/api/lib/logger";
import { verifyCronSecret } from "~/lib/cron-auth.js";

export const dynamic = "force-dynamic";
export const runtime = "nodejs";

/** Window over which auth events are analysed. */
const WINDOW_MS = 30 * 60 * 1000; // 30 minutes

/**
 * Alert thresholds — tune per deployment if needed.
 * Exported so tests can reference them without re-declaring magic numbers.
 */
export const THRESHOLDS = {
  /** Total failed login attempts in the window before alerting. */
  globalFailures: 20,
  /** Failed attempts attributed to a single entityId (userId / IP placeholder) before alerting. */
  perEntityFailures: 10,
};

export interface AnomalyReport {
  windowStartedAt: string;
  windowEndedAt: string;
  totalFailures: number;
  anomalies: Array<{ type: string; count: number; entityId: string | null }>;
}

/**
 * Analyses recent auth audit events and returns detected anomalies.
 * Exported for unit testing without an HTTP layer.
 */
export async function detectAuthAnomalies(windowMs = WINDOW_MS): Promise<AnomalyReport> {
  const windowEnd = new Date();
  const windowStart = new Date(windowEnd.getTime() - windowMs);

  const failureEvents = await prisma.auditLog.findMany({
    where: {
      entityType: "Auth",
      action: "CREATE",
      summary: { startsWith: "Login failed" },
      createdAt: { gte: windowStart, lte: windowEnd },
    },
    select: {
      entityId: true,
      summary: true,
    },
  });

  const anomalies: AnomalyReport["anomalies"] = [];

  // Global threshold: too many failures overall
  if (failureEvents.length >= THRESHOLDS.globalFailures) {
    anomalies.push({
      type: "HIGH_GLOBAL_FAILURE_RATE",
      count: failureEvents.length,
      entityId: null,
    });
  }

  // Per-entity threshold: one entity accumulating failures (brute-force pattern)
  const countByEntity = new Map<string, number>();
  for (const event of failureEvents) {
    if (event.entityId) {
      countByEntity.set(event.entityId, (countByEntity.get(event.entityId) ?? 0) + 1);
    }
  }
  for (const [entityId, count] of countByEntity.entries()) {
    if (count >= THRESHOLDS.perEntityFailures) {
      anomalies.push({
        type: "CONCENTRATED_FAILURES",
        count,
        entityId,
      });
    }
  }

  return {
    windowStartedAt: windowStart.toISOString(),
    windowEndedAt: windowEnd.toISOString(),
    totalFailures: failureEvents.length,
    anomalies,
  };
}

/**
 * GET /api/cron/auth-anomaly-check
 *
 * Scans recent auth audit events for brute-force / anomaly patterns and
 * alerts ADMIN users when thresholds are exceeded.
 *
 * Protected by CRON_SECRET. Run every 30 minutes via cron or Vercel Cron.
 */
export async function GET(request: Request) {
  const deny = verifyCronSecret(request);
  if (deny) return deny;

  try {
    const report = await detectAuthAnomalies();

    if (report.anomalies.length > 0) {
      const adminUsers = await prisma.user.findMany({
        where: { systemRole: "ADMIN" },
        select: { id: true },
      });

      if (adminUsers.length > 0) {
        const summary = report.anomalies
          .map((a) =>
            a.entityId
              ? `${a.type}: ${a.count} failures for entity ${a.entityId}`
              : `${a.type}: ${a.count} total failures`,
          )
          .join("; ");

        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        await createNotificationsForUsers({
          db: prisma as any,
          userIds: adminUsers.map((u) => u.id),
          type: "SYSTEM_ALERT",
          title: `Auth Anomaly Detected (${report.anomalies.length} signal${report.anomalies.length > 1 ? "s" : ""})`,
          body: `${summary}. Window: ${report.windowStartedAt} – ${report.windowEndedAt}. Review audit logs at /admin/settings.`,
          category: "system",
          priority: "CRITICAL",
          link: "/admin/settings",
        });

        logger.warn(
          { anomalies: report.anomalies, window: { start: report.windowStartedAt, end: report.windowEndedAt } },
          "Auth anomaly cron: anomalies detected and admins notified",
        );
      }
    }

    return NextResponse.json({
      ok: true,
      ...report,
    });
  } catch (error) {
    logger.error({ error, route: "/api/cron/auth-anomaly-check" }, "Auth anomaly cron failed");
    return NextResponse.json(
      { ok: false, error: "Internal error" },
      { status: 500 },
    );
  }
}
