// wwwroot/js/ingredients.js

// ======================
// Globals & Helpers
// ======================
let OWNED_SET = new Set();
let ALL_AGG_INGS = [];
let AI_CTRL = null;
const AI_DELAY = 300;
const SEARCH_STATE = { query: "", mode: null };
const els = { list: null, search: null };
// --- Exclusions par recette ---
const RECIPE_ING_CACHE = new Map();         // id -> { '1': [noms], '2': [...], ... }
const EXCLUDED_BY_RECIPE = new Map();       // id -> Set(noms normalisés)
// État “Ingrédients à avoir”
let LAST_ING_TO_HAD = null;
let LAST_PORTIONS = 1;
let lastNeededSignature = "";
let prevNotShippedCount = -1;

const ACCENT_RX = /[\u0300-\u036f]/g;
const normalizeName = (s) => (s || "").trim().toLowerCase();
const normalizeText = (s) => {
    let t = (s || "").toLowerCase();
    try { t = t.normalize("NFD").replace(ACCENT_RX, ""); } catch { }
    return t.replace(/\s/g, " ").trim();
};

// Fractions unicode → décimaux
const VULGAR_FRAC = { "½": "0.5", "¼": "0.25", "¾": "0.75", "⅓": "0.3333", "⅔": "0.6667", "⅛": "0.125", "⅜": "0.375", "⅝": "0.625", "⅞": "0.875" };

// Rang unités
const UNIT_RANK = { "pièce": 6, "piece": 6, "pcs": 6, "pc": 6, "cs": 5, "tbsp": 5, "cc": 4, "tsp": 4, "g": 3, "kg": 3, "mg": 3, "ml": 3, "cl": 3, "l": 3, "": 1 };

const nameKey = (s) => (s || "").trim().toLowerCase();

// --- Exclusions par recette (ingrédients "principaux" ET "à avoir") ---
const EXCLUDED_NEEDED_BY_RECIPE = new Map();  // id -> Set(noms normalisés)


function excludedUnionFrom(map) {
    const out = new Set();
    for (const set of map.values()) for (const n of set) out.add(n);
    return out;
}
function applyNeededExclusions(items) {
    if (EXCLUDED_NEEDED_BY_RECIPE.size === 0) return items;
    const ex = excludedUnionFrom(EXCLUDED_NEEDED_BY_RECIPE);
    return (items || []).filter(it => !ex.has(nameKey(it?.Name)));
}

// Récupère les noms "à avoir" d’une recette (à partir de l’objet recette du strip)
function getNeededNamesForRecipeObj(recipe, portions) {
    if (!recipe) return [];
    const det = detectIngredientsToHadProp(recipe);
    const arr = det ? (det.parsed?.[String(portions)] || []) : [];
    return (Array.isArray(arr) ? arr : [])
        .map(el => (el?.Name ?? el?.name ?? "").toString().trim())
        .filter(Boolean);
}


(function addExcludeStyle() {
    const id = "hf-exclude-style";
    if (document.getElementById(id)) return;
    const st = document.createElement("style"); st.id = id;
    st.textContent = `
    #recipeStrip .card.card--excluded{ opacity:.45; outline:2px dashed #888; }
    #recipeStrip .card.card--excluded:hover{ opacity:.7; }
  `;
    document.head.appendChild(st);
})();

// Retourne les noms d'ingrédients (par portion 1..4) pour une recette
async function getIngredientNamesForRecipe(recipeId, portions = 1) {
    const id = String(recipeId);
    if (!RECIPE_ING_CACHE.has(id)) {
        try {
            const res = await fetch(`/HelloFresh/GetRecipesDetails?ids=${encodeURIComponent(id)}`);
            if (!res.ok) throw new Error("HTTP " + res.status);
            const arr = await res.json();
            const one = Array.isArray(arr) ? arr.find(x => String(x.id) === id) : null;
            const map = {};
            if (one && one.ingredientsJson) {
                try {
                    const obj = JSON.parse(one.ingredientsJson);
                    for (const k of ["1", "2", "3", "4"]) {
                        const list = Array.isArray(obj[k]) ? obj[k] : [];
                        map[k] = list.map(el => (el?.Name ?? el?.name ?? "").toString().trim()).filter(Boolean);
                    }
                } catch { /* ignore */ }
            }
            RECIPE_ING_CACHE.set(id, map);
        } catch (e) {
            console.warn("[ingredients] GetRecipesDetails fail for", id, e);
            RECIPE_ING_CACHE.set(id, {}); // évite re-fetch en boucle
        }
    }
    const cache = RECIPE_ING_CACHE.get(id) || {};
    return (cache[String(portions)] || []).slice();
}

