import { listAssignmentBookings } from "@capakraken/application";
import { createNotificationsForUsers } from "./create-notification.js";

type DbClient = Parameters<typeof listAssignmentBookings>[0] & {
  project: {
    findUnique: (args: {
      where: { id: string };
      select: { id: true; name: true; shortCode: true; budgetCents: true };
    }) => Promise<{
      id: string;
      name: string;
      shortCode: string;
      budgetCents: number;
    } | null>;
  };
  notification: {
    findFirst: (args: {
      where: {
        entityId: string;
        entityType: string;
        type: string;
      };
      select: { id: true };
    }) => Promise<{ id: string } | null>;
    create: (args: {
      data: {
        userId: string;
        type: string;
        category: string;
        priority: string;
        title: string;
        body: string;
        entityId: string;
        entityType: string;
        link: string;
        channel: string;
      };
    }) => Promise<{ id: string; userId: string }>;
  };
  user: {
    findMany: (args: {
      where: { systemRole: { in: string[] } };
      select: { id: true };
    }) => Promise<Array<{ id: string }>>;
  };
};

const THRESHOLDS = [
  { percent: 100, type: "BUDGET_OVERRUN_100", label: "100%", priority: "URGENT" as const },
  { percent: 80, type: "BUDGET_OVERRUN_80", label: "80%", priority: "HIGH" as const },
] as const;

/**
 * Check whether a project's current spend has crossed 80% or 100% of its budget.
 * Creates in-app notifications for all managers/admins when a threshold is
 * crossed for the first time.
 *
 * Safe to call repeatedly -- duplicate notifications are prevented by checking
 * whether a notification with the same entityId + type already exists.
 */
export async function checkBudgetThresholds(
  db: DbClient,
  projectId: string,
): Promise<void> {
  const project = await db.project.findUnique({
    where: { id: projectId },
    select: { id: true, name: true, shortCode: true, budgetCents: true },
  });

  if (!project || project.budgetCents <= 0) return;

  // Compute total spend from assignment bookings (same logic as listWithCosts)
  const bookings = await listAssignmentBookings(db, {
    startDate: new Date("1900-01-01T00:00:00.000Z"),
    endDate: new Date("2100-12-31T23:59:59.999Z"),
    projectIds: [projectId],
  });

  let totalCostCents = 0;
  for (const booking of bookings) {
    const days =
      (new Date(booking.endDate).getTime() -
        new Date(booking.startDate).getTime()) /
        (1000 * 60 * 60 * 24) +
      1;
    totalCostCents += booking.dailyCostCents * days;
  }
  totalCostCents = Math.round(totalCostCents);

  const spendPercent = (totalCostCents / project.budgetCents) * 100;

  for (const threshold of THRESHOLDS) {
    if (spendPercent < threshold.percent) continue;

    // Check if we already sent this alert
    const existing = await db.notification.findFirst({
      where: {
        entityId: projectId,
        entityType: "project_budget",
        type: threshold.type,
      },
      select: { id: true },
    });

    if (existing) continue;

    // Get all managers and admins
    const managers = await db.user.findMany({
      where: { systemRole: { in: ["ADMIN", "MANAGER"] } },
      select: { id: true },
    });

    const formattedSpend = (totalCostCents / 100).toLocaleString("de-DE", {
      minimumFractionDigits: 2,
      maximumFractionDigits: 2,
    });
    const formattedBudget = (project.budgetCents / 100).toLocaleString(
      "de-DE",
      { minimumFractionDigits: 2, maximumFractionDigits: 2 },
    );

    await createNotificationsForUsers({
      db,
      userIds: managers.map((m) => m.id),
      type: threshold.type,
      category: "NOTIFICATION",
      priority: threshold.priority,
      title: `Budget alert: ${project.name} has reached ${threshold.label} of budget`,
      body: `Project ${project.shortCode} "${project.name}" has spent ${formattedSpend} EUR of ${formattedBudget} EUR budget (${Math.round(spendPercent)}%).`,
      entityId: projectId,
      entityType: "project_budget",
      link: `/projects/${projectId}`,
      channel: "in_app",
    });
  }
}
