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

export interface IngredientUnitInfo {
  /** g per ml – krävs för volym → massa. */
  densityGPerMl?: number | null;
  /** g per styck – krävs för antal → massa. */
  gramsPerPiece?: number | null;
}

export function unitKind(unit: Unit): UnitKind {
  return UNIT_INFO[unit].kind;
}

/** Konvertera till basenhet inom samma slag (g, ml eller st). */
export function toBase(quantity: number, unit: Unit): { kind: UnitKind; amount: number } {
  const info = UNIT_INFO[unit];
  return { kind: info.kind, amount: quantity * info.toBase };
}

/**
 * Konvertera valfri mängd till gram. Returnerar null när konvertering inte är
 * möjlig utan mer information – hellre ärlig osäkerhet än gissning (spec §61.4).
 */
export function toGrams(
  quantity: number,
  unit: Unit,
  info: IngredientUnitInfo = {},
): number | null {
  const base = toBase(quantity, unit);
  switch (base.kind) {
    case "mass":
      return base.amount;
    case "volume": {
      const density = info.densityGPerMl;
      if (density == null || density <= 0) return null;
      return base.amount * density;
    }
    case "count": {
      const perPiece = info.gramsPerPiece;
      if (perPiece == null || perPiece <= 0) return null;
      return base.amount * perPiece;
    }
  }
}

/** Konvertera en mängd mellan enheter (samma slag, eller via densitet/styckvikt). */
export function convert(
  quantity: number,
  from: Unit,
  to: Unit,
  info: IngredientUnitInfo = {},
): number | null {
  const fromInfo = UNIT_INFO[from];
  const toInfo = UNIT_INFO[to];
  if (fromInfo.kind === toInfo.kind) {
    return (quantity * fromInfo.toBase) / toInfo.toBase;
  }
  // Olika slag: gå via gram.
  const grams = toGrams(quantity, from, info);
  if (grams == null) return null;
  if (toInfo.kind === "mass") return grams / toInfo.toBase;
  if (toInfo.kind === "volume") {
    const density = info.densityGPerMl;
    if (density == null || density <= 0) return null;
    return grams / density / toInfo.toBase;
  }
  const perPiece = info.gramsPerPiece;
  if (perPiece == null || perPiece <= 0) return null;
  return grams / perPiece / toInfo.toBase;
}