// Union des exclusions (Set global)
function excludedUnion() {
    const out = new Set();
    for (const set of EXCLUDED_BY_RECIPE.values()) {
        for (const n of set) out.add(n);
    }
    return out;
}

// Filtre une liste d’items en appliquant les exclusions
function applyExclusionsTo(items) {
    if (EXCLUDED_BY_RECIPE.size === 0) return items;
    const ex = excludedUnion();
    return (items || []).filter(it => !ex.has(nameKey(it?.Name)));
}

// ========== Normalisation quantités ==========
function normalizeQuantityText(q) {
    if (!q) return "";
    let s = String(q).toLowerCase();
    s = s.replace(/[½¼¾⅓⅔⅛⅜⅝⅞]/g, m => VULGAR_FRAC[m] || m);
    s = s.replace(/\b(\d+)\s*\/\s*(\d+)\b/g, (_, a, b) => {
        const num = parseFloat(a), den = parseFloat(b);
        return (!den || isNaN(num) || isNaN(den)) ? `${a}/${b}` : (num / den).toString();
    });
    s = s.replace(/,/g, ".").replace(/\s+/g, " ").trim();
    s = s
        .replace(/\b(pieces?)\b/g, "pièce")
        .replace(/\b(pcs?)\b/g, "pièce")
        .replace(/\b(gr|grammes?|grams?)\b/g, "g")
        .replace(/\b(millilitres?|milliliters?|mls?)\b/g, "ml")
        .replace(/\b(litres?|liters?)\b/g, "l");
    s = s
        .replace(/\b(c(?:uill[eè]re)?s?\s*(?:a|à)\s*s(?:oupe)?s?\.?)\b/gi, "cs")
        .replace(/\b(c(?:uill[eè]re)?s?\s*(?:a|à)\s*caf[eé]s?s?\.?)\b/gi, "cc");
    s = s.replace(/[\/]+/g, " ").trim();
    return s;
}
function parseQuantity(q) {
    const s = normalizeQuantityText(q);
    const m = s.match(/^([0-9]+(?:\.[0-9]+)?)\s*([a-zéû]+)?$/i);
    if (!m) return { value: NaN, unit: "", raw: s };
    return { value: parseFloat(m[1]), unit: (m[2] || "").trim(), raw: s };
}
function quantityScore(q) {
    const { value, unit, raw } = parseQuantity(q);
    const isNum = !Number.isNaN(value);
    const unitRank = UNIT_RANK[unit] ?? (unit ? 2 : 1);
    return { isNum, unitRank, value: isNum ? value : -Infinity, raw };
}
function pickBestQuantity(qtys) {
    const arr = Array.from(qtys || []);
    if (arr.length === 0) return "";
    const dedup = Array.from(new Map(arr.map(q => [normalizeQuantityText(q), q])).values());
    dedup.sort((a, b) => {
        const sa = quantityScore(a), sb = quantityScore(b);
        if (sa.isNum !== sb.isNum) return sa.isNum ? -1 : 1;
        if (sa.unitRank !== sb.unitRank) return sb.unitRank - sa.unitRank;
        if (sa.value !== sb.value) return sb.value - sa.value;
        return sa.raw.localeCompare(sb.raw, "fr");
    });
    return normalizeQuantityText(dedup[0]);
}

