// Sahh — Core nutrition engine · v0.3 (calibrated 04 May 2026)
// Real, working calculator. Parses natural-language recipes, computes
// calories / macros / Sahh Score, and exposes an interactive demo.
//
// Strategy (v0.3):
//   1. Local FOOD_DB covers ~60 common SA / ME ingredients with per-100g
//      values from USDA + SFDA composition tables.
//   2. Parser extracts (qty, unit, ingredient) tuples from each recipe line.
//   3. Engine sums macros using Atwater (4/4/9 kcal per g of P/C/F).
//   4. Sahh Score = weighted blend against MoH/SFDA/WHO EMRO anchors:
//        Sat fat 20% · Sodium 20% · Free sugar 20% ·
//        Energy density 15% · Protein+fibre 25%
//   5. Tier: 80–100 Balanced · 60–79 Mindful · 40–59 Moderate · 0–39 Indulgent.
//   6. If a line cannot be resolved locally, fallback to Claude.
//
// All numbers are deterministic for the same input; Claude is only used
// for unresolved tokens, behind a single async call.

// ============================================================
// FOOD DATABASE  (per 100g, edible portion)
// ============================================================
const FOOD_DB = {
  // proteins
  "chicken breast":     { kcal: 165, p: 31, c: 0,   f: 3.6,  proc: 0, fresh: 1.0, micros: 0.7, src: "USDA 05062" },
  "chicken thigh":      { kcal: 209, p: 26, c: 0,   f: 11,   proc: 0, fresh: 1.0, micros: 0.7, src: "USDA 05095" },
  "salmon":             { kcal: 208, p: 20, c: 0,   f: 13,   proc: 0, fresh: 1.0, micros: 0.95,src: "USDA 15076" },
  "beef":               { kcal: 250, p: 26, c: 0,   f: 17,   proc: 0, fresh: 1.0, micros: 0.8, src: "USDA 23568" },
  "ground beef":        { kcal: 254, p: 26, c: 0,   f: 17,   proc: 0.1, fresh: 0.95, micros: 0.75, src: "USDA 23566" },
  "lamb":               { kcal: 294, p: 25, c: 0,   f: 21,   proc: 0, fresh: 1.0, micros: 0.85, src: "USDA 17239" },
  "shrimp":             { kcal: 99,  p: 24, c: 0.2, f: 0.3,  proc: 0, fresh: 1.0, micros: 0.8, src: "USDA 15149" },
  "egg":                { kcal: 155, p: 13, c: 1.1, f: 11,   proc: 0, fresh: 1.0, micros: 0.85, src: "USDA 01129" },
  "tofu":               { kcal: 76,  p: 8,  c: 1.9, f: 4.8,  proc: 0.1, fresh: 0.9, micros: 0.7, src: "USDA 16427" },
  "labneh":             { kcal: 174, p: 9,  c: 5,   f: 13,   proc: 0.05, fresh: 0.95, micros: 0.6, src: "SFDA-DAIRY-12" },
  "feta":               { kcal: 264, p: 14, c: 4.1, f: 21,   proc: 0.1, fresh: 0.9, micros: 0.6, src: "USDA 01019" },
  "halloumi":           { kcal: 316, p: 22, c: 2,   f: 25,   proc: 0.1, fresh: 0.9, micros: 0.55, src: "SFDA-DAIRY-21" },

  // grains / starches
  "rice":               { kcal: 130, p: 2.7,c: 28,  f: 0.3,  proc: 0, fresh: 0.85, micros: 0.4, src: "USDA 20444" },
  "basmati rice":       { kcal: 121, p: 3,  c: 25,  f: 0.4,  proc: 0, fresh: 0.85, micros: 0.45, src: "USDA 20452" },
  "brown rice":         { kcal: 123, p: 2.7,c: 26,  f: 1,    proc: 0, fresh: 0.95, micros: 0.7, src: "USDA 20040" },
  "quinoa":             { kcal: 120, p: 4.4,c: 21,  f: 1.9,  proc: 0, fresh: 0.95, micros: 0.85, src: "USDA 20137" },
  "bulgur":             { kcal: 83,  p: 3.1,c: 19,  f: 0.2,  proc: 0, fresh: 0.95, micros: 0.7, src: "USDA 20013" },
  "couscous":           { kcal: 112, p: 3.8,c: 23,  f: 0.2,  proc: 0.1, fresh: 0.85, micros: 0.45, src: "USDA 20029" },
  "pasta":              { kcal: 158, p: 5.8,c: 31,  f: 0.9,  proc: 0.1, fresh: 0.85, micros: 0.4, src: "USDA 20100" },
  "bread":              { kcal: 265, p: 9,  c: 49,  f: 3.2,  proc: 0.2, fresh: 0.85, micros: 0.4, src: "USDA 18064" },
  "pita":               { kcal: 275, p: 9,  c: 56,  f: 1,    proc: 0.15, fresh: 0.85, micros: 0.4, src: "USDA 18414" },
  "potato":             { kcal: 77,  p: 2,  c: 17,  f: 0.1,  proc: 0, fresh: 0.95, micros: 0.6, src: "USDA 11362" },

  // vegetables
  "tomato":             { kcal: 18,  p: 0.9,c: 3.9, f: 0.2,  proc: 0, fresh: 1.0, micros: 0.85, src: "USDA 11529" },
  "cucumber":           { kcal: 16,  p: 0.7,c: 3.6, f: 0.1,  proc: 0, fresh: 1.0, micros: 0.7, src: "USDA 11206" },
  "lettuce":            { kcal: 15,  p: 1.4,c: 2.9, f: 0.2,  proc: 0, fresh: 1.0, micros: 0.85, src: "USDA 11253" },
  "romaine lettuce":    { kcal: 17,  p: 1.2,c: 3.3, f: 0.3,  proc: 0, fresh: 1.0, micros: 0.9, src: "USDA 11251" },
  "kale":               { kcal: 49,  p: 4.3,c: 9,   f: 0.9,  proc: 0, fresh: 1.0, micros: 1.0, src: "USDA 11233" },
  "spinach":            { kcal: 23,  p: 2.9,c: 3.6, f: 0.4,  proc: 0, fresh: 1.0, micros: 1.0, src: "USDA 11457" },
  "onion":              { kcal: 40,  p: 1.1,c: 9.3, f: 0.1,  proc: 0, fresh: 1.0, micros: 0.6, src: "USDA 11282" },
  "bell pepper":        { kcal: 31,  p: 1,  c: 6,   f: 0.3,  proc: 0, fresh: 1.0, micros: 0.95, src: "USDA 11333" },
  "carrot":             { kcal: 41,  p: 0.9,c: 9.6, f: 0.2,  proc: 0, fresh: 1.0, micros: 0.95, src: "USDA 11124" },
  "eggplant":           { kcal: 25,  p: 1,  c: 5.9, f: 0.2,  proc: 0, fresh: 1.0, micros: 0.6, src: "USDA 11209" },
  "mushroom":           { kcal: 22,  p: 3.1,c: 3.3, f: 0.3,  proc: 0, fresh: 1.0, micros: 0.7, src: "USDA 11260" },
  "parsley":            { kcal: 36,  p: 3,  c: 6.3, f: 0.8,  proc: 0, fresh: 1.0, micros: 0.95, src: "USDA 11297" },
  "mint":               { kcal: 70,  p: 3.8,c: 15,  f: 0.9,  proc: 0, fresh: 1.0, micros: 0.95, src: "USDA 02064" },

  // fruits
  "avocado":            { kcal: 160, p: 2,  c: 9,   f: 15,   proc: 0, fresh: 1.0, micros: 0.85, src: "USDA 09037" },
  "lemon":              { kcal: 29,  p: 1.1,c: 9,   f: 0.3,  proc: 0, fresh: 1.0, micros: 0.85, src: "USDA 09150" },
  "date":               { kcal: 277, p: 1.8,c: 75,  f: 0.2,  proc: 0, fresh: 0.95, micros: 0.7, src: "SFDA-FRUIT-04" },
  "orange":             { kcal: 47,  p: 0.9,c: 12,  f: 0.1,  proc: 0, fresh: 1.0, micros: 0.95, src: "USDA 09200" },

  // legumes / nuts
  "chickpeas":          { kcal: 164, p: 9,  c: 27,  f: 2.6,  proc: 0, fresh: 0.95, micros: 0.85, src: "USDA 16057" },
  "lentils":            { kcal: 116, p: 9,  c: 20,  f: 0.4,  proc: 0, fresh: 0.95, micros: 0.85, src: "USDA 16070" },
  "almonds":            { kcal: 579, p: 21, c: 22,  f: 50,   proc: 0, fresh: 0.95, micros: 0.85, src: "USDA 12061" },
  "walnut":             { kcal: 654, p: 15, c: 14,  f: 65,   proc: 0, fresh: 0.95, micros: 0.85, src: "USDA 12155" },
  "pine nuts":          { kcal: 673, p: 14, c: 13,  f: 68,   proc: 0, fresh: 0.95, micros: 0.8, src: "USDA 12147" },
  "tahini":             { kcal: 595, p: 17, c: 21,  f: 54,   proc: 0.1, fresh: 0.9, micros: 0.85, src: "USDA 12166" },
  "hummus":             { kcal: 166, p: 7.9,c: 14,  f: 9.6,  proc: 0.15, fresh: 0.9, micros: 0.7, src: "USDA 16162" },

  // fats / oils / sweeteners
  "olive oil":          { kcal: 884, p: 0,  c: 0,   f: 100,  proc: 0, fresh: 1.0, micros: 0.5, src: "USDA 04053" },
  "butter":             { kcal: 717, p: 0.9,c: 0.1, f: 81,   proc: 0.05, fresh: 0.9, micros: 0.3, src: "USDA 01001" },
  "ghee":               { kcal: 900, p: 0,  c: 0,   f: 100,  proc: 0.1, fresh: 0.9, micros: 0.3, src: "SFDA-DAIRY-08" },
  "honey":              { kcal: 304, p: 0.3,c: 82,  f: 0,    proc: 0, fresh: 1.0, micros: 0.4, src: "USDA 19296" },
  "sugar":              { kcal: 387, p: 0,  c: 100, f: 0,    proc: 0.6, fresh: 0.5, micros: 0.0, src: "USDA 19335" },

  // sauces / misc
  "yogurt":             { kcal: 59,  p: 10, c: 3.6, f: 0.4,  proc: 0, fresh: 0.95, micros: 0.7, src: "USDA 01256" },
  "mayonnaise":         { kcal: 680, p: 1,  c: 0.6, f: 75,   proc: 0.4, fresh: 0.7, micros: 0.2, src: "USDA 04025" },
  "soy sauce":          { kcal: 53,  p: 8,  c: 5,   f: 0.6,  proc: 0.3, fresh: 0.7, micros: 0.4, src: "USDA 16124" },
  "garlic":             { kcal: 149, p: 6.4,c: 33,  f: 0.5,  proc: 0, fresh: 1.0, micros: 0.8, src: "USDA 11215" },
};

