// Atomic per-user idea-code generator (DB-side).
// Schema: User.idea_code_counter Int @default(0) — increment-and-return via
// Prisma `update` (which acquires a row-lock for the duration of the
// transaction; concurrent calls serialize). Format: "IDEA-001", "IDEA-002", …
//
// Concurrency: vertrouwt op Postgres row-locking binnen Prisma `update`.
// Geen aparte $transaction nodig voor enkelvoudige update — de update is
// atomisch op één rij. Voor combineren met een idea.create wordt
// nextIdeaCode aangeroepen binnen de bredere $transaction van de caller.
//
// Self-correcting: na de increment wordt de numerieke MAX van bestaande codes
// opgevraagd via raw SQL (geen string-vergelijking — die faalt boven IDEA-999).
// Als de counter achterloopt (bijv. na directe DB-inserts tijdens development)
// wordt nextN = MAX+1 gebruikt en de counter direct bijgewerkt.

import { prisma } from '@/lib/prisma'
import { formatIdeaCode } from '@/lib/idea-code'

import type { Prisma } from '@prisma/client'

export async function nextIdeaCode(
  userId: string,
  client: Prisma.TransactionClient | typeof prisma = prisma,
): Promise<string> {
  // Increment counter — acquires Postgres row lock, serializes concurrent calls.
  const u = await client.user.update({
    where: { id: userId },
    data: { idea_code_counter: { increment: 1 } },
    select: { idea_code_counter: true },
  })

  // Numeric MAX guards against counter drift (e.g. ideas inserted directly in
  // DB without updating the counter). String MAX mis-sorts "IDEA-1000" <
  // "IDEA-999", so we cast to INTEGER in SQL.
  const rows = await (client as Prisma.TransactionClient).$queryRaw<
    [{ max_n: number | bigint | null }]
  >`
    SELECT MAX(CAST(SUBSTRING(code FROM 6) AS INTEGER)) AS max_n
    FROM ideas
    WHERE user_id = ${userId}
  `
  const maxExisting = rows[0].max_n !== null ? Number(rows[0].max_n) : 0
  const nextN = Math.max(u.idea_code_counter, maxExisting + 1)

  // Re-sync counter forward if it was behind the actual max.
  if (nextN !== u.idea_code_counter) {
    await client.user.update({
      where: { id: userId },
      data: { idea_code_counter: nextN },
      select: { id: true },
    })
  }

  return formatIdeaCode(nextN)
}