// ========== Ingrédients utils ==========
function normalizeItem(it) {
    if (!it || typeof it !== "object") return { Name: "", Quantity: "", Image: "", Owned: false };
    return {
        Name: it.Name ?? it.name ?? "",
        Quantity: it.Quantity ?? it.quantity ?? "",
        Image: it.Image ?? it.image ?? "",
        Owned: Boolean(it.Owned ?? it.owned ?? false),
    };
}
function isOwned(name) { return OWNED_SET.has(normalizeName(name)); }
function mergeDuplicates(items) {
    const map = new Map();
    for (const raw of items) {
        const it = normalizeItem(raw);
        if (!it.Name) continue;
        const key = normalizeName(it.Name);
        const prev = map.get(key);
        if (!prev) {
            map.set(key, { ...it, _qty: new Set(it.Quantity ? [it.Quantity] : []) });
        } else {
            if (!prev.Image && it.Image) prev.Image = it.Image;
            if (it.Quantity) prev._qty.add(it.Quantity);
            prev.Owned = prev.Owned || it.Owned;
        }
    }
    return Array.from(map.values()).map(x => ({ ...x, Quantity: pickBestQuantity(x._qty) }));
}
function sortIngredientsForDisplay(items) {
    return items.map(normalizeItem).filter(x => x.Name).sort((a, b) => {
        const ao = isOwned(a.Name) ? 1 : 0, bo = isOwned(b.Name) ? 1 : 0;
        if (ao !== bo) return ao - bo;
        return (a.Name || "").localeCompare((b.Name || ""), "fr", { sensitivity: "base" });
    });
}

// ========== UI cartes ingrédients ==========
function renderIngredientCard(ingRaw) {
    const ing = normalizeItem(ingRaw);
    const div = document.createElement("div");
    div.className = "card";
    div.dataset.name = ing.Name;
    if (isOwned(ing.Name)) div.classList.add("checked");
    div.innerHTML = `
    <div class="image-container">
      <img src="${ing.Image || ""}" alt="${ing.Name}">
    </div>
    <div class="card-content">
      <h3>${ing.Name || "(ingrédient)"}</h3>
      <div class="footerCard">
        <div class="selection-slot"></div>
        <div class="recipe-info">
          <span class="prep-time">${ing.Quantity || ""}</span>
        </div>
      </div>
    </div>
  `;
    let busy = false;
    div.addEventListener("click", async () => {
        if (busy) return; busy = true;
        const name = div.dataset.name, key = normalizeName(name), was = div.classList.contains("checked");
        div.classList.toggle("checked");
        try {
            const res = await fetch("/HelloFresh/ToggleOwnedIngredient", {
                method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(name),
            });
            if (!res.ok) throw new Error("HTTP " + res.status);
            const { status } = await res.json();
            if (status === "added") OWNED_SET.add(key);
            else if (status === "removed") OWNED_SET.delete(key);
            else div.classList.toggle("checked", was);
            const idx = ALL_AGG_INGS.findIndex(x => normalizeName(x.Name) === key);
            if (idx !== -1) ALL_AGG_INGS[idx].Owned = (status === "added");
        } catch (e) {
            console.error("Erreur toggle ingrédient", e);
            div.classList.toggle("checked", was);
        } finally {
            busy = false; reapplyCurrentSearch();
        }
    });
    return div;
}
function renderItems(items) {
    if (!els.list) return;
    els.list.innerHTML = "";
    items.forEach(ing => els.list.appendChild(renderIngredientCard(ing)));
}