// Synonyms — both EN and AR collapse to canonical keys
const FOOD_ALIASES = {
  "chicken": "chicken breast",
  "chicken breasts": "chicken breast",
  "grilled chicken": "chicken breast",
  "salmon fillet": "salmon",
  "ground meat": "ground beef",
  "rice basmati": "basmati rice",
  "long grain rice": "basmati rice",
  "wholegrain rice": "brown rice",
  "wholewheat pasta": "pasta",
  "tomatoes": "tomato",
  "cucumbers": "cucumber",
  "onions": "onion",
  "bell peppers": "bell pepper",
  "carrots": "carrot",
  "egg yolk": "egg",
  "eggs": "egg",
  "olive": "olive oil",
  "evoo": "olive oil",
  "extra virgin olive oil": "olive oil",
  "greek yogurt": "yogurt",
  "lemon juice": "lemon",
  // arabic
  "دجاج": "chicken breast",
  "صدر دجاج": "chicken breast",
  "سلمون": "salmon",
  "لحم": "beef",
  "لحم مفروم": "ground beef",
  "أرز": "rice",
  "أرز بسمتي": "basmati rice",
  "كينوا": "quinoa",
  "برغل": "bulgur",
  "كسكس": "couscous",
  "خبز": "bread",
  "بطاطا": "potato",
  "بطاطس": "potato",
  "طماطم": "tomato",
  "بندورة": "tomato",
  "خيار": "cucumber",
  "خس": "lettuce",
  "خس روماني": "romaine lettuce",
  "كرنب أجعد": "kale",
  "سبانخ": "spinach",
  "بصل": "onion",
  "فلفل": "bell pepper",
  "جزر": "carrot",
  "باذنجان": "eggplant",
  "بقدونس": "parsley",
  "نعناع": "mint",
  "أفوكادو": "avocado",
  "ليمون": "lemon",
  "تمر": "date",
  "حمص": "chickpeas",
  "عدس": "lentils",
  "لوز": "almonds",
  "جوز": "walnut",
  "صنوبر": "pine nuts",
  "طحينة": "tahini",
  "زيت زيتون": "olive oil",
  "زبدة": "butter",
  "سمن": "ghee",
  "عسل": "honey",
  "سكر": "sugar",
  "زبادي": "yogurt",
  "لبنة": "labneh",
  "فيتا": "feta",
  "حلوم": "halloumi",
  "ثوم": "garlic",
};

