// src/lib/auth/account-delete-guard.ts — deleteUser.beforeDelete hook (P0 S1).
//
// Self-service account deletion (deleteUser.enabled, src/lib/auth.ts) can hit
// a user who still owns sites (sites.ownerUserId) or has support tickets
// (support_tickets.user_id / .assigned_to). Migration 0052 made all three FKs
// `ON DELETE SET NULL` (nullable columns) instead of the implicit Postgres
// RESTRICT they had before — so the deletion never throws an uncaught FK
// violation (500) anymore, at the database level. This guard does NOT block
// the deletion: a site is owned by its org (orgId, cascade), not by the user
// who created it — no app code reads sites.ownerUserId as a functional value
// (verified: only ever written at creation, indexed, and joined for display).
// Blocking here would strand a user who can never find/use a "transfer
// ownership" flow that doesn't exist in the product today. Instead we just
// log the orphaning for ops visibility.
import "server-only";
import { count, eq } from "drizzle-orm";
import { db } from "@/lib/db/client";
import { sites, supportTickets } from "@/lib/db/domain-schema";

export type AccountDeletionOwnership = {
  /** sites.owner_user_id rows that will become NULL. */
  siteCount: number;
  /** support_tickets.user_id rows that will become NULL. */
  ticketCount: number;
};

/** Counts the records that will be orphaned (owner set to NULL) if `userId` is deleted. */
export async function getAccountDeletionOwnership(
  userId: string,
): Promise<AccountDeletionOwnership> {
  const [[siteRow], [ticketRow]] = await Promise.all([
    db.select({ n: count() }).from(sites).where(eq(sites.ownerUserId, userId)),
    db
      .select({ n: count() })
      .from(supportTickets)
      .where(eq(supportTickets.userId, userId)),
  ]);
  return { siteCount: siteRow?.n ?? 0, ticketCount: ticketRow?.n ?? 0 };
}

/**
 * Better Auth `deleteUser.beforeDelete` hook. Never throws — the deletion is
 * always allowed to proceed (see file header for why). Logs when it will
 * orphan owned records, so ops can spot accounts that deleted while still
 * holding sites/tickets. A transient DB error while counting must NOT abort
 * the deletion (that would resurrect the 500 this fix removes), so the whole
 * body is best-effort: on failure we log and let the delete continue.
 */
export async function logAccountDeletionOwnership(
  userId: string,
): Promise<void> {
  try {
    const { siteCount, ticketCount } =
      await getAccountDeletionOwnership(userId);
    if (siteCount > 0 || ticketCount > 0) {
      console.warn("[account-delete] user deletion orphans owned records", {
        userId,
        siteCount,
        ticketCount,
      });
    }
  } catch (err) {
    console.warn("[account-delete] ownership check failed, proceeding", {
      userId,
      error: err instanceof Error ? err.message : String(err),
    });
  }
}