// ========== Recherche ==========
async function applyAISearch(q) {
    SEARCH_STATE.query = q; SEARCH_STATE.mode = q ? "ai" : null;
    if (!q?.trim()) { renderItems(sortIngredientsForDisplay(mergeDuplicates([...ALL_AGG_INGS]))); return; }
    if (els.list) els.list.innerHTML = "<em>Recherche IA…</em>";
    try {
        if (AI_CTRL) AI_CTRL.abort(); AI_CTRL = new AbortController();
        const res = await fetch("/HelloFresh/SmartSearch?debug=true", {
            method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ query: q }), signal: AI_CTRL.signal
        });
        const raw = await res.clone().text();
        if (!res.ok) { console.warn("AI SmartSearch HTTP", res.status, raw); applyLiveFilter(q); return; }
        const data = JSON.parse(raw);
        const items = Array.isArray(data?.items) ? data.items : [];
        if (!items.length) { applyLiveFilter(q); return; }
        renderItems(sortIngredientsForDisplay(mergeDuplicates(items)));
    } catch (err) {
        if (err.name === "AbortError") console.log("[AI] annulée");
        else { console.error("AI SmartSearch error:", err); applyLiveFilter(q); }
    } finally { AI_CTRL = null; }
}
function applyLiveFilter(q) {
    SEARCH_STATE.query = String(q ?? ""); SEARCH_STATE.mode = q ? "live" : null;
    const nq = normalizeText(q);
    if (!nq) { renderItems(sortIngredientsForDisplay(mergeDuplicates([...ALL_AGG_INGS]))); return; }
    const filtered = ALL_AGG_INGS.filter(x => normalizeText(x.Name).includes(nq));
    const list = sortIngredientsForDisplay(mergeDuplicates(applyExclusionsTo(filtered)));
    renderItems(list);
}
function reapplyCurrentSearch() {
    const q = SEARCH_STATE.query || "";
    if (!q) {
        const base = sortIngredientsForDisplay(mergeDuplicates([...ALL_AGG_INGS]));
        renderItems(applyExclusionsTo(base));
        return;
    }
    if (SEARCH_STATE.mode === "ai") applyAISearch(q); else applyLiveFilter(q);
}

// ========== Chargement liste principale ==========
async function loadAndRenderIngredients() {
    if (!els.list) return;
    els.list.innerHTML = "Chargement…";
    try {
        const res = await fetch("/HelloFresh/AggregatedIngredients");
        if (!res.ok) { const txt = await res.text().catch(() => ""); console.error("[AggregatedIngredients] HTTP", res.status, txt); els.list.innerHTML = `Erreur chargement ingrédients (${res.status})`; return; }
        const data = await res.json();
        ALL_AGG_INGS = Array.isArray(data) ? data : [];
        OWNED_SET = new Set(ALL_AGG_INGS.filter(x => x?.Name && x.Owned === true).map(x => x.Name.trim().toLowerCase()));
        els.list.innerHTML = "";
        const initialMerged = mergeDuplicates([...ALL_AGG_INGS]);
        const initial = sortIngredientsForDisplay(applyExclusionsTo(initialMerged));
        els.list.innerHTML = "";
        renderItems(initial.length ? initial : []);
        if (!initial.length) els.list.innerHTML = "<em>Aucun ingrédient</em>";
    } catch (e) { console.error("[AggregatedIngredients] exception", e); els.list.innerHTML = "Erreur chargement ingrédients"; }
}

// ========== Not shipped (DOM) + BDD ==========
function getNotShippedIngredientsFromDOM(root = document) {
    const nodes = Array.from(root.querySelectorAll(".ingredient-item-not-shipped"));
    return nodes.map(n => {
        const name = (n.querySelector('[data-test="ingredient-name"], .ingredient-name, .name, h3, span')?.textContent || n.getAttribute("data-name") || n.querySelector("img")?.alt || "").trim();
        const qty = (n.querySelector('[data-test="ingredient-quantity"], .ingredient-amount, .quantity, .qty')?.textContent || n.getAttribute("data-quantity") || "").trim();
        const img = (n.querySelector("img")?.src || n.getAttribute("data-img") || "").trim();
        return normalizeItem({ Name: name, Quantity: qty, Image: img, Owned: isOwned(name) });
    }).filter(x => x.Name);
}
// Détecte la propriété "ingredients à avoir" dans un objet recette,
// même si le nom varie (ingredientsToHad / IngredientsToHad / pantry / etc.)
function detectIngredientsToHadProp(recipe) {
    if (!recipe || typeof recipe !== "object") return null;

    // Candidats fréquents (essayés d'abord)
    const CANDIDATES = [
        "ingredientsToHad", "IngredientsToHad", "ingredients_to_had",
        "ingredientsToHaveAtHome", "ingredientsToHave", "toHaveAtHome",
        "pantry", "pantryItems", "pantry_ingredients", "ingredientsPantry"
    ];

    for (const key of CANDIDATES) {
        if (key in recipe && recipe[key]) {
            try {
                const val = recipe[key];
                const obj = (typeof val === "string") ? JSON.parse(val) : val;
                if (obj && typeof obj === "object" &&
                    (Array.isArray(obj["1"]) || Array.isArray(obj["2"]) || Array.isArray(obj["3"]) || Array.isArray(obj["4"]))) {
                    return { prop: key, parsed: obj };
                }
            } catch { }
        }
    }

    // Heuristique : scanne toutes les props à la recherche d’un objet 1..4 -> array d’objets Name/Quantity
    for (const [key, val] of Object.entries(recipe)) {
        if (!val) continue;
        try {
            const obj = (typeof val === "string") ? JSON.parse(val) : val;
            if (obj && typeof obj === "object") {
                const arr = obj["1"] || obj["2"] || obj["3"] || obj["4"];
                if (Array.isArray(arr) && arr.length) {
                    const it = arr[0] || {};
                    if (typeof it === "object" && ("Name" in it || "name" in it)) {
                        return { prop: key, parsed: obj };
                    }
                }
            }
        } catch { }
    }
    return null;
}