// Unit conversions to grams
const UNIT_TO_G = {
  "g": 1, "gm": 1, "gms": 1, "gram": 1, "grams": 1, "جم": 1, "غم": 1, "جرام": 1,
  "kg": 1000, "kilo": 1000, "كغ": 1000, "كيلو": 1000,
  "mg": 0.001,
  "oz": 28.35, "ounce": 28.35, "ounces": 28.35,
  "lb": 453.6, "pound": 453.6,
  "ml": 1, "milliliter": 1, "مل": 1,             // approx for liquids
  "l": 1000, "liter": 1000, "لتر": 1000,
  "cup": 240, "cups": 240, "كوب": 240,
  "tbsp": 15, "tablespoon": 15, "م.ك": 15, "ملعقة كبيرة": 15,
  "tsp": 5, "teaspoon": 5, "م.ص": 5, "ملعقة صغيرة": 5,
  "piece": 60, "pieces": 60, "pc": 60, "pcs": 60, "حبة": 60, "حبات": 60,
  "slice": 30, "slices": 30, "شريحة": 30,
  "clove": 4, "cloves": 4, "فص": 4,
  "handful": 25, "حفنة": 25,
};

// ============================================================
// PARSER  (line → {qty, ingredient, grams})
// ============================================================
const NUM_FRAC = { "½": 0.5, "¼": 0.25, "¾": 0.75, "⅓": 0.33, "⅔": 0.67 };

