import type { InventoryTransactionType, Unit } from "@app/shared-types";

export interface TransactionLike {
  type: InventoryTransactionType;
  quantityDelta: number;
  unit: Unit;
}

/** Transaktionstyper som ska vara negativa (uttag). */
const OUTFLOW_TYPES: ReadonlySet<InventoryTransactionType> = new Set([
  "consume",
  "discard",
  "cook_use",
  "leftover_consumed",
]);
/** Transaktionstyper som ska vara positiva (inflöde). */
const INFLOW_TYPES: ReadonlySet<InventoryTransactionType> = new Set([
  "purchase",
  "leftover_created",
]);

export interface BalanceResult {
  balance: number;
  valid: boolean;
  errors: string[];
}

/**
 * Beräkna saldo ur transaktionshistorik (spec §8: transaktioner är sanningen).
 * Saldo tillåts aldrig bli negativt – i så fall flaggas historiken som
 * inkonsistent så att en correction kan föreslås, i stället för tyst clamp.
 */
export function computeBalance(transactions: TransactionLike[]): BalanceResult {
  let balance = 0;
  const errors: string[] = [];
  for (const [i, tx] of transactions.entries()) {
    if (OUTFLOW_TYPES.has(tx.type) && tx.quantityDelta > 0) {
      errors.push(`Transaktion ${i} (${tx.type}) borde vara negativ men är +${tx.quantityDelta}`);
    }
    if (INFLOW_TYPES.has(tx.type) && tx.quantityDelta < 0) {
      errors.push(`Transaktion ${i} (${tx.type}) borde vara positiv men är ${tx.quantityDelta}`);
    }
    balance += tx.quantityDelta;
    if (balance < -1e-9) {
      errors.push(
        `Saldo blev negativt (${balance.toFixed(3)}) efter transaktion ${i} (${tx.type})`,
      );
      balance = 0;
    }
  }
  return { balance: round3(balance), valid: errors.length === 0, errors };
}

/** Normalisera ett uttag: rätt tecken oavsett hur anroparen skickade mängden. */
export function normalizeDelta(type: InventoryTransactionType, quantity: number): number {
  const magnitude = Math.abs(quantity);
  if (OUTFLOW_TYPES.has(type)) return -magnitude;
  if (INFLOW_TYPES.has(type)) return magnitude;
  return quantity; // adjust/correction/move/freeze/thaw får vara valfritt tecken
}

function round3(v: number): number {
  return Math.round(v * 1000) / 1000;
}