// Lit une recette en tolérant la casse / formats
function getIngredientsToHadFromRecipe(r) {
    const det = detectIngredientsToHadProp(r);
    if (!det) return [];
    const pRaw = r?.portions ?? r?.Portions ?? 0;
    const portions = clampQty(pRaw) + 1; // 1..4
    const list = Array.isArray(det.parsed[portions]) ? det.parsed[portions] : [];
    return list.map(normalizeItem);
}


function collectIngredientsToHadFromAllRecipes() {
    const res = [];
    const all = Array.isArray(window.allRecipes) ? window.allRecipes : [];
    for (const r of all) res.push(...getIngredientsToHadFromRecipe(r));
    return res;
}

function computeSignature(items) {
    const merged = mergeDuplicates(items || []);
    return JSON.stringify(merged.map(i => ({ n: normalizeName(i.Name), q: normalizeQuantityText(i.Quantity), img: i.Image || "" })));
}

function renderNeededList(itemsArr) {
    const container = document.getElementById("neededIngredients");
    if (!container) return;
    const merged = mergeDuplicates(itemsArr || []);
    const sig = computeSignature(merged);
    if (sig === lastNeededSignature) return;
    lastNeededSignature = sig;
    container.innerHTML = "";
    for (const ing of merged) {
        const li = document.createElement("li");
        li.className = "card needed";
        li.innerHTML = `
      <div class="image-container"><img src="${ing.Image || ""}" alt="${ing.Name}"></div>
      <div class="card-content">
        <h3>${ing.Name || "(ingrédient)"}</h3>
        <div class="footerCard"><div class="recipe-info"></div></div>
      </div>`;
        container.appendChild(li);
    }
}
function updateNeededList(trigger = "manual") {
    const container = document.getElementById("neededIngredients");
    if (!container) {
        console.debug("[needed]", trigger, "→ container #neededIngredients introuvable (on réessaiera)");
        return;
    }
    console.debug("[needed]", trigger, "→ container OK");

    // 1) DOM (non livrés)
    const domItems = getNotShippedIngredientsFromDOM();
    if (domItems.length) {
        const filtered = applyNeededExclusions(domItems);
        renderNeededList(filtered);
        return;
    }

    // 2) Agrégation de TOUTES les recettes
    const aggregated = collectIngredientsToHadFromAllRecipes();
    if (aggregated.length) {
        const filtered = applyNeededExclusions(aggregated);
        renderNeededList(filtered);
        return;
    }

    // 3) Dernière recette vue (fallback)
    if (LAST_ING_TO_HAD) {
        try {
            const parsed = JSON.parse(LAST_ING_TO_HAD || "{}");
            const list = Array.isArray(parsed[LAST_PORTIONS]) ? parsed[LAST_PORTIONS] : [];
            const filtered = applyNeededExclusions(list);
            if (filtered.length) {
                renderNeededList(filtered);
                return;
            }
        } catch (e) { /* ... */ }
    }


    // 4) Rien
    const emptySig = "EMPTY";
    if (lastNeededSignature !== emptySig) {
        lastNeededSignature = emptySig;
        container.innerHTML = "<p>Aucun ingrédient à afficher.</p>";
    }
    console.warn("[needed]", trigger, "→ aucun item");
}