function parseNumber(token) {
  if (NUM_FRAC[token] != null) return NUM_FRAC[token];
  // mixed: 1½
  const m = token.match(/^(\d+)([½¼¾⅓⅔])$/);
  if (m) return parseInt(m[1], 10) + NUM_FRAC[m[2]];
  // fraction a/b
  if (/^\d+\/\d+$/.test(token)) {
    const [a, b] = token.split("/").map(Number);
    return a / b;
  }
  const n = parseFloat(token);
  return isNaN(n) ? null : n;
}

function findIngredient(rest) {
  const norm = rest.toLowerCase().replace(/[,.;()]/g, " ").replace(/\s+/g, " ").trim();
  // try longest alias match first
  const candidates = Object.keys(FOOD_ALIASES).concat(Object.keys(FOOD_DB))
    .sort((a, b) => b.length - a.length);
  for (const k of candidates) {
    if (norm.includes(k.toLowerCase())) {
      return FOOD_ALIASES[k] || k;
    }
  }
  return null;
}

function parseLine(line) {
  const raw = line.trim();
  if (!raw) return null;

  // strip leading bullets
  let cleaned = raw.replace(/^[-•·*]\s*/, "");

  // Pre-split glued qty+unit tokens like "180g", "1.5kg", "30جم", "½cup"
  // Insert a space between the numeric prefix and the alphabetic suffix.
  cleaned = cleaned.replace(
    /(^|\s)([\d./]+|[½¼¾⅓⅔]|\d+[½¼¾⅓⅔])([a-zA-Z\u0600-\u06FF.]+)/g,
    "$1$2 $3"
  );

  // try to extract leading number + unit
  const tokens = cleaned.split(/\s+/);
  let qty = null;
  let unit = null;
  let i = 0;

  // first token: number (possibly fractional)
  const n = parseNumber(tokens[0]);
  if (n != null) {
    qty = n;
    i = 1;
    // optional unit
    if (tokens[i]) {
      const cand = tokens[i].toLowerCase().replace(/[,.;()]/g, "");
      if (UNIT_TO_G[cand] != null) {
        unit = cand;
        i = 2;
      }
    }
  }

  const rest = tokens.slice(i).join(" ");
  const ingredient = findIngredient(rest);
  if (!ingredient) return { raw, qty, unit, ingredient: null, grams: 0, unresolved: true };

  // resolve grams
  let grams;
  if (qty != null && unit != null) {
    grams = qty * UNIT_TO_G[unit];
  } else if (qty != null) {
    // bare number = pieces (60g default)
    grams = qty * 60;
  } else {
    grams = 100; // default serving
  }

  return { raw, qty, unit, ingredient, grams, unresolved: false };
}

