// Calculation Engine — Energy / Protein / Fluids cards.
const { useState: useStateCalc, useMemo: useMemoCalc } = React;

const { CITATIONS, ENERGY_METHODS, CALORIC_ADJUSTMENTS, FLUID_METHODS,
        ACTIVITY, proteinDefaultsFor, devineIBW, adjustedBodyWeight,
        toCm, toKg, mifflinFormulaText, harrisFormulaText } = window.RD;
const Seg = window.Seg;

// Helpers
const fmt = n => Number.isFinite(n) ? Math.round(n).toLocaleString() : "—";
const fmt1 = n => Number.isFinite(n) ? n.toFixed(1) : "—";
const fmt2 = n => Number.isFinite(n) ? n.toFixed(2) : "—";

function CitationCard({ citationId, open, onToggle, expandedFirst }) {
  const c = CITATIONS[citationId];
  if (!c) return null;
  return (
    <div className={`citation ${open ? "open" : ""}`}>
      <button type="button" className="cite-btn" onClick={onToggle} aria-expanded={open}>
        <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 8h.01"/><path d="M11 12h1v4h1"/></svg>
        <span>{open ? "Hide source" : "Source"}</span>
        <span className="cite-tag">{c.tag}</span>
      </button>
      {open && (
        <div className="cite-body">
          <div className="cite-full">{c.full}</div>
          {c.note && <div className="cite-note">{c.note}</div>}
        </div>
      )}
    </div>
  );
}

function EditableNumber({ value, computed, onChange, onReset, suffix, width = 64, decimals = 0, ariaLabel }) {
  const isOverridden = value !== null;
  const display = isOverridden ? value : computed;
  const formatted = Number.isFinite(display)
    ? (decimals ? Number(display).toFixed(decimals) : String(Math.round(display)))
    : "";

  const [draft, setDraft] = useStateCalc(formatted);
  const [focused, setFocused] = useStateCalc(false);

  // Keep draft in sync with external value when not actively editing.
  React.useEffect(() => {
    if (!focused) setDraft(formatted);
  }, [formatted, focused]);

  return (
    <span className={`editable ${isOverridden ? "overridden" : ""}`}>
      <input
        className="num-input"
        type="text"
        inputMode="decimal"
        style={{ width }}
        value={draft}
        onFocus={() => setFocused(true)}
        onBlur={() => {
          setFocused(false);
          // Commit final parse on blur — strips trailing dots etc.
          const cleaned = draft.replace(/[^\d.\-]/g, "");
          if (cleaned === "" || cleaned === "-" || cleaned === ".") {
            onChange(null);
            setDraft("");
          } else {
            const n = parseFloat(cleaned);
            if (Number.isFinite(n)) {
              onChange(n);
              // Re-format on blur to canonical decimals.
              setDraft(decimals ? n.toFixed(decimals) : String(Math.round(n)));
            } else {
              onChange(null);
              setDraft("");
            }
          }
        }}
        onChange={e => {
          // Allow free typing: digits, one decimal point, optional leading minus.
          const raw = e.target.value;
          const cleaned = raw.replace(/[^\d.\-]/g, "");
          setDraft(cleaned);
          // Live-commit parsed value when it is a complete number.
          if (cleaned === "" || cleaned === "-" || cleaned.endsWith(".") || cleaned === ".") {
            // Don't commit yet — user is mid-type.
            return;
          }
          const n = parseFloat(cleaned);
          if (Number.isFinite(n)) onChange(n);
        }}
        aria-label={ariaLabel}
      />
      {suffix && <span className="suffix">{suffix}</span>}
      {isOverridden && (
        <button className="reset-pin" type="button" onClick={onReset} title="Reset to calculated">
          <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 4v5h5"/></svg>
        </button>
      )}
    </span>
  );
}

