/* NutriDMS, Meal Program Builder
   Multi-step create/edit flow with 3 switchable layouts (left-rail · top-stepper
   · card-grid), a collapsed-by-default Loraa assistant, and live validation.
   ════════════════════════════════════════════════════════════════════════ */
const { useState: bUseState, useEffect: bUseEffect, useMemo: bUseMemo } = React;

const MPB_STEPS = [
  { id: "basics", t: "Basics", s: "Name & template", ic: "file-edit" },
  { id: "recipes", t: "Recipes", s: "Choose approved recipes", ic: "utensils-crossed" },
  { id: "rules", t: "Rules", s: "Targets & restrictions", ic: "sliders-horizontal" },
  { id: "validate", t: "Validate", s: "Loraa check", ic: "lightbulb" },
  { id: "assignments", t: "Assignments", s: "Auto-generated fixes", ic: "list-checks" },
  { id: "review", t: "Review", s: "Save or submit", ic: "check-circle-2" },
];

const MPB_LAYOUT_KEY = "nutridms.mp.builderLayout";
function mpbLayout() { try { return localStorage.getItem(MPB_LAYOUT_KEY) || "rail"; } catch (e) { return "rail"; } }
function mpbSetLayout(v) { try { localStorage.setItem(MPB_LAYOUT_KEY, v); } catch (e) {} window.dispatchEvent(new Event("nutridms-mp-layout")); }

const NUTRIENT_OPTS = ["Sodium", "Added Sugar", "Fiber", "Protein", "Carbohydrates", "Fat", "Calories"];
const UNIT_BY_NUTR = { Sodium: "mg/day", "Added Sugar": "g/day", Fiber: "g/day", Protein: "g/day", Carbohydrates: "g/day", Fat: "g/day", Calories: "kcal/day" };

/* Map an org Health-Condition record's nutrient tokens → builder daily restrictions.
   Pulls from Settings → Compliance → Health Conditions (compConditionNames + records). */
const MP_COND_NUTR_MAP = {
  sodium: { nutrient: "Sodium", op: "<", value: 1500, unit: "mg/day" },
  "saturated fat": { nutrient: "Fat", op: "<", value: 20, unit: "g/day" },
  fat: { nutrient: "Fat", op: "<", value: 65, unit: "g/day" },
  sugar: { nutrient: "Added Sugar", op: "<", value: 25, unit: "g/day" },
  "added sugar": { nutrient: "Added Sugar", op: "<", value: 25, unit: "g/day" },
  carbohydrate: { nutrient: "Carbohydrates", op: "<", value: 180, unit: "g/day" },
  fiber: { nutrient: "Fiber", op: ">", value: 28, unit: "g/day" },
  protein: { nutrient: "Protein", op: ">", value: 50, unit: "g/day" },
  calorie: { nutrient: "Calories", op: "<", value: 1800, unit: "kcal/day" },
};
function mpConditionRecords() {
  try { return (compLoad().conditions || []).filter((c) => c.status === "active"); } catch (e) { return []; }
}
/* Derive restriction rows for a set of condition names, deduped by nutrient. */
function mpRestrictionsForConditions(names) {
  const recs = mpConditionRecords();
  const out = []; const seen = new Set();
  (names || []).forEach((nm) => {
    const rec = recs.find((c) => c.name === nm); if (!rec) return;
    (rec.nutrients || []).forEach((tok) => {
      const key = Object.keys(MP_COND_NUTR_MAP).find((k) => String(tok).toLowerCase().includes(k));
      if (key && !seen.has(MP_COND_NUTR_MAP[key].nutrient)) { seen.add(MP_COND_NUTR_MAP[key].nutrient); out.push({ ...MP_COND_NUTR_MAP[key] }); }
    });
  });
  return out;
}