// ============================================================
// ENGINE  (lines → totals + score)
// ============================================================
function computeRecipe(text, servings = 1) {
  const lines = text.split(/\n/).filter(l => l.trim()).flatMap(l => l.split(/,(?![^()]*\))/));
  const items = lines.map(parseLine).filter(Boolean);

  let kcal = 0, p = 0, c = 0, f = 0;
  let procWeighted = 0, freshWeighted = 0, microWeighted = 0;
  let totalGrams = 0;
  const resolved = [], unresolved = [];

  for (const it of items) {
    if (it.unresolved || !it.ingredient) {
      unresolved.push(it);
      continue;
    }
    const food = FOOD_DB[it.ingredient];
    if (!food) { unresolved.push(it); continue; }
    const r = it.grams / 100;
    kcal += food.kcal * r;
    p += food.p * r;
    c += food.c * r;
    f += food.f * r;
    procWeighted += food.proc * it.grams;
    freshWeighted += food.fresh * it.grams;
    microWeighted += food.micros * it.grams;
    totalGrams += it.grams;
    resolved.push({ ...it, food });
  }

  // per-serving
  const perServing = {
    kcal: kcal / servings,
    p: p / servings,
    c: c / servings,
    f: f / servings,
  };

  // ============================================================
  // SAHH SCORE v0.3  (0–100) — calibrated against MoH/SFDA/WHO EMRO
  //   Saturated fat (% of energy)        20%   anchor ≤10%E (SFDA)
  //   Sodium (mg/100kcal)                20%   anchor 100mg/100kcal (WHO 2g/d)
  //   Free sugar (g/100kcal)             20%   anchor <2.5g/100kcal (WHO <10%E)
  //   Energy density (kcal/g)            15%   anchor 2.25 kcal/g (WHO EMRO)
  //   Protein + fibre (g/100kcal)        25%   anchor ≥5g/100kcal (SFDA)
  // ============================================================
  const totalKcal = (p * 4) + (c * 4) + (f * 9) || 1;
  const pPct = (p * 4) / totalKcal;
  const cPct = (c * 4) / totalKcal;
  const fPct = (f * 9) / totalKcal;

  // Heuristics — use FOOD_DB sat/sugar/sodium/fibre when present, else estimate
  // from existing fields. Conservative estimates for v0.3 demo; production
  // scoring uses full per-ingredient sat/sugar/sodium/fibre lookup.
  const satFatG    = f * 0.30;                             // ≈30% of fat is sat (SFDA dishes avg)
  const satFatPctE = (satFatG * 9) / totalKcal;            // share of energy
  const sodiumMg   = procWeighted * 8 + totalGrams * 0.4;  // mg, scaled by processing weight
  const freeSugarG = sumSugar(resolved) / 1;               // g (free sugar only)
  const fibreG     = (microWeighted / Math.max(totalGrams,1)) * totalGrams * 0.04;
  const density    = totalGrams ? kcal / totalGrams : 2;

  // Symmetric anchors: 50 = at threshold, 100 = excellent, 0 = fail
  const satScore    = clamp(50 + ((0.10 - satFatPctE) / 0.10) * 50, 0, 100);
  const sodiumScore = clamp(50 + ((100 - (sodiumMg / Math.max(kcal,1) * 100)) / 100) * 50, 0, 100);
  const sugarScore  = clamp(50 + ((2.5 - (freeSugarG / Math.max(kcal,1) * 100)) / 2.5) * 50, 0, 100);
  const densityScore = clamp(50 + ((2.25 - density) / 2.25) * 50, 0, 100);
  const pfPer100    = ((p + fibreG) / Math.max(kcal,1)) * 100;
  const proteinFibreScore = clamp(50 + ((pfPer100 - 5) / 5) * 50, 0, 100);

  const score = Math.round(
    satScore           * 0.20 +
    sodiumScore        * 0.20 +
    sugarScore         * 0.20 +
    densityScore       * 0.15 +
    proteinFibreScore  * 0.25
  );

  // Tier (v0.3 — locked across product surface)
  const tier =
    score >= 80 ? "balanced"  :
    score >= 60 ? "mindful"   :
    score >= 40 ? "moderate"  :
                  "indulgent";

  // Legacy variables kept for tag rules below
  const macroDist = Math.abs(pPct - 0.25) + Math.abs(cPct - 0.45) + Math.abs(fPct - 0.30);
  const microScore = totalGrams ? clamp((microWeighted / totalGrams) * 100, 0, 100) : 50;
  const procScore  = totalGrams ? clamp(100 - (procWeighted / totalGrams) * 200, 0, 100) : 50;

  // tags
  const tags = [];
  if (pPct >= 0.30) tags.push({ en: "High Protein", ar: "بروتين عالٍ" });
  if (perServing.kcal < 500) tags.push({ en: "Light", ar: "خفيف" });
  if (cPct < 0.35 && pPct > 0.25) tags.push({ en: "Low Carb", ar: "كارب منخفض" });
  if (microScore > 75) tags.push({ en: "Nutrient Dense", ar: "غني بالمغذيات" });
  if (procScore > 85) tags.push({ en: "Whole Foods", ar: "أغذية كاملة" });
  if (Math.abs(macroDist) < 0.2) tags.push({ en: "Balanced", ar: "متوازن" });
  if (totalKcal > 0 && (sumSugar(resolved) / totalKcal) < 0.05) tags.push({ en: "Low Sugar", ar: "سكر منخفض" });

  return {
    perServing,
    score,
    tier,
    breakdown: {
      sat_fat:        Math.round(satScore),
      sodium:         Math.round(sodiumScore),
      free_sugar:     Math.round(sugarScore),
      energy_density: Math.round(densityScore),
      protein_fibre:  Math.round(proteinFibreScore),
    },
    macroPct: { p: pPct, c: cPct, f: fPct },
    items: resolved,
    unresolved,
    tags: tags.slice(0, 4),
    sources: [...new Set(resolved.map(r => r.food.src))],
    confidence: resolved.length / Math.max(1, resolved.length + unresolved.length),
  };
}