function Calculations({ state, calc, setCalc }) {
  const ageNum = parseFloat(state.age);
  const weightKg = state.weight ? toKg(parseFloat(state.weight), state.weightUnit) : null;
  const heightCm = state.height ? toCm(parseFloat(state.height), state.heightUnit) : null;
  const sex = state.sex;
  const dxId = state.diagnosis?.id;
  const elderly = Number.isFinite(ageNum) && ageNum >= 65;

  const ready = Number.isFinite(ageNum) && Number.isFinite(weightKg) && Number.isFinite(heightCm) && (sex === "F" || sex === "M");

  // ---------- Energy ----------
  const method = ENERGY_METHODS.find(m => m.id === calc.energyMethod) || ENERGY_METHODS[0];
  const computedBMR = ready ? method.fn(weightKg, heightCm, ageNum, sex) : null;
  const bmr = calc.bmrOverride != null ? calc.bmrOverride : computedBMR;

  const activityRow = ACTIVITY.find(a => a.id === state.activity);
  const computedActivity = activityRow?.mult ?? null;
  const activityMult = calc.activityMultOverride != null ? calc.activityMultOverride : computedActivity;

  const stress = calc.stressFactor;
  const computedTDEE = (Number.isFinite(bmr) && Number.isFinite(activityMult)) ? bmr * activityMult * stress : null;
  const tdee = calc.tdeeOverride != null ? calc.tdeeOverride : computedTDEE;

  const caloricAdj = CALORIC_ADJUSTMENTS.find(c => c.id === calc.caloricAdjustment) || CALORIC_ADJUSTMENTS[2];
  const energyNeeds = Number.isFinite(tdee) ? window.RD.applyModifiers("energy", tdee + caloricAdj.value, state) : null;
  // v1c Epic 5.1 — kcal per kg of actual body weight (secondary display)
  const energyPerKg = (Number.isFinite(energyNeeds) && Number.isFinite(weightKg) && weightKg > 0) ? energyNeeds / weightKg : null;

  // ---------- Protein ----------
  // v1d S4/S5: shared resolver — dx defaults → modifiers → RD overrides.
  const dxDefaults = ready && dxId ? proteinDefaultsFor(dxId, ageNum, state.activity) : null;
  const wb = window.RD.resolveProteinWeight({ weightKg, heightCm, sex }, calc, dxDefaults, state);
  const { proteinWeight, ibw, abw } = wb;
  const proteinBasisLabel = wb.basisLabel;
  const basisDefault = window.RD.defaultBasisFor(dxDefaults);
  const basisIsOverride = calc.proteinWeightBasis != null && calc.proteinWeightBasis !== basisDefault;
  const range = dxDefaults ? window.RD.applyModifiers("protein", { low: dxDefaults.low, high: dxDefaults.high, point: dxDefaults.point }, state) : null;
  const computedBasis = range ? (Number.isFinite(range.point) ? range.point : (range.low + range.high) / 2) : null;
  const proteinBasis = calc.proteinBasisOverride != null ? calc.proteinBasisOverride : computedBasis;
  const proteinG = (Number.isFinite(proteinBasis) && Number.isFinite(proteinWeight)) ? proteinBasis * proteinWeight : null;
  const proteinKcal = Number.isFinite(proteinG) ? proteinG * 4 : null;
  const proteinPctKcal = (Number.isFinite(proteinKcal) && Number.isFinite(energyNeeds)) ? (proteinKcal / energyNeeds) * 100 : null;

  // ---------- Fluids ----------
  const fluidMethod = FLUID_METHODS.find(f => f.id === calc.fluidMethod) || FLUID_METHODS[0];
  let computedFluid = null, fluidLow = null, fluidHigh = null;
  if (calc.fluidMethod === "perKcal" && Number.isFinite(energyNeeds)) {
    computedFluid = energyNeeds * 1;
  } else if (calc.fluidMethod === "perKg" && Number.isFinite(weightKg)) {
    fluidLow = weightKg * 30;
    fluidHigh = weightKg * 35;
    computedFluid = (fluidLow + fluidHigh) / 2;
  }
  const fluid = calc.fluidValueOverride != null ? calc.fluidValueOverride : computedFluid;

  // ---------- Citation auto-expand on first use of dx-specific logic ----------
  const [citeOpen, setCiteOpen] = useStateCalc({ energy: false, protein: false, fluid: false });
  const [autoExpandedDx, setAutoExpandedDx] = useStateCalc(null);
  React.useEffect(() => {
    if (dxId && dxId !== autoExpandedDx && dxDefaults) {
      setCiteOpen(s => ({ ...s, protein: true }));
      setAutoExpandedDx(dxId);
    }
  }, [dxId]);

  // Has any manual override?
  const anyOverride = calc.bmrOverride != null || calc.activityMultOverride != null || calc.tdeeOverride != null
                   || calc.proteinBasisOverride != null || calc.fluidValueOverride != null
                   || calc.stressFactor !== 1.0;

  if (!ready) {
    return (
      <section className="zone" aria-labelledby="zone-calc">
        <header className="zone-head">
          <span className="zone-num">02</span>
          <h2 id="zone-calc" className="zone-title">Calculation Engine</h2>
          <span className="zone-sub">Energy, protein, fluids — transparent &amp; cited</span>
        </header>
        <div className="zone-body">
          <div className="calc-empty">
            <span className="calc-empty-glyph">∿</span>
            <div>
              <div className="calc-empty-title">Calculations are waiting on the basics.</div>
              <div className="calc-empty-sub">
                Add age, sex, height, and weight above and the engine will run live.
              </div>
            </div>
          </div>
        </div>
      </section>
    );
  }

  // ---------- Render ----------
  return (
    <section className="zone" aria-labelledby="zone-calc">
      <header className="zone-head">
        <span className="zone-num">02</span>
        <h2 id="zone-calc" className="zone-title">Calculation Engine</h2>
        <span className="zone-sub">Energy, protein, fluids — transparent &amp; cited</span>
      </header>
      <div className="zone-body calc-stack">

        {/* ENERGY */}
        <article className="calc-pane">
          <header className="pane-head">
            <div className="pane-title-wrap">
              <span className="pane-title">Energy needs</span>
              {method.recommended && <span className="badge-rec">Recommended</span>}
            </div>
            <div className="pane-controls">
              <label className="mini-label">Method</label>
              <select className="input small" value={calc.energyMethod} onChange={e => setCalc({ energyMethod: e.target.value, bmrOverride: null })}>
                {ENERGY_METHODS.map(m => <option key={m.id} value={m.id}>{m.label}</option>)}
              </select>
            </div>
          </header>

          <div className="transparency">
            <div className="t-row">
              <span className="t-label">Formula</span>
              <code className="t-mono">BMR = {method.formula(sex)}</code>
            </div>
            <div className="t-row">
              <span className="t-label">Plug in</span>
              <code className="t-mono">
                {sex === "M"
                  ? `BMR = (10 × ${fmt1(weightKg)}) + (6.25 × ${fmt1(heightCm)}) − (5 × ${ageNum}) + 5`
                  : calc.energyMethod === "mifflin"
                    ? `BMR = (10 × ${fmt1(weightKg)}) + (6.25 × ${fmt1(heightCm)}) − (5 × ${ageNum}) − 161`
                    : `BMR = ${fmt1(method.fn(weightKg, heightCm, ageNum, sex))}`}
              </code>
            </div>
            {calc.energyMethod === "mifflin" && (
              <div className="t-row">
                <span className="t-label">Steps</span>
                <code className="t-mono">
                  = {fmt1(10*weightKg)} + {fmt1(6.25*heightCm)} − {fmt(5*ageNum)} {sex === "M" ? "+ 5" : "− 161"}
                </code>
              </div>
            )}
            <div className="t-row result">
              <span className="t-label">BMR</span>
              <span className="t-result">
                <EditableNumber
                  value={calc.bmrOverride}
                  computed={computedBMR}
                  onChange={v => setCalc({ bmrOverride: v })}
                  onReset={() => setCalc({ bmrOverride: null })}
                  suffix="kcal/day"
                  width={68}
                  ariaLabel="BMR override"
                />
              </span>
            </div>
          </div>

          <div className="multipliers">
            <div className="mult-row">
              <span className="m-label">Activity multiplier</span>
              <EditableNumber
                value={calc.activityMultOverride}
                computed={computedActivity}
                decimals={3}
                onChange={v => setCalc({ activityMultOverride: v })}
                onReset={() => setCalc({ activityMultOverride: null })}
                suffix={activityRow ? `· ${activityRow.label}` : ""}
                width={62}
                ariaLabel="Activity multiplier"
              />
            </div>
            <div className="mult-row">
              <span className="m-label">Stress factor</span>
              <EditableNumber
                value={calc.stressFactor !== 1.0 ? calc.stressFactor : null}
                computed={1.0}
                decimals={2}
                onChange={v => setCalc({ stressFactor: v == null ? 1.0 : v })}
                onReset={() => setCalc({ stressFactor: 1.0 })}
                suffix="× (1.0 = none)"
                width={56}
                ariaLabel="Stress factor"
              />
            </div>
            <div className="mult-row tdee">
              <span className="m-label">TDEE = BMR × activity × stress</span>
              <span className="tdee-val">
                <span className="num-mono">{fmt(tdee)}</span>
                <span className="num-suffix">kcal/day</span>
              </span>
            </div>
          </div>

          <div className="adjustment-row">
            <label className="mini-label">Caloric adjustment</label>
            <select className="input" style={{ flex: 1 }}
                    value={calc.caloricAdjustment}
                    onChange={e => setCalc({ caloricAdjustment: e.target.value })}>
              {CALORIC_ADJUSTMENTS.map(c => <option key={c.id} value={c.id}>{c.label}</option>)}
            </select>
          </div>

          <div className="result-bar">
            <div className="result-label">Estimated Energy Needs</div>
            <div className="result-value">
              <span className="big-num">{fmt(energyNeeds)}</span>
              <span className="big-unit">kcal / day</span>
              {Number.isFinite(energyPerKg) && (
                <span className="result-sub">{fmt1(energyPerKg)} kcal/kg/day · actual body weight (Mifflin uses actual weight by design)</span>
              )}
              {caloricAdj.value !== 0 && (
                <span className="result-note">
                  TDEE {fmt(tdee)} {caloricAdj.value > 0 ? "+" : "−"} {Math.abs(caloricAdj.value)} = {fmt(energyNeeds)}
                </span>
              )}
            </div>
          </div>

          <CitationCard
            citationId={method.citation}
            open={citeOpen.energy}
            onToggle={() => setCiteOpen(s => ({ ...s, energy: !s.energy }))}
          />
        </article>

        {/* PROTEIN */}
        <article className="calc-pane">
          <header className="pane-head">
            <div className="pane-title-wrap">
              <span className="pane-title">Protein needs</span>
              {dxDefaults?.geriAdjusted && (
                <span className="badge-rec geri" title="Floor raised to ≥1.0 g/kg per ESPEN Geriatrics.">Geriatric considerations applied</span>
              )}
            </div>
            {wb.canDerive && (
              <div className="pane-controls">
                <label className="mini-label">Weight basis{basisIsOverride ? " · changed" : ""}</label>
                <Seg
                  ariaLabel="Protein weight basis"
                  value={wb.basis}
                  onChange={v => setCalc({ proteinWeightBasis: v === basisDefault ? null : v })}
                  options={[
                    { value: "current",  label: `Current ${fmt1(weightKg)} kg` },
                    { value: "ideal",    label: `Ideal ${fmt1(ibw)} kg` },
                    { value: "adjusted", label: `Adjusted ${fmt1(abw)} kg` },
                  ]}
                />
              </div>
            )}
          </header>

          {!dxId ? (
            <div className="pane-empty">
              <span>Select a primary diagnosis above — the protein basis depends on it.</span>
            </div>
          ) : (
            <>
              <div className="transparency">
                <div className="t-row">
                  <span className="t-label">Range</span>
                  <code className="t-mono">{fmt2(range.low)}–{fmt2(range.high)} g/kg ({proteinBasisLabel} body weight)</code>
                </div>
                <div className="t-row">
                  <span className="t-label">Plug in</span>
                  <code className="t-mono">
                    Protein = {fmt2(proteinBasis)} × {fmt1(proteinWeight)} kg
                    {proteinBasisLabel === "ideal" && Number.isFinite(ibw) && (
                      <span style={{ color: "var(--ink-4)", marginLeft: 8 }}>
                        · IBW (Devine) = {fmt1(ibw)} kg
                      </span>
                    )}
                    {proteinBasisLabel === "adjusted" && Number.isFinite(ibw) && (
                      <span style={{ color: "var(--ink-4)", marginLeft: 8 }}>
                        · IBW {fmt1(ibw)} + 0.25×({fmt1(weightKg)}−{fmt1(ibw)}) = ABW {fmt1(abw)}
                      </span>
                    )}
                  </code>
                </div>
                <div className="t-row result">
                  <span className="t-label">Total</span>
                  <span className="t-result">
                    <span className="num-mono big">{fmt(proteinG)}</span>
                    <span className="num-suffix">g/day</span>
                    {Number.isFinite(proteinPctKcal) && (
                      <span className="num-aux">≈ {fmt(proteinKcal)} kcal · {proteinPctKcal.toFixed(0)}% of energy</span>
                    )}
                  </span>
                </div>
              </div>

              <div className="multipliers">
                <div className="mult-row">
                  <span className="m-label">Basis</span>
                  <EditableNumber
                    value={calc.proteinBasisOverride}
                    computed={computedBasis}
                    decimals={2}
                    onChange={v => setCalc({ proteinBasisOverride: v })}
                    onReset={() => setCalc({ proteinBasisOverride: null })}
                    suffix={`g/kg · range ${fmt2(range.low)}–${fmt2(range.high)}`}
                    width={56}
                    ariaLabel="Protein basis"
                  />
                </div>
              </div>

              <div className="rationale">
                <span className="r-glyph">i</span>
                <span>{dxDefaults.rationale}</span>
              </div>

              <CitationCard
                citationId={dxDefaults.citation}
                open={citeOpen.protein}
                onToggle={() => setCiteOpen(s => ({ ...s, protein: !s.protein }))}
              />
            </>
          )}
        </article>

        {/* FLUIDS */}
        <article className="calc-pane">
          <header className="pane-head">
            <div className="pane-title-wrap">
              <span className="pane-title">Fluid needs</span>
            </div>
            <div className="pane-controls">
              <label className="mini-label">Method</label>
              <Seg
                ariaLabel="Fluid method"
                value={calc.fluidMethod}
                onChange={v => setCalc({ fluidMethod: v, fluidValueOverride: null })}
                options={[
                  { value: "perKcal", label: "1 mL · kcal⁻¹" },
                  { value: "perKg",   label: "30–35 mL/kg" },
                ]}
              />
            </div>
          </header>

          <div className="transparency">
            <div className="t-row">
              <span className="t-label">Method</span>
              <code className="t-mono">{fluidMethod.label}</code>
            </div>
            {calc.fluidMethod === "perKcal" ? (
              <div className="t-row">
                <span className="t-label">Plug in</span>
                <code className="t-mono">{fmt(energyNeeds)} kcal × 1 mL/kcal = {fmt(computedFluid)} mL</code>
              </div>
            ) : (
              <div className="t-row">
                <span className="t-label">Plug in</span>
                <code className="t-mono">{fmt1(weightKg)} kg × 30–35 mL = {fmt(fluidLow)}–{fmt(fluidHigh)} mL</code>
              </div>
            )}
            <div className="t-row result">
              <span className="t-label">Total</span>
              <span className="t-result">
                <EditableNumber
                  value={calc.fluidValueOverride}
                  computed={computedFluid}
                  onChange={v => setCalc({ fluidValueOverride: v })}
                  onReset={() => setCalc({ fluidValueOverride: null })}
                  suffix="mL/day"
                  width={76}
                  ariaLabel="Fluid total"
                />
              </span>
            </div>
          </div>

          {dxId === "ckd" && (
            <div className="ckd-note">
              <span className="warn-glyph">!</span>
              Fluid restrictions may apply per nephrology — verify with the care team before finalizing.
            </div>
          )}

          <CitationCard
            citationId={fluidMethod.citation}
            open={citeOpen.fluid}
            onToggle={() => setCiteOpen(s => ({ ...s, fluid: !s.fluid }))}
          />
        </article>

        {/* Adjustment notes — visible whenever any override is in play */}
        {anyOverride && (
          <div className="adjustment-notes">
            <div className="an-head">
              <span className="an-glyph">✎</span>
              <div>
                <div className="an-title">Clinical notes for adjustment</div>
                <div className="an-sub">Document your rationale — these notes flow into the assessment summary.</div>
              </div>
            </div>
            <textarea
              className="input"
              rows={2}
              placeholder="e.g. Bumped protein basis to 1.5 g/kg due to recent infection and elevated CRP."
              value={calc.adjustmentNotes}
              onChange={e => setCalc({ adjustmentNotes: e.target.value })}
            />
          </div>
        )}

      </div>
    </section>
  );
}

window.Calculations = Calculations;