// Scan DOM non-livrés (anti-boucle)
function scanNotShippedAndUpdate() {
    const count = document.querySelectorAll(".ingredient-item-not-shipped").length;
    if (count !== prevNotShippedCount) { prevNotShippedCount = count; updateNeededList(); }
}

// ========== Recettes (strip) ==========
const ownedMap = new Map();
const MAX_PORTIONS = 14;
const clampQty = n => Math.max(0, Math.min(3, Number(n) || 0));
const truncate = (s, m) => (s && s.length > m ? s.slice(0, m) + "…" : (s ?? ""));

function setSelectedUI(card, selected) {
    const slot = card?.querySelector?.(".selection-slot"); if (!slot) return;
    if (selected) {
        slot.classList.add("active");
        if (!slot.querySelector(".selection-indicator")) {
            slot.innerHTML = `<div class="selection-indicator"><span class="selection-text">Sélectionné</span></div>`;
        }
    } else { slot.classList.remove("active"); slot.innerHTML = ""; }
}
function applySelectionUIById(id) {
    const card = document.getElementById(String(id));
    const selected = (ownedMap.get(String(id)) || 0) > 0;
    setSelectedUI(card, selected);
}

function buildLabels(tagsStr) {
    const wrap = document.createElement("div");
    wrap.className = "label-container";
    const tags = (tagsStr || "").split(/[,•]/).map(t => t.trim()).filter(Boolean).filter(t => t !== "•" && t !== "\u2022");
    tags.forEach(tag => {
        const span = document.createElement("span");
        span.className = "label-badge";
        const c = (window.labelColors || {})[tag];
        span.style.backgroundColor = c?.bg ?? "#eee";
        span.style.color = c?.color ?? "#333";
        span.textContent = tag;
        wrap.appendChild(span);
    });
    return wrap;
}