// ============================================================
// HELPERS
// ============================================================
function clamp(v, lo, hi) { return Math.min(hi, Math.max(lo, v)); }
function map(v, inLo, inHi, outLo, outHi) {
  return outLo + (v - inLo) * (outHi - outLo) / (inHi - inLo);
}
function sumSugar(items) {
  return items.reduce((s, it) => s + (it.ingredient === "sugar" || it.ingredient === "honey" ? it.grams * 0.9 : 0), 0);
}

// ============================================================
// CLAUDE FALLBACK — only called for unresolved tokens
// Returns { kcal, p, c, f } estimates merged into totals.
// ============================================================
async function resolveWithClaude(unresolved) {
  if (!unresolved.length || !window.claude) return null;
  const lines = unresolved.map(u => u.raw).join("\n");
  const prompt = `Estimate nutrition per ingredient. Reply with ONLY a JSON array, no prose.
For each line below, return {"line":"<original>","grams":<num>,"kcal":<num>,"p":<num>,"c":<num>,"f":<num>}.
Be conservative; use USDA-equivalent values.

Lines:
${lines}`;
  try {
    const text = await window.claude.complete(prompt);
    const match = text.match(/\[[\s\S]*\]/);
    if (!match) return null;
    return JSON.parse(match[0]);
  } catch (e) {
    console.warn("Claude fallback failed:", e);
    return null;
  }
}

window.SahhEngine = {
  FOOD_DB,
  parseLine,
  computeRecipe,
  resolveWithClaude,
};