function mpBlankProgram() {
  return {
    id: "mp-" + Date.now(), name: "", type: "consumer", description: "",
    durationWeeks: 4, population: "", frequency: "3 meals/day",
    goals: [], conditions: [], restrictions: [{ nutrient: "Fiber", op: ">", value: 25, unit: "g/day" }],
    channel: "portal", status: "draft", owner: { name: "Eve Nakamura", initials: "EN" }, reviewer: null,
    tags: [], version: "v0.1", created: "2026-06-18", updated: "2026-06-18", days: [], _wfStepIdx: 0,
  };
}
// derive recipe pool from days; build days from pool
function poolFromDays(days) { return Array.from(new Set((days || []).map((d) => d.recipeId))); }
function daysFromPool(pool, frequency) {
  const slots = frequency.startsWith("4") ? ["Breakfast", "Lunch", "Dinner", "Snack"] : ["Breakfast", "Lunch", "Dinner"];
  const out = [];
  pool.forEach((rid, i) => { out.push({ day: Math.floor(i / slots.length) + 1, meal: slots[i % slots.length], recipeId: rid, serving: "1 serving" }); });
  return out;
}

function MealProgramBuilder() {
  useMpRerender();
  const { role, setPage, toast } = useApp();
  if (!mpEnabled()) return <MealProgramsGate />;

  const editing = bUseMemo(() => (window.__mpOpen ? mpGet(window.__mpOpen) : null), []);
  const [draft, setDraft] = bUseState(() => editing ? JSON.parse(JSON.stringify(editing)) : mpBlankProgram());
  const [pool, setPool] = bUseState(() => poolFromDays(draft.days));
  const [step, setStep] = bUseState("basics");
  const [layout, setLayout] = bUseState(mpbLayout);
  const [loraaOpen, setLoraaOpen] = bUseState(false);
  bUseEffect(() => { const h = () => setLayout(mpbLayout()); window.addEventListener("nutridms-mp-layout", h); return () => window.removeEventListener("nutridms-mp-layout", h); }, []);

  const set = (patch) => setDraft((d) => ({ ...d, ...patch }));
  const stepIdx = MPB_STEPS.findIndex((s) => s.id === step);
  const progForValidation = bUseMemo(() => ({ ...draft, days: daysFromPool(pool, draft.frequency) }), [JSON.stringify(draft), JSON.stringify(pool)]);
  const flags = bUseMemo(() => mpValidate(progForValidation), [JSON.stringify(progForValidation)]);
  const crit = flags.filter((f) => f.severity === "critical").length;

  const toggleRecipe = (rid) => setPool((p) => p.includes(rid) ? p.filter((x) => x !== rid) : [...p, rid]);

  // Loraa fix: replace the flagged recipe in the pool with an approved suggestion.
  const swapInPool = (flag, newRecipe, cell) => {
    const oldId = cell ? cell.recipeId : null;
    setPool((p) => {
      if (oldId && p.includes(oldId)) {
        const mapped = p.map((x) => (x === oldId ? newRecipe.id : x));
        return mapped.filter((x, i, a) => a.indexOf(x) === i);
      }
      return p.includes(newRecipe.id) ? p : [...p, newRecipe.id];
    });
    toast(`Swapped in ${newRecipe.name}`);
  };

  const persist = (status, msg) => {
    const out = { ...draft, days: daysFromPool(pool, draft.frequency), status, updated: "2026-06-18", _wfStepIdx: status === "draft" ? 0 : 1 };
    mpUpsert(out); toast(msg); window.__mpOpen = out.id; setPage("meal-program-detail");
  };

  const stepDone = (id) => {
    const i = MPB_STEPS.findIndex((s) => s.id === id);
    if (i === 0) return draft.name.trim().length > 0;
    if (i === 1) return pool.length > 0;
    if (i === 2) return (draft.restrictions || []).length > 0;
    return i < stepIdx;
  };

  // ── Step bodies ──
  const Body = () => {
    if (step === "basics") return (
      <>
        <h2>Program basics</h2>
        <p className="mpb-sub">Start from a program type, then describe what this plan is for.</p>
        <div style={{ marginBottom: 18 }}>
          <label style={{ fontSize: 12.5, fontWeight: 700, color: "var(--gray-700)", display: "block", marginBottom: 9 }}>Program type</label>
          <div className="mp-templates">
            {MP_TYPES.map((t) => {
              const locked = t.enterprise && mpPlan() !== "enterprise";
              return (
                <button key={t.id} className={`mp-template ${t.id} ${draft.type === t.id ? "on" : ""} ${locked ? "enterprise locked" : ""}`} onClick={() => !locked && set({ type: t.id })}>
                  <div className="mp-template-ic"><Icon name={t.icon} size={20} /></div>
                  <div className="mp-template-t">{t.label} {locked && <span className="pill neutral" style={{ fontSize: 10 }}><Icon name="lock" size={10} /> Ent.</span>}</div>
                  <div className="mp-template-ex">{t.ex.slice(0, 3).join(" · ")}</div>
                </button>
              );
            })}
          </div>
        </div>
        <div className="mpb-grid2">
          <div className="mpb-field"><label>Program name</label><input className="input" value={draft.name} onChange={(e) => set({ name: e.target.value })} placeholder="e.g. 12-Week Diabetes Weight Management" /></div>
          <div className="mpb-field"><label>Population</label><input className="input" value={draft.population} onChange={(e) => set({ population: e.target.value })} placeholder="e.g. Adults · Type 2 Diabetes" /></div>
        </div>
        <div className="mpb-field" style={{ marginTop: 14 }}><label>Description</label><textarea className="input" rows={3} value={draft.description} onChange={(e) => set({ description: e.target.value })} placeholder="What is this program designed to achieve?" /></div>
        <div className="mpb-grid2" style={{ marginTop: 14 }}>
          <div className="mpb-field"><label>Duration (weeks)</label><input className="input" type="number" min={1} value={draft.durationWeeks} onChange={(e) => set({ durationWeeks: +e.target.value || 1 })} /></div>
          <div className="mpb-field"><label>Meal frequency</label><select className="select" value={draft.frequency} onChange={(e) => set({ frequency: e.target.value })}><option>3 meals/day</option><option>4 meals/day</option><option>5 meals/day</option></select></div>
        </div>
      </>
    );
    if (step === "recipes") return (
      <>
        <h2>Choose approved recipes</h2>
        <p className="mpb-sub">Pick from your library, only <strong>approved &amp; published</strong> recipes appear here, linked live to the Recipe Library. Selected recipes fill the schedule across days &amp; meals.</p>
        <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 14 }}>
          <span className="pill" style={{ background: "var(--green-50)", color: "var(--green-700)", border: "1px solid var(--green-200)" }}><Icon name="check" size={11} /> {pool.length} selected</span>
          {pool.length > 0 && <button className="btn ghost sm" onClick={() => setPool([])}>Clear</button>}
        </div>
        <div className="mp-recipe-pick">
          {(window.RECIPES || []).filter((r) => r.status === "approved" || r.status === "published").map((r) => {
            const on = pool.includes(r.id);
            return (
              <button key={r.id} className={`mp-recipe-tile ${on ? "on" : ""}`} onClick={() => toggleRecipe(r.id)}>
                <div className="mp-recipe-thumb" style={{ backgroundImage: `url("${r.cover}")` }} />
                <span className="mp-recipe-st approved">{r.status === "published" ? "Published" : "Approved"}</span>
                {on && <span className="mp-recipe-mk"><Icon name="check" size={13} stroke={3} /></span>}
                <div className="mp-recipe-body"><div className="mp-recipe-nm">{r.name}</div></div>
              </button>
            );
          })}
        </div>
        {pool.length > 0 && (
          <>
            <div className="mp-section-h" style={{ margin: "22px 0 10px" }}><Icon name="utensils" size={17} className="ic" /><h3>Selected recipes</h3><span className="count">{pool.length}</span></div>
            <div className="mp-selrec-grid">
              {pool.map((rid) => <MpSelectedRecipeCard key={rid} recipeId={rid} onRemove={() => toggleRecipe(rid)} />)}
            </div>
            <div className="mp-section-h" style={{ margin: "22px 0 10px" }}><Icon name="calendar-days" size={17} className="ic" /><h3>Schedule preview</h3></div>
            <MpScheduleGrid prog={progForValidation} />
          </>
        )}
      </>
    );
    if (step === "rules") return (
      <>
        <h2>Targets &amp; restrictions</h2>
        <p className="mpb-sub">Loraa validates every day of the plan against these. Conditions pull in your compliance health-tag rules too.</p>
        <div className="mpb-field" style={{ marginBottom: 16 }}>
          <label>Health conditions <span style={{ fontWeight: 500, color: "var(--gray-500)" }}>· pulled from your org rules</span></label>
          <div className="mp-cond-chips">
            {(draft.conditions || []).map((c) => (
              <span key={c} className="mp-cond-chip">{c}<button onClick={() => set({ conditions: (draft.conditions || []).filter((x) => x !== c) })}><Icon name="x" size={12} /></button></span>
            ))}
            {(draft.conditions || []).length === 0 && <span className="mp-cond-empty">No conditions selected</span>}
          </div>
          <select className="select" value="" onChange={(e) => {
            const nm = e.target.value; if (!nm || (draft.conditions || []).includes(nm)) return;
            const conds = [...(draft.conditions || []), nm];
            const add = mpRestrictionsForConditions([nm]);
            const existing = draft.restrictions || [];
            const merged = [...existing];
            add.forEach((r) => { if (!merged.some((x) => x.nutrient === r.nutrient)) merged.push(r); });
            set({ conditions: conds, restrictions: merged });
            if (window.__toast) {} 
          }}>
            <option value="">+ Add a condition…</option>
            {mpConditionRecords().filter((c) => !(draft.conditions || []).includes(c.name)).map((c) => <option key={c.id} value={c.name}>{c.name} · {c.category}</option>)}
          </select>
          <div className="mpb-hint" style={{ marginTop: 6 }}>Selecting a condition auto-fills its daily nutrient restrictions below.</div>
        </div>
        <label style={{ fontSize: 12.5, fontWeight: 700, color: "var(--gray-700)", display: "block", marginBottom: 9 }}>Daily nutrient restrictions</label>
        {(draft.restrictions || []).map((r, i) => (
          <div key={i} className="mp-restr-row">
            <select className="select" value={r.nutrient} onChange={(e) => { const v = e.target.value; const rs = [...draft.restrictions]; rs[i] = { ...rs[i], nutrient: v, unit: UNIT_BY_NUTR[v] }; set({ restrictions: rs }); }}>
              {NUTRIENT_OPTS.map((n) => <option key={n}>{n}</option>)}
            </select>
            <select className="select" style={{ width: 64 }} value={r.op} onChange={(e) => { const rs = [...draft.restrictions]; rs[i] = { ...rs[i], op: e.target.value }; set({ restrictions: rs }); }}>
              <option value="<">&lt;</option><option value=">">&gt;</option>
            </select>
            <input className="input" type="number" value={r.value} onChange={(e) => { const rs = [...draft.restrictions]; rs[i] = { ...rs[i], value: +e.target.value }; set({ restrictions: rs }); }} />
            <button className="icon-btn" onClick={() => set({ restrictions: draft.restrictions.filter((_, j) => j !== i) })}><Icon name="trash-2" size={15} /></button>
          </div>
        ))}
        <button className="btn secondary sm" style={{ marginTop: 6 }} onClick={() => set({ restrictions: [...(draft.restrictions || []), { nutrient: "Sodium", op: "<", value: 1500, unit: "mg/day" }] })}><Icon name="plus" size={13} /> Add restriction</button>
      </>
    );
    if (step === "validate") return (
      <>
        <h2>Loraa validation</h2>
        <p className="mpb-sub">A live check of the plan against its targets, recipe approval status, allergens, duplicates, and rotation.</p>
        <MpValidationPanel prog={progForValidation} onFix={(f) => setStep("recipes")} onSwap={swapInPool} />
      </>
    );
    if (step === "assignments") return (
      <>
        <h2>Generated assignments</h2>
        <p className="mpb-sub">Loraa turns every blocking or high-severity issue into an assignable correction task.</p>
        <MpAssignmentBoard prog={progForValidation} />
      </>
    );
    if (step === "review") return (
      <>
        <h2>Review &amp; submit</h2>
        <p className="mpb-sub">Final check before this enters the review workflow.</p>
        <div className="mp-side-card" style={{ marginBottom: 14 }}>
          <h4>Summary</h4>
          <div className="mp-fact"><span className="mp-fact-k">Name</span><span className="mp-fact-v">{draft.name || "Untitled"}</span></div>
          <div className="mp-fact"><span className="mp-fact-k">Type</span><span className="mp-fact-v">{(MP_TYPES.find((t) => t.id === draft.type) || {}).label}</span></div>
          <div className="mp-fact"><span className="mp-fact-k">Duration</span><span className="mp-fact-v">{draft.durationWeeks} weeks · {draft.frequency}</span></div>
          <div className="mp-fact"><span className="mp-fact-k">Recipes</span><span className="mp-fact-v">{pool.length} selected</span></div>
          <div className="mp-fact"><span className="mp-fact-k">Loraa issues</span><span className="mp-fact-v">{flags.length === 0 ? "None" : `${flags.length} (${crit} blocking)`}</span></div>
        </div>
        {crit > 0 && (
          <div className="pill warning" style={{ padding: "11px 14px", fontSize: 12.5, lineHeight: 1.5, display: "flex", gap: 8, alignItems: "flex-start", whiteSpace: "normal" }}>
            <Icon name="alert-triangle" size={14} style={{ flexShrink: 0, marginTop: 1 }} />
            <span>{crit} blocking issue{crit === 1 ? "" : "s"} will be attached as assignments. You can still save a draft; submitting routes it for review with the fixes flagged.</span>
          </div>
        )}
      </>
    );
    return null;
  };

  const goNext = () => { if (stepIdx < MPB_STEPS.length - 1) setStep(MPB_STEPS[stepIdx + 1].id); };
  const goPrev = () => { if (stepIdx > 0) setStep(MPB_STEPS[stepIdx - 1].id); };

  return (
    <div>
      <Crumbs path={[{ label: "Meal Programs", onClick: () => setPage("meal-programs") }, { label: editing ? "Edit program" : "New program" }]} />
      <div className="page-head">
        <div>
          <h1 className="page-title">{editing ? "Edit program" : "Create meal program"}</h1>
          <p className="page-sub">{draft.name || "Untitled program"} · {pool.length} recipes</p>
        </div>
        <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
          {/* layout switcher */}
          <div className="seg" style={{ display: "inline-flex", gap: 2, background: "var(--gray-100)", borderRadius: 9, padding: 3 }}>
            {[["rail", "panel-left"], ["top", "panel-top"], ["cards", "layout-grid"]].map(([id, ic]) => (
              <button key={id} className="icon-btn" title={`${id} layout`} style={{ width: 30, height: 28, borderRadius: 7, background: layout === id ? "#fff" : "transparent", boxShadow: layout === id ? "0 1px 3px rgba(0,0,0,.12)" : "none", color: layout === id ? "var(--green-700)" : "var(--gray-500)" }} onClick={() => mpbSetLayout(id)}><Icon name={ic} size={15} /></button>
            ))}
          </div>
          <button className="btn ghost" onClick={() => setPage(editing ? "meal-program-detail" : "meal-programs")}>Cancel</button>
        </div>
      </div>

      {/* top / cards steppers render above panel */}
      {layout === "top" && (
        <div className="mpb-top" style={{ marginBottom: 18 }}>
          {MPB_STEPS.map((s, i) => (
            <button key={s.id} className={`mpb-top-step ${step === s.id ? "on" : ""} ${stepDone(s.id) ? "done" : ""}`} onClick={() => setStep(s.id)}>
              <span className="mpb-top-n">{stepDone(s.id) ? <Icon name="check" size={11} stroke={3} /> : i + 1}</span> {s.t}
            </button>
          ))}
        </div>
      )}
      {layout === "cards" && (
        <div className="mpb-cardgrid" style={{ marginBottom: 18 }}>
          {MPB_STEPS.map((s, i) => (
            <button key={s.id} className={`mpb-stepcard ${step === s.id ? "on" : ""} ${stepDone(s.id) ? "done" : ""}`} onClick={() => setStep(s.id)}>
              <span className="mpb-stepcard-n">{stepDone(s.id) ? <Icon name="check" size={12} stroke={3} /> : i + 1}</span>
              <div className="mpb-stepcard-t">{s.t}</div>
              <div style={{ fontSize: 11.5, color: "var(--gray-400)", marginTop: 2 }}>{s.s}</div>
            </button>
          ))}
        </div>
      )}

      <div className={`mpb layout-${layout}`}>
        {layout === "rail" && (
          <div className="mpb-rail">
            {MPB_STEPS.map((s, i) => (
              <button key={s.id} className={`mpb-rail-step ${step === s.id ? "on" : ""} ${stepDone(s.id) ? "done" : ""}`} onClick={() => setStep(s.id)}>
                <span className="mpb-rail-n">{stepDone(s.id) ? <Icon name="check" size={13} stroke={3} /> : i + 1}</span>
                <span style={{ minWidth: 0 }}><span className="mpb-rail-t" style={{ display: "block" }}>{s.t}</span><span className="mpb-rail-s">{s.s}</span></span>
              </button>
            ))}
            <div style={{ marginTop: 8, paddingTop: 10, borderTop: "1px solid var(--gray-200)" }}>
              <MpLoraaBuilderPill step={step} open={loraaOpen} setOpen={setLoraaOpen} flags={flags} />
            </div>
          </div>
        )}

        <div className="mpb-panel">
          {(layout === "top" || layout === "cards") && (
            <div style={{ marginBottom: 16 }}><MpLoraaBuilderPill step={step} open={loraaOpen} setOpen={setLoraaOpen} flags={flags} inline /></div>
          )}
          {Body()}
          <div className="mpb-foot">
            <button className="btn secondary" onClick={goPrev} disabled={stepIdx === 0}><Icon name="arrow-left" size={15} /> Back</button>
            {stepIdx < MPB_STEPS.length - 1 ? (
              <button className="btn primary" onClick={goNext}>Next: {MPB_STEPS[stepIdx + 1].t} <Icon name="arrow-right" size={15} /></button>
            ) : (
              <div style={{ display: "flex", gap: 9 }}>
                <button className="btn secondary" onClick={() => persist("draft", "Draft saved")}><Icon name="save" size={15} /> Save draft</button>
                <button className="btn primary" onClick={() => persist("validating", "Submitted for review")} disabled={!draft.name.trim() || pool.length === 0}><Icon name="send" size={15} /> Submit for review</button>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

/* Collapsed-by-default Loraa assistant for the builder */
function MpLoraaBuilderPill({ step, open, setOpen, flags, inline }) {
  const tips = {
    basics: "Name the program for the outcome and audience. Clinical types unlock condition-aware checks.",
    recipes: "Prefer approved recipes, Loraa will flag any that aren't. Aim for variety to avoid rotation warnings.",
    rules: "Set the daily limits that matter for this population. Conditions pull in your health-tag compliance rules.",
    validate: flags.length ? `I found ${flags.length} thing${flags.length === 1 ? "" : "s"} to look at, ${flags.filter((f) => f.severity === "critical").length} blocking.` : "Everything checks out against your targets and rules.",
    assignments: "Each blocking or high issue becomes a correction task you can route to the right owner.",
    review: "Save a draft anytime. Submitting routes the plan into the review workflow with any fixes attached.",
  };
  if (!open) {
    return <button className="loraa-pill" style={inline ? {} : { width: "100%", justifyContent: "center" }} onClick={() => setOpen(true)}><span className="loraa-logo"><img src="assets/loraa-logo.png" alt="" /></span> Ask Loraa</button>;
  }
  return (
    <div style={{ border: "1px solid #E0DBFB", borderRadius: 14, overflow: "hidden", background: "linear-gradient(180deg,#FBFAFF,#fff)", marginTop: inline ? 0 : 4 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 9, padding: "11px 13px", background: "linear-gradient(120deg, rgba(105,56,239,.08), rgba(91,192,235,.05))" }}>
        <MpLoraaMark size={22} />
        <span style={{ fontWeight: 800, fontSize: 13, color: "#3B1E8E" }}>Loraa</span>
        <button className="icon-btn" style={{ marginLeft: "auto", width: 26, height: 26 }} onClick={() => setOpen(false)}><Icon name="x" size={14} /></button>
      </div>
      <div style={{ padding: "12px 14px", fontSize: 12.5, color: "var(--gray-700)", lineHeight: 1.55 }}>
        {tips[step]}
        <div style={{ marginTop: 9, fontSize: 11, color: "#8478B0", display: "flex", gap: 6, alignItems: "center" }}><Icon name="info" size={11} /> Supportive guidance, you make the final call.</div>
      </div>
    </div>
  );
}

if (typeof window !== "undefined") Object.assign(window, { MealProgramBuilder, mpbLayout, mpbSetLayout, MPB_LAYOUT_KEY });
