import { Client } from "@/models/Client";
import { CreditTransaction, type CreditTransactionDoc } from "@/models/CreditTransaction";

type BookCreditParams = {
  clientId: string;
  amount: number;
  type: CreditTransactionDoc["type"];
  reason: string;
  createdByClientId?: string | null;
  relatedOrderId?: string | null;
};

type BookCreditResult = { error?: string; balanceAfter?: number };

// Einzige Stelle, die Client.creditBalance ändert — jede Buchung ist atomar
// (verhindert Race Conditions bei gleichzeitigen Buchungen, gleiches Muster
// wie der DiscountCode.usedCount-Claim in lib/actions/discounts.ts) und
// erzeugt immer einen CreditTransaction-Protokolleintrag.
export async function bookCredit({
  clientId,
  amount,
  type,
  reason,
  createdByClientId = null,
  relatedOrderId = null,
}: BookCreditParams): Promise<BookCreditResult> {
  const rounded = Math.round(amount * 100) / 100;
  if (!rounded) return { error: "Betrag darf nicht 0 sein." };
  const trimmedReason = reason.trim();
  if (!trimmedReason) return { error: "Bitte einen Grund angeben." };

  const updated =
    rounded < 0
      ? // Guthaben darf nicht unter 0 fallen — der Query-Filter matcht auch
        // bei fehlendem creditBalance-Feld (Bestandskonten) nicht, was hier
        // korrekt als "kein Guthaben vorhanden" wirkt.
        await Client.findOneAndUpdate(
          { _id: clientId, creditBalance: { $gte: -rounded } },
          { $inc: { creditBalance: rounded } },
          { new: true }
        ).select("creditBalance")
      : await Client.findByIdAndUpdate(clientId, { $inc: { creditBalance: rounded } }, { new: true }).select(
          "creditBalance"
        );

  if (!updated) {
    const exists = await Client.exists({ _id: clientId });
    return { error: exists ? "Nicht genug Guthaben vorhanden." : "Kunde nicht gefunden." };
  }

  await CreditTransaction.create({
    clientId,
    amount: rounded,
    balanceAfter: updated.creditBalance,
    type,
    reason: trimmedReason,
    createdByClientId,
    relatedOrderId,
  });

  return { balanceAfter: updated.creditBalance };
}
