import { Client } from "@/models/Client";
import { Order } from "@/models/Order";
import { getPriceState } from "@/lib/priceProposal";
import { getTotalOrderDiscount, getPayableAmount } from "@/lib/discounts";
import { bookCredit } from "@/lib/creditLedger";
import { logActivity } from "@/lib/orderActivity";

// Kontoguthaben wird automatisch eingesetzt, sobald ein Preisvorschlag
// vorliegt (gleiche Bedingung wie beim Rabattcode-Einlösen, siehe
// DiscountCodeRedeem) — "wie bei Amazon", der Kunde muss nichts eingeben.
// Lazy-Ensure-Muster wie getOrCreateReferralCode: idempotent, beliebig oft
// bei jedem Seitenaufruf aufrufbar, macht bei bereits angewendetem Guthaben
// (creditApplied > 0) sofort nichts. Einmal eingesetzt, wird der Betrag bei
// einer späteren Preisänderung (Gegenvorschlag) NICHT neu berechnet —
// konsistent mit discountAmount, das beim Einlösen ebenfalls einfriert.
export async function ensureAccountCreditApplied(orderId: string): Promise<void> {
  const order = await Order.findById(orderId)
    .select("clientId creditApplied discountAmount manualDiscountAmount rejected")
    .lean();
  if (!order || order.creditApplied || order.rejected) return;

  const { state } = await getPriceState(orderId);
  if (state.phase === "none") return;

  const client = await Client.findById(order.clientId).select("creditBalance").lean();
  const balance = client?.creditBalance || 0;
  if (balance <= 0) return;

  const payableBeforeCredit = getPayableAmount(state.latest.amount, getTotalOrderDiscount(order));
  const applyAmount = Math.round(Math.min(balance, payableBeforeCredit) * 100) / 100;
  if (applyAmount <= 0) return;

  // Claim zuerst auf dem Auftrag (verhindert doppeltes Anwenden bei
  // gleichzeitigen Seitenaufrufen), erst danach das Guthaben abbuchen — bei
  // fehlschlagendem Abzug (z. B. Guthaben zwischenzeitlich anderswo
  // verbraucht) wird der Claim wieder freigegeben.
  const claimed = await Order.findOneAndUpdate(
    { _id: orderId, creditApplied: { $in: [0, null] } },
    { $set: { creditApplied: applyAmount } }
  );
  if (!claimed) return;

  const result = await bookCredit({
    clientId: String(order.clientId),
    amount: -applyAmount,
    type: "order_redemption",
    reason: "Automatisch beim Auftrag eingesetzt",
    relatedOrderId: orderId,
  });
  if (result.error) {
    await Order.findByIdAndUpdate(orderId, { $set: { creditApplied: 0 } });
    return;
  }

  await logActivity(orderId, "credit_applied", "client", `Guthaben eingesetzt: −${applyAmount.toFixed(2)} €`);
}
