import type { MeasurementSystem } from "./locale.js";
import { UNIT_INFO } from "./constants.js";
import type { Unit } from "./enums.js";

/**
 * Måttvisningstjänst (i18n-spec §9–10, §30 – M5).
 *
 * Lagring är ALLTID kanonisk (GRAM/MILLILITER/COUNT …). Denna modul väljer
 * hur en kanonisk mängd VISAS för användarens measurementSystem – förlustfritt:
 * originalvärdet rör vi aldrig, vi räknar bara fram en visningsrepresentation.
 *
 * METRIC       g/kg, ml/dl/l som i dag.
 * US_CUSTOMARY vikt -> oz/lb, volym -> tsp/tbsp/fl oz/cup.
 * MIXED        (GB/CA-stil) metriskt kök – som METRIC tills marknadsdata säger annat.
 */

export interface DisplayQuantity {
  value: number;
  unit: Unit;
  /** Ex "0.25" -> visas som ¼ i UI:t om klienten vill. */
  approximate: boolean;
}

const OZ_IN_GRAMS = 28.349523125;
const LB_IN_GRAMS = 453.59237;
const TSP_ML = 5;
const TBSP_ML = 15;
const FLOZ_ML = 29.5735295625;
const CUP_ML = 236.5882365;

/** Avrunda till närmaste kvarts (för cups/tsp – så recepten ser naturliga ut). */
function roundQuarter(v: number): number {
  return Math.round(v * 4) / 4;
}

function round1(v: number): number {
  return Math.round(v * 10) / 10;
}

/** Kanonisk mängd -> visningsmängd för användarens måttsystem. */
export function displayQuantity(
  quantity: number,
  unit: Unit,
  system: MeasurementSystem,
): DisplayQuantity {
  const info = UNIT_INFO[unit];
  if (!info) return { value: quantity, unit, approximate: false };

  if (system !== "US_CUSTOMARY") {
    // METRIC/MIXED: uppgradera bara till läsbara metriska enheter.
    if (info.kind === "mass") {
      const grams = quantity * info.toBase;
      if (grams >= 1000)
        return { value: round1(grams / 1000), unit: "KILOGRAM", approximate: false };
      return { value: Math.round(grams), unit: "GRAM", approximate: false };
    }
    if (info.kind === "volume") {
      const ml = quantity * info.toBase;
      // Behåll kökstypiska enheter som de är (tsk/msk/krm visas bäst oförändrade).
      if (unit === "TEASPOON" || unit === "TABLESPOON" || unit === "PINCH") {
        return { value: quantity, unit, approximate: false };
      }
      if (ml >= 1000) return { value: round1(ml / 1000), unit: "LITER", approximate: false };
      if (ml >= 100) return { value: round1(ml / 100), unit: "DECILITER", approximate: false };
      return { value: Math.round(ml), unit: "MILLILITER", approximate: false };
    }
    return { value: quantity, unit, approximate: false };
  }

  // US_CUSTOMARY
  if (info.kind === "mass") {
    const grams = quantity * info.toBase;
    if (grams >= LB_IN_GRAMS)
      return { value: round1(grams / LB_IN_GRAMS), unit: "POUND", approximate: true };
    return { value: round1(grams / OZ_IN_GRAMS), unit: "OUNCE", approximate: true };
  }
  if (info.kind === "volume") {
    const ml = quantity * info.toBase;
    if (ml >= CUP_ML / 2)
      return { value: roundQuarter(ml / CUP_ML), unit: "CUP_US", approximate: true };
    if (ml >= FLOZ_ML)
      return { value: roundQuarter(ml / FLOZ_ML), unit: "FLUID_OUNCE_US", approximate: true };
    if (ml >= TBSP_ML)
      return { value: roundQuarter(ml / TBSP_ML), unit: "TABLESPOON", approximate: true };
    return { value: roundQuarter(ml / TSP_ML), unit: "TEASPOON", approximate: true };
  }
  return { value: quantity, unit, approximate: false };
}

/** kcal -> kJ (i18n-spec §18: EU visar båda, kJ = kcal × 4.184). */
export function kcalToKilojoules(kcal: number): number {
  return Math.round(kcal * 4.184);
}

/** Salt (g) <-> natrium (mg): salt = natrium × 2.5 (spec §18–19). */
export function sodiumMgToSaltGrams(sodiumMg: number): number {
  return Math.round(sodiumMg * 2.5) / 1000;
}

export function saltGramsToSodiumMg(saltGrams: number): number {
  return Math.round((saltGrams * 1000) / 2.5);
}