function buildRecipeCardList(recipe) {
    const card = document.createElement("div");
    card.className = "card";
    card.id = recipe.id ?? recipe.Id;
    card.innerHTML = `
    <div class="image-container"><img src="${recipe.image}" alt="${truncate(recipe.name, 10)}"></div>
    <div class="card-content">
      <h3>${recipe.name}</h3>
      <div class="footerCard"><div class="recipe-info"><span class="prep-time">${recipe.tempsDePreparation}min</span></div></div>
    </div>
  `.replace(/\${/g, "${");
    card.addEventListener("click", async (e) => {
        if (e.ctrlKey) return; // laisse le Ctrl+clic tranquille

        const id = recipe.id ?? recipe.Id;
        const portions = clampQty(recipe.portions ?? recipe.Portions ?? 0) + 1; // 1..4

        if (EXCLUDED_BY_RECIPE.has(String(id))) {
            // ré-afficher
            EXCLUDED_BY_RECIPE.delete(String(id));
            EXCLUDED_NEEDED_BY_RECIPE.delete(String(id));     // 👈 aussi pour "à avoir"
            card.classList.remove("card--excluded");
        } else {
            // cacher
            const namesMain = await getIngredientNamesForRecipe(id, portions); // déjà en place chez toi
            EXCLUDED_BY_RECIPE.set(String(id), new Set(namesMain.map(nameKey)));

            const namesNeeded = getNeededNamesForRecipeObj(recipe, portions);   // 👈 "à avoir" depuis l’objet recette
            EXCLUDED_NEEDED_BY_RECIPE.set(String(id), new Set(namesNeeded.map(nameKey)));

            card.classList.add("card--excluded");
        }

        // Re-rendre les deux panneaux
        reapplyCurrentSearch();       // liste principale
        updateNeededList("exclude-toggle");  // “à avoir”
    });


    const usersVal = recipe.Users ?? recipe.users ?? recipe.User ?? recipe.user ?? [];
    const usersArr = Array.isArray(usersVal) ? usersVal.filter(Boolean) : String(usersVal || "").split(/[,•]/).map(s => s.trim()).filter(Boolean);
    if (usersArr.length) {
        const img = card.querySelector(".image-container");
        const wrap = document.createElement("div"); wrap.className = "label-container";
        usersArr.forEach(u => { const span = document.createElement("span"); span.className = "label-badge user-badge"; span.textContent = u; wrap.appendChild(span); });
        img?.appendChild(wrap);
    }

    // Mémorise la dernière recette pour un fallback, via détection auto
    const det = detectIngredientsToHadProp(recipe);
    const portions = clampQty(recipe.portions ?? recipe.Portions ?? 0) + 1;
    LAST_PORTIONS = portions;
    LAST_ING_TO_HAD = det ? JSON.stringify(det.parsed) : null;

    console.debug("[needed] buildRecipe detected prop:", det?.prop || "(none)", "portions:", portions);
    updateNeededList("buildRecipe");


    return card;
}

const GET_ALL_RECIPES_URL = "/HelloFresh/GetAllRecipes";
async function loadAllRecipesHorizontal() {
    const strip = document.getElementById("recipeStrip");
    if (!strip) return;

    try {
        const r = await fetch("/HelloFresh/GetRecipesOwned?isUserImportant=false", { credentials: "same-origin" });
        if (r.ok) { const data = await r.json(); ownedMap.clear(); (data || []).forEach(x => ownedMap.set(String(x.id), clampQty(x.portions || 0))); }
    } catch { }

    try {
        const res = await fetch(GET_ALL_RECIPES_URL, { credentials: "same-origin" });
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        const all = await res.json();
        window.allRecipes = all;

        strip.innerHTML = "";
        if (!Array.isArray(all) || all.length === 0) { strip.innerHTML = '<p class="placeholder">Aucune recette disponible.</p>'; updateNeededList(); return; }

        all.sort((a, b) => {
            const ua = String(a.userId ?? ""), ub = String(b.userId ?? "");
            if (ua !== ub) return ua.localeCompare(ub);
            return String(a.name ?? "").localeCompare(String(b.name ?? ""), "fr", { sensitivity: "base" });
        });

        all.forEach(r => strip.appendChild(buildRecipeCardList(r)));
        updateNeededList("afterGetAllRecipes");
        console.debug("[needed] recipes loaded:", Array.isArray(window.allRecipes) ? window.allRecipes.length : 0);

    } catch (e) {
        console.error("loadAllRecipesHorizontal error", e);
        strip.innerHTML = '<p class="placeholder">Erreur de chargement.</p>';
        updateNeededList();
    }
}

// ======================
// Init
// ======================
document.addEventListener("DOMContentLoaded", () => {
    els.list = document.getElementById("ingredientsList") || null;
    els.search = document.getElementById("hfSearch") || null;

    document.querySelectorAll(".dropdown-toggle").forEach(el => el.addEventListener("click", (e) => e.preventDefault()));

    if (els.search) {
        let aiTimer;
        els.search.addEventListener("input", (e) => { clearTimeout(aiTimer); const val = e.target.value || ""; aiTimer = setTimeout(() => applyAISearch(val), AI_DELAY); });
        els.search.addEventListener("keydown", (e) => { if (e.key === "Enter") { e.preventDefault(); clearTimeout(aiTimer); applyAISearch(els.search.value || ""); } });
    } else {
        console.error("[ingredients] #hfSearch introuvable dans le DOM");
    }

    loadAndRenderIngredients();
    loadAllRecipesHorizontal();

    // Premier rendu (même si le UL n'est pas encore dans le DOM, on loggue)
    updateNeededList("dom-ready");

    // Petits réessaies pour les pages qui injectent tardivement le UL / les cartes
    setTimeout(() => updateNeededList("post-300ms"), 300);
    setTimeout(() => updateNeededList("post-1200ms"), 1200);
    const mo = new MutationObserver(() => {
        // Throttle : on regroupe les mutations
        if (typeof window !== "undefined") {
            if (mo._scheduled) return;
            mo._scheduled = true;
            setTimeout(() => {
                mo._scheduled = false;
                updateNeededList("mutation");
            }, 120);
        } else {
            updateNeededList("mutation");
        }
    });
    mo.observe(document.body, { childList: true, subtree: true });

});
