// VELOUR dashboard — Wellness pillar page. A state you TEND: measured dials, trends, no checkboxes.
const { Card, Badge } = window.VelourDesignSystem_380ed4;
const FRESH = !!window.VELOUR_FRESH;

const STORAGE_KEY = FRESH ? "velour_fresh_wellness_log" : "velour_wellness_log";

// A broad set of common supplements to choose from. Anything not here can be
// added as a custom entry, so the list stays a starting point — not a limit.
const SUPP_PRESETS = [
  "Vitamin D", "Vitamin C", "Vitamin B12", "Multivitamin",
  "Magnesium", "Omega-3", "Probiotic", "Zinc",
  "Iron", "Calcium", "Creatine", "Collagen",
  "Ashwagandha", "Melatonin", "Turmeric", "Electrolytes",
];

// ---- date helpers -----------------------------------------------------------
function wlToISODate(d) { return window.velourDateISO(d); }
function wlTodayISO() {
  const d = new Date();
  const off = Number(window.VELOUR_DAY_OFFSET) || 0;
  if (off) d.setDate(d.getDate() + off);
  return wlToISODate(d);
}
function wlFormatDateLabel(iso) {
  const today = wlTodayISO();
  const d = new Date(iso + "T00:00:00");
  // Yesterday derives from the same "today" so the labels can't disagree with it.
  if (iso === today) return "Today";
  if (iso === wlAddDays(today, -1)) return "Yesterday";
  return d.toLocaleDateString(undefined, { weekday: "short", month: "short", day: "numeric" });
}
function wlAddDays(iso, n) {
  const d = new Date(iso + "T00:00:00");
  d.setDate(d.getDate() + n);
  return wlToISODate(d);
}

// Stored entries can miss fields the dashboard reads (hand-edited or older
// storage); default them so metric math never yields NaN and formatting never throws.
function normalizeEntry(e) {
  const num = (v) => (Number.isFinite(+v) ? +v : 0);
  return {
    sleepH: num(e.sleepH), sleepM: num(e.sleepM), hydration: num(e.hydration),
    steps: num(e.steps), daylight: num(e.daylight), stillness: num(e.stillness),
    // Movement, in minutes (migration 017). Defaulted like the rest: every day
    // written before it existed genuinely holds no movement, so 0 is the truth
    // rather than a gap.
    exercise: num(e.exercise),
    supps: Array.isArray(e.supps) ? e.supps : [],
    // Preserved rather than defaulted — see the note above wlStampManual.
    ...(e.sources && typeof e.sources === "object" ? { sources: e.sources } : {}),
  };
}

// ---- provenance -------------------------------------------------------------
//
// Where each number came from. Absent means manual: every entry written before
// this existed was typed by a member, because nothing else could write one.
//
// It exists BEFORE any import does, because withdrawing consent to a health
// source does not mean "stop importing" — it means "delete what came from there",
// and a step count from Apple Health is indistinguishable from a typed one
// without this. That is the same lesson as the photo purge endpoint: an off
// switch that cannot actually erase is a promise the product must not make.
//
// Only fields the member actually CHANGED are stamped manual, so a value that
// arrived from a source keeps its provenance when the member edits the day around
// it. Values live in a small allowlist: "manual", or a source id when import lands.
const WL_METRICS = ["sleepH", "sleepM", "hydration", "steps", "daylight", "stillness", "exercise", "supps"];
function wlStampManual(prev, next) {
  const sources = Object.assign({}, (prev && prev.sources) || {});
  WL_METRICS.forEach(function (k) {
    var before = prev ? JSON.stringify(prev[k]) : undefined;
    if (before !== JSON.stringify(next[k])) sources[k] = "manual";
  });
  return Object.assign({}, next, { sources: sources });
}

function loadWellnessLog() {
  try {
    const saved = localStorage.getItem(STORAGE_KEY);
    if (saved) {
      const log = JSON.parse(saved);
      for (const day of Object.keys(log)) log[day] = normalizeEntry(log[day]);
      return log;
    }
  } catch (e) {}
  return {}; // { "2026-06-16": { sleepH, sleepM, hydration, steps, daylight, stillness, exercise, supps } }
}

function saveWellnessLog(log) {
  try { localStorage.setItem(STORAGE_KEY, JSON.stringify(log)); } catch (e) {}
}

// ---- Manual entry form shown on fresh / no-data state ----------------------
function WellnessOnboard({ onSave, selectedDate, onDateChange, existingData }) {
  const [step, setStep] = React.useState(existingData ? 1 : 0); // 0=intro, 1=form
  const today = wlTodayISO();
  const [form, setForm] = React.useState(existingData || {
    sleepH: 7, sleepM: 0,
    hydration: 1.0,
    steps: 5000,
    daylight: 20,
    stillness: 10,
    // Movement starts at 0, unlike every other default here, and that is
    // deliberate: the others are a plausible ordinary day, and an ordinary day
    // has no exercise in it. A non-zero default would put minutes a member never
    // did into their record the moment they opened the form.
    exercise: 0,
    supps: [],
  });

  // If the selected date or its existing data changes, refresh the form to match.
  React.useEffect(() => {
    setForm(existingData || {
      sleepH: 7, sleepM: 0, hydration: 1.0, steps: 5000, daylight: 20, stillness: 10, exercise: 0, supps: [],
    });
    setStep(existingData ? 1 : 0);
  }, [selectedDate]);

  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));
  const [suppInput, setSuppInput] = React.useState("");

  const addSupp = (name) => {
    const v = (name || "").trim();
    if (!v) return;
    setForm((f) => (f.supps.includes(v) ? f : { ...f, supps: [...f.supps, v] }));
    setSuppInput("");
  };
  const removeSupp = (name) => setForm((f) => ({ ...f, supps: f.supps.filter((x) => x !== name) }));

  const handleSave = () => {
    onSave(selectedDate, form);
  };

  const DateBar = () => (
    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", flexWrap: "wrap", gap: 14, marginBottom: 24, background: "var(--surface-card)", border: "var(--border-width) solid var(--border)", borderRadius: 14, padding: "12px 18px" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <button onClick={() => onDateChange(wlAddDays(selectedDate, -1))} aria-label="Previous day" style={{ width: 32, height: 32, borderRadius: "50%", border: "var(--border-width) solid var(--border-strong)", background: "var(--surface-card)", color: "var(--text-secondary)", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}>
          <i className="ph ph-caret-left" style={{ fontSize: 13 }}></i>
        </button>
        <i className="ph ph-calendar-blank" style={{ fontSize: 16, color: "var(--teal)" }}></i>
        <span style={{ fontFamily: "var(--font-serif)", fontSize: 17, color: "var(--text-primary)" }}>{wlFormatDateLabel(selectedDate)}</span>
        <input type="date" value={selectedDate} max={today} onChange={(e) => e.target.value && onDateChange(e.target.value)} style={{ border: "var(--border-width) solid var(--border)", borderRadius: 8, padding: "5px 9px", fontSize: 12.5, color: "var(--text-tertiary)", background: "var(--surface-card)", fontFamily: "var(--font-sans)" }} />
        <button onClick={() => onDateChange(wlAddDays(selectedDate, 1))} disabled={selectedDate >= today} aria-label="Next day" style={{ width: 32, height: 32, borderRadius: "50%", border: "var(--border-width) solid var(--border-strong)", background: "var(--surface-card)", color: selectedDate >= today ? "var(--border-strong)" : "var(--text-secondary)", cursor: selectedDate >= today ? "default" : "pointer", display: "flex", alignItems: "center", justifyContent: "center", opacity: selectedDate >= today ? 0.5 : 1 }}>
          <i className="ph ph-caret-right" style={{ fontSize: 13 }}></i>
        </button>
        {selectedDate !== today && (
          <button onClick={() => onDateChange(today)} style={{ fontSize: 12.5, color: "var(--teal-text)", background: "var(--teal-fill)", border: "none", borderRadius: 999, padding: "6px 12px", cursor: "pointer", fontFamily: "var(--font-sans)", fontWeight: 500 }}>Jump to today</button>
        )}
      </div>
      {existingData && <span style={{ fontSize: 12.5, color: "var(--teal-text)", display: "inline-flex", alignItems: "center", gap: 6 }}><i className="ph ph-check-circle" style={{ fontSize: 14 }}></i>Already logged — editing</span>}
    </div>
  );

  if (step === 0) {
    return (
      <main style={{ maxWidth: 1240, margin: "0 auto", padding: "36px 32px 64px", fontFamily: "var(--font-sans)" }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 9, fontSize: 11.5, letterSpacing: "0.16em", textTransform: "uppercase", fontWeight: 500, color: "var(--teal-text)", background: "var(--teal-fill)", borderRadius: 999, padding: "6px 14px" }}><i className="ph ph-heart" style={{ fontSize: 14 }}></i>Wellness</span>
        <h1 style={{ fontFamily: "var(--font-serif)", fontWeight: 500, fontSize: 40, lineHeight: 1.08, letterSpacing: "-0.02em", color: "var(--text-primary)", margin: "18px 0 0" }}>Your body, in rhythm.</h1>
        <p style={{ fontSize: 16, lineHeight: 1.65, color: "var(--text-secondary)", margin: "14px 0 28px", maxWidth: 560 }}>Wellness is a state, not a to-do list. Log a day and VELOUR begins reflecting the broad strokes back — gently, with no goals to chase.</p>
        <DateBar />
        {/* NO "CONNECT HEALTH DATA" ON THIS SURFACE, AND THE COPY NO LONGER OFFERS IT.
            The button here never had an onClick — it was a picture of a door. And
            it could not have had one: Apple Health has no web equivalent, so a
            browser can never read it. The import belongs on the phone, where
            HealthKit exists; the web's job is to display whatever the app has
            already synced through /api/wellness. The equivalent button on
            src/ui_kits/app/WellnessScreen.jsx is deliberately kept, because that
            is the surface where it can one day be true. Removed 4 Sep 2026. */}
        <Card padding={0} style={{ overflow: "hidden" }}>
          <div style={{ background: "var(--teal-fill)", padding: "48px 40px", textAlign: "center" }}>
            <div style={{ width: 56, height: 56, borderRadius: 15, background: "var(--teal)", display: "inline-flex", alignItems: "center", justifyContent: "center", marginBottom: 20 }}><i className="ph ph-waveform" style={{ fontSize: 26, color: "#fff" }}></i></div>
            <div style={{ fontFamily: "var(--font-serif)", fontSize: 26, color: "var(--teal-text)", letterSpacing: "-0.01em" }}>Your rhythm will appear here.</div>
            <p style={{ fontSize: 15, lineHeight: 1.6, color: "var(--teal-text)", opacity: 0.85, maxWidth: 420, margin: "12px auto 0" }}>Log {window.velourDayPhrase(wlFormatDateLabel(selectedDate))} and your sleep, movement, and daylight start to fill in.</p>
            <div style={{ display: "flex", gap: 12, justifyContent: "center", marginTop: 24, flexWrap: "wrap" }}>
              <button onClick={() => setStep(1)} style={{ display: "inline-flex", alignItems: "center", gap: 8, background: "var(--ink)", color: "var(--parchment)", border: "none", borderRadius: 999, padding: "12px 22px", fontFamily: "var(--font-sans)", fontSize: 14.5, fontWeight: 500, cursor: "pointer" }}><i className="ph ph-pencil-simple" style={{ fontSize: 16 }}></i>Log {window.velourDayPhrase(wlFormatDateLabel(selectedDate))} manually</button>
            </div>
          </div>
        </Card>
      </main>
    );
  }

  // ---- Manual entry form ----
  const fields = [
    {
      id: "sleep", icon: "moon", label: "Sleep", color: "var(--teal)",
      body: (
        <div style={{ display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap" }}>
          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            <label style={{ fontSize: 12, color: "var(--text-tertiary)", letterSpacing: "0.06em" }}>HOURS</label>
            <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
              <StepBtn icon="minus" onClick={() => set("sleepH", Math.max(0, form.sleepH - 1))} />
              <span style={{ fontFamily: "var(--font-serif)", fontSize: 26, minWidth: 36, textAlign: "center" }}>{form.sleepH}</span>
              <StepBtn icon="plus" onClick={() => set("sleepH", Math.min(12, form.sleepH + 1))} />
            </div>
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            <label style={{ fontSize: 12, color: "var(--text-tertiary)", letterSpacing: "0.06em" }}>MINUTES</label>
            <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
              <StepBtn icon="minus" onClick={() => set("sleepM", form.sleepM === 0 ? 45 : form.sleepM - 15)} />
              <span style={{ fontFamily: "var(--font-serif)", fontSize: 26, minWidth: 36, textAlign: "center" }}>{String(form.sleepM).padStart(2, "0")}</span>
              <StepBtn icon="plus" onClick={() => set("sleepM", form.sleepM === 45 ? 0 : form.sleepM + 15)} />
            </div>
          </div>
          <span style={{ fontSize: 15, color: "var(--text-tertiary)", alignSelf: "flex-end", paddingBottom: 4 }}>= {form.sleepH}h {String(form.sleepM).padStart(2, "0")}m last night</span>
        </div>
      ),
    },
    {
      id: "hydration", icon: "drop", label: "Hydration", color: "var(--teal)",
      body: (
        <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
          <StepBtn icon="minus" onClick={() => set("hydration", Math.max(0, +(form.hydration - 0.25).toFixed(2)))} />
          <span style={{ fontFamily: "var(--font-serif)", fontSize: 26, minWidth: 60, textAlign: "center" }}>{window.velourLitres(form.hydration)} L</span>
          <StepBtn icon="plus" onClick={() => set("hydration", +(form.hydration + 0.25).toFixed(2))} />
          <span style={{ fontSize: 13, color: "var(--text-tertiary)", marginLeft: 6 }}>≈ {Math.round(form.hydration / 0.24)} glasses</span>
        </div>
      ),
    },
    // THIS FIELD WAS CALLED "MOVEMENT" AND IS NOW CALLED "STEPS". The rename is
    // not cosmetic: movement now means minutes of effort, and steps cannot
    // measure that — an hour of swimming, a spin class and a heavy lift are all
    // roughly zero steps. Two tiles both called Movement would have been the
    // ambiguity that made the closet count disagree with the closet grid.
    // "Steps" is also simply what this number is; the tile already said so.
    {
      id: "steps", icon: "footprints", label: "Steps", color: "var(--teal)",
      body: (
        <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
          <StepBtn icon="minus" onClick={() => set("steps", Math.max(0, form.steps - 500))} />
          <span style={{ fontFamily: "var(--font-serif)", fontSize: 26, minWidth: 100, textAlign: "center" }}>{form.steps.toLocaleString()} steps</span>
          <StepBtn icon="plus" onClick={() => set("steps", form.steps + 500)} />
        </div>
      ),
    },
    // MOVEMENT — minutes of effort, and typeable HERE as well as importable on
    // the phone. Not everyone owns a watch, and a field one surface can fill and
    // the other cannot is how this codebase drifts. Apple Health can supply the
    // same number; nothing about this field assumes it did.
    {
      id: "exercise", icon: "person-simple-run", label: "Movement", color: "var(--teal)",
      body: (
        <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
          <StepBtn icon="minus" onClick={() => set("exercise", Math.max(0, form.exercise - 5))} />
          <span style={{ fontFamily: "var(--font-serif)", fontSize: 26, minWidth: 90, textAlign: "center" }}>{form.exercise} min</span>
          <StepBtn icon="plus" onClick={() => set("exercise", form.exercise + 5)} />
          <span style={{ fontSize: 13, color: "var(--text-tertiary)", marginLeft: 6 }}>at effort — a swim, a class, a lift</span>
        </div>
      ),
    },
    {
      id: "daylight", icon: "sun-horizon", label: "Daylight", color: "var(--teal)",
      body: (
        <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
          <StepBtn icon="minus" onClick={() => set("daylight", Math.max(0, form.daylight - 5))} />
          <span style={{ fontFamily: "var(--font-serif)", fontSize: 26, minWidth: 90, textAlign: "center" }}>{form.daylight} min</span>
          <StepBtn icon="plus" onClick={() => set("daylight", form.daylight + 5)} />
          <span style={{ fontSize: 13, color: "var(--text-tertiary)", marginLeft: 6 }}>outdoors today</span>
        </div>
      ),
    },
    {
      id: "stillness", icon: "wind", label: "Stillness", color: "var(--teal)",
      body: (
        <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
          <StepBtn icon="minus" onClick={() => set("stillness", Math.max(0, form.stillness - 1))} />
          <span style={{ fontFamily: "var(--font-serif)", fontSize: 26, minWidth: 80, textAlign: "center" }}>{form.stillness} min</span>
          <StepBtn icon="plus" onClick={() => set("stillness", form.stillness + 1)} />
          <span style={{ fontSize: 13, color: "var(--text-tertiary)", marginLeft: 6 }}>breathwork / meditation</span>
        </div>
      ),
    },
    {
      id: "supps", icon: "pill", label: "Supplements", color: "var(--teal)",
      body: (
        <div>
          {/* Your selection — tap × to remove */}
          {form.supps.length > 0 && (
            <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginBottom: 14 }}>
              {form.supps.map((s) => (
                <span key={s} style={{ display: "inline-flex", alignItems: "center", gap: 8, padding: "8px 10px 8px 16px", borderRadius: 999, background: "var(--teal)", color: "#fff", fontFamily: "var(--font-sans)", fontSize: 13.5, fontWeight: 500 }}>
                  {s}
                  <button onClick={() => removeSupp(s)} aria-label={`Remove ${s}`} style={{ display: "flex", border: "none", background: "rgba(255,255,255,0.25)", borderRadius: "50%", width: 18, height: 18, alignItems: "center", justifyContent: "center", cursor: "pointer", color: "#fff", padding: 0 }}>
                    <i className="ph ph-x" style={{ fontSize: 11 }}></i>
                  </button>
                </span>
              ))}
            </div>
          )}

          {/* Custom entry — add anything not in the list */}
          <div style={{ display: "flex", gap: 8, marginBottom: 16 }}>
            <input
              value={suppInput}
              onChange={(e) => setSuppInput(e.target.value)}
              onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); addSupp(suppInput); } }}
              placeholder="Add your own supplement…"
              style={{ flex: 1, padding: "10px 14px", borderRadius: 10, border: "var(--border-width) solid var(--border)", background: "var(--surface-card)", fontFamily: "var(--font-sans)", fontSize: 14, color: "var(--text-primary)", outline: "none" }}
            />
            <button onClick={() => addSupp(suppInput)} style={{ padding: "0 18px", borderRadius: 10, border: "none", background: "var(--teal)", color: "#fff", fontFamily: "var(--font-sans)", fontSize: 14, fontWeight: 500, cursor: "pointer", whiteSpace: "nowrap" }}>Add</button>
          </div>

          {/* Common presets — quick-add chips */}
          {SUPP_PRESETS.some((s) => !form.supps.includes(s)) && (
            <div>
              <div style={{ fontSize: 12, color: "var(--text-tertiary)", marginBottom: 10 }}>Choose from common supplements</div>
              <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
                {SUPP_PRESETS.filter((s) => !form.supps.includes(s)).map((s) => (
                  <button key={s} onClick={() => addSupp(s)} style={{ display: "inline-flex", alignItems: "center", gap: 6, padding: "8px 14px", borderRadius: 999, border: "var(--border-width) dashed var(--teal)", background: "transparent", cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 13.5, fontWeight: 500, color: "var(--teal-text)" }}>
                    <i className="ph ph-plus" style={{ fontSize: 11 }}></i>{s}
                  </button>
                ))}
              </div>
            </div>
          )}
        </div>
      ),
    },
  ];

  return (
    <main style={{ maxWidth: 860, margin: "0 auto", padding: "36px 32px 64px", fontFamily: "var(--font-sans)" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 14, marginBottom: 24 }}>
        <button onClick={() => setStep(0)} style={{ display: "inline-flex", alignItems: "center", gap: 8, background: "none", border: "none", cursor: "pointer", fontSize: 13.5, color: "var(--text-tertiary)", padding: 0, fontFamily: "var(--font-sans)" }}>
          <i className="ph ph-arrow-left" style={{ fontSize: 15 }}></i> Back
        </button>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 9, fontSize: 11.5, letterSpacing: "0.16em", textTransform: "uppercase", fontWeight: 500, color: "var(--teal-text)", background: "var(--teal-fill)", borderRadius: 999, padding: "6px 14px" }}><i className="ph ph-heart" style={{ fontSize: 14 }}></i>Logging wellness</span>
      </div>
      <h1 style={{ fontFamily: "var(--font-serif)", fontWeight: 500, fontSize: 36, lineHeight: 1.1, letterSpacing: "-0.02em", color: "var(--text-primary)", margin: "0 0 8px" }}>How did your body feel {(() => { const d = window.velourDayPhrase(wlFormatDateLabel(selectedDate)); return /^(today|yesterday)$/.test(d) ? d : `on ${d}`; })()}?</h1>
      <p style={{ fontSize: 15, color: "var(--text-secondary)", margin: "0 0 20px", lineHeight: 1.6 }}>Log what you remember — VELOUR will find the pattern. Switch days to backfill earlier in the month.</p>

      <DateBar />

      <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
        {fields.map((f) => (
          <Card key={f.id} padding={24}>
            <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 18 }}>
              <span style={{ width: 36, height: 36, borderRadius: 10, background: "var(--teal-fill)", display: "inline-flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
                <i className={`ph ph-${f.icon}`} style={{ fontSize: 18, color: "var(--teal)" }}></i>
              </span>
              <span style={{ fontSize: 15, fontWeight: 500, color: "var(--text-primary)" }}>{f.label}</span>
            </div>
            {f.body}
          </Card>
        ))}
      </div>

      <div style={{ marginTop: 28, display: "flex", gap: 12 }}>
        <button onClick={handleSave} style={{ display: "inline-flex", alignItems: "center", gap: 8, background: "var(--ink)", color: "var(--parchment)", border: "none", borderRadius: 999, padding: "14px 28px", fontFamily: "var(--font-sans)", fontSize: 15, fontWeight: 500, cursor: "pointer", boxShadow: "0 6px 20px rgba(44,44,42,0.22)" }}>
          <i className="ph ph-check" style={{ fontSize: 16 }}></i>Save {window.velourDayPhrase(wlFormatDateLabel(selectedDate))}'s wellness
        </button>
        <button onClick={() => setStep(0)} style={{ background: "transparent", color: "var(--text-secondary)", border: "var(--border-width) solid var(--border-strong)", borderRadius: 999, padding: "14px 22px", fontFamily: "var(--font-sans)", fontSize: 15, cursor: "pointer" }}>Cancel</button>
      </div>
    </main>
  );
}

function StepBtn({ icon, onClick }) {
  return (
    <button onClick={onClick} style={{ width: 32, height: 32, borderRadius: "50%", border: "var(--border-width) solid var(--border-strong)", background: "var(--surface-card)", color: "var(--text-secondary)", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0, fontFamily: "var(--font-sans)" }}>
      <i className={`ph ph-${icon}`} style={{ fontSize: 14 }}></i>
    </button>
  );
}

// ---- WlRing progress indicator ------------------------------------------------
function WlRing({ pct, size = 60, stroke = 6, children }) {
  const safePct = Number.isFinite(pct) ? Math.min(100, Math.max(0, pct)) : 0;
  const R = (size - stroke) / 2, C = 2 * Math.PI * R, off = C * (1 - safePct / 100);
  return (
    <div style={{ position: "relative", width: size, height: size, flexShrink: 0 }}>
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ transform: "rotate(-90deg)" }}>
        <circle cx={size / 2} cy={size / 2} r={R} fill="none" stroke="var(--border)" strokeWidth={stroke} />
        <circle cx={size / 2} cy={size / 2} r={R} fill="none" stroke="var(--teal)" strokeWidth={stroke} strokeLinecap="round" strokeDasharray={C} strokeDashoffset={off} />
      </svg>
      <div style={{ position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center" }}>{children}</div>
    </div>
  );
}

// Provenance, in the small text migration 011 was built to make possible. Absent
// means typed, which is what every entry written before the import existed was —
// so this stays silent rather than labelling six of seven tiles "you typed this".
function WlSourceNote({ source }) {
  if (source !== "apple-health") return null;
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 11.5, color: "var(--text-tertiary)" }}>
      <i className="ph ph-heartbeat" style={{ fontSize: 12, color: "var(--teal)" }}></i>from Apple Health
    </span>
  );
}

// `m.quantity` draws the tile WITHOUT a ring, a percentage or a trend badge.
//
// THAT IS THE WHOLE POINT OF THE VARIANT, so do not "finish" it later by giving
// Movement a goal. A ring is a target you either close or fail, which is Apple
// Fitness's framing and precisely what this product is defined against — the
// lede on this page says wellness is "a state, not a to-do list… with no goals to
// chase". Import Apple's numbers; never import Apple's framing. The other tiles
// keep their rings because they had them before this rule was written down, and
// changing them is a separate decision from adding this one.
function MetricCard({ m }) {
  return (
    <Card padding={20} style={{ display: "flex", alignItems: "center", gap: 16 }}>
      {m.quantity ? (
        <span style={{ width: 60, height: 60, borderRadius: 16, background: "var(--teal-fill)", display: "inline-flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
          <i className={`ph ph-${m.icon}`} style={{ fontSize: 24, color: "var(--teal)" }}></i>
        </span>
      ) : (
        <WlRing pct={m.pct}><i className={`ph ph-${m.icon}`} style={{ fontSize: 22, color: "var(--teal)" }}></i></WlRing>
      )}
      <div style={{ minWidth: 0, flex: 1 }}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 }}>
          <span style={{ fontSize: 12.5, color: "var(--text-tertiary)" }}>{m.label}</span>
          {!m.quantity && <span style={{ fontSize: 11.5, fontWeight: 500, color: "var(--teal-text)", background: "var(--teal-fill)", borderRadius: 999, padding: "2px 9px", whiteSpace: "nowrap" }}>{m.trend}</span>}
        </div>
        <div style={{ fontFamily: "var(--font-serif)", fontSize: 24, color: "var(--text-primary)", letterSpacing: "-0.01em", margin: "3px 0 2px", whiteSpace: "nowrap" }}>{m.value}</div>
        <div style={{ fontSize: 12, color: "var(--text-tertiary)" }}>{m.goal}</div>
        <WlSourceNote source={m.source} />
      </div>
    </Card>
  );
}

function SleepInsight({ data }) {
  const sleepLabel = `${data.sleepH}h ${String(data.sleepM).padStart(2, "0")}m`;
  return (
    <window.VelourInsight pillar="wellness"
      // Water under the 2.0 L goal the Hydration tile uses gets the hydration
      // study; otherwise the card is about sleep and gets the sleep one. Picked
      // by what the card says, never by which reading sounds more impressive.
      cite={data.hydration < 2.0 ? "mild-dehydration-mood" : "sleep-routine-satisfaction"}
      headline={`You logged ${sleepLabel} of sleep and ${window.velourLitres(data.hydration)} L of water today.`}
      support="Keep logging daily and VELOUR will start surfacing patterns — like whether your best sleep follows your most active days.">
      <div style={{ marginTop: 18, display: "flex", flexWrap: "wrap", alignItems: "center", gap: "10px 26px" }}>
        {data.supps.length > 0 && (
          <div style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 13.5, color: "var(--teal-text)" }}>
            <i className="ph ph-pill" style={{ fontSize: 15, color: "var(--teal)" }}></i>
            <span>{data.supps.join(" · ")}</span>
          </div>
        )}
        <div style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 13.5, color: "var(--text-secondary)" }}>
          <i className="ph ph-info" style={{ fontSize: 15, color: "var(--teal)" }}></i>
          <span>Patterns emerge after a few days of entries.</span>
        </div>
      </div>
    </window.VelourInsight>
  );
}

function DashWellnessFilled({ data, selectedDate, onDateChange, onEdit, entriesThisMonth }) {
  const today = wlTodayISO();
  const sleepTotalMins = data.sleepH * 60 + data.sleepM;
  const sleepPct = Math.min(100, Math.round((sleepTotalMins / 450) * 100)); // goal: 7h30m
  const hydraPct = Math.min(100, Math.round((data.hydration / 2.0) * 100));
  const stepsPct = Math.min(100, Math.round((data.steps / 8000) * 100));
  const daylightPct = Math.min(100, Math.round((data.daylight / 45) * 100));
  const stillPct = Math.min(100, Math.round((data.stillness / 10) * 100));
  const suppPct = data.supps.length > 0 ? Math.min(100, Math.round((data.supps.length / 3) * 100)) : 0;

  // Where each number came from, so the tiles can say so. Absent means typed —
  // 011's rule — and sleep is keyed under sleepH because the hours and the
  // minutes are one reading with one origin.
  const src = (data.sources && typeof data.sources === "object") ? data.sources : {};

  const metrics = [
    { id: "sleep", icon: "moon", label: "Sleep", value: `${data.sleepH}h ${String(data.sleepM).padStart(2, "0")}m`, goal: "7h 30m goal", pct: sleepPct, trend: sleepPct >= 90 ? "On target" : sleepPct >= 70 ? "Close" : "Low", source: src.sleepH },
    { id: "hydra", icon: "drop", label: "Hydration", value: `${window.velourLitres(data.hydration)} L`, goal: "2.0 L goal", pct: hydraPct, trend: hydraPct >= 100 ? "Hit it" : "On pace", source: src.hydration },
    { id: "steps", icon: "footprints", label: "Steps", value: data.steps.toLocaleString(), goal: "8,000 steps goal", pct: stepsPct, trend: stepsPct >= 100 ? "Goal met" : `${stepsPct}%`, source: src.steps },
    // A QUANTITY, NEVER A TARGET — see the note on MetricCard. No goal line, no
    // ring, no percentage: what steps cannot see, said as a number and left alone.
    { id: "move", icon: "person-simple-run", label: "Movement", value: `${data.exercise} min`, goal: "at effort", quantity: true, source: src.exercise },
    { id: "out", icon: "sun-horizon", label: "Daylight", value: `${data.daylight} min`, goal: "45 min outdoors", pct: daylightPct, trend: daylightPct >= 100 ? "Goal met" : daylightPct >= 50 ? "Halfway" : "Low", source: src.daylight },
    { id: "still", icon: "wind", label: "Stillness", value: `${data.stillness} min`, goal: "10 min breathwork", pct: stillPct, trend: stillPct >= 100 ? "Done" : "Steady", source: src.stillness },
    { id: "supp", icon: "pill", label: "Supplements", value: data.supps.length ? `${data.supps.length} taken` : "None logged", goal: data.supps.length ? data.supps.join(" · ") : "Tap to add", pct: suppPct, trend: data.supps.length ? (data.supps.length >= 3 ? "Goal met" : `${data.supps.length} of 3`) : "—", source: src.supps },
  ];

  const nudges = [];
  if (hydraPct < 100) nudges.push({ icon: "drop", t: `${window.velourLitres(2.0 - data.hydration)} L more water`, s: "You tend to dip after 3pm." });
  if (daylightPct < 100) nudges.push({ icon: "sun-horizon", t: `${45 - data.daylight} more minutes outdoors`, s: "A short walk closes the gap." });
  if (data.supps.length === 0) nudges.push({ icon: "pill", t: "Log your supplements", s: "Tap Edit to add what you took." });
  if (nudges.length === 0) nudges.push({ icon: "check-circle", t: `You hit every goal ${wlFormatDateLabel(selectedDate).toLowerCase() === "today" ? "today" : "that day"}`, s: "A genuinely good day. Rest well." });

  return (
    <main style={{ maxWidth: 1240, margin: "0 auto", padding: "36px 32px 64px", display: "flex", flexDirection: "column", gap: 24, fontFamily: "var(--font-sans)" }}>
      <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", flexWrap: "wrap", gap: 24 }}>
        <div style={{ maxWidth: 560 }}>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 9, fontSize: 11.5, letterSpacing: "0.16em", textTransform: "uppercase", fontWeight: 500, color: "var(--teal-text)", background: "var(--teal-fill)", borderRadius: 999, padding: "6px 14px" }}><i className="ph ph-heart" style={{ fontSize: 14 }}></i>Wellness</span>
          <h1 style={{ fontFamily: "var(--font-serif)", fontWeight: 500, fontSize: 40, lineHeight: 1.08, letterSpacing: "-0.02em", color: "var(--text-primary)", margin: "18px 0 0" }}>Your body, in rhythm.</h1>
          <p style={{ fontSize: 16, lineHeight: 1.65, color: "var(--text-secondary)", margin: "14px 0 0" }}>Nothing to check off — wellness is a state, not a to-do list. VELOUR watches the broad strokes and reflects the rhythm back, gently.</p>
        </div>
        <div style={{ background: "var(--teal-fill)", borderRadius: 14, padding: "16px 18px", minWidth: 132 }}>
          <div style={{ fontSize: 11.5, color: "var(--teal-text)", opacity: 0.8, marginBottom: 8 }}>Logged this month</div>
          <div style={{ fontFamily: "var(--font-serif)", fontSize: 26, color: "var(--teal-text)", letterSpacing: "-0.01em", whiteSpace: "nowrap" }}>{entriesThisMonth} day{entriesThisMonth === 1 ? "" : "s"}</div>
          <div style={{ fontSize: 12, color: "var(--teal-text)", opacity: 0.75, marginTop: 4 }}>Keep going for patterns</div>
        </div>
      </div>

      <SleepInsight data={data} />

      {/* Date selector */}
      <Card padding={0} style={{ overflow: "hidden" }}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "16px 22px", flexWrap: "wrap", gap: 14 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
            <button onClick={() => onDateChange(wlAddDays(selectedDate, -1))} aria-label="Previous day" style={{ width: 34, height: 34, borderRadius: "50%", border: "var(--border-width) solid var(--border-strong)", background: "var(--surface-card)", color: "var(--text-secondary)", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}>
              <i className="ph ph-caret-left" style={{ fontSize: 14 }}></i>
            </button>
            <div style={{ display: "flex", alignItems: "center", gap: 10, minWidth: 200 }}>
              <i className="ph ph-calendar-blank" style={{ fontSize: 17, color: "var(--teal)" }}></i>
              <span style={{ fontFamily: "var(--font-serif)", fontSize: 19, color: "var(--text-primary)", letterSpacing: "-0.01em" }}>{wlFormatDateLabel(selectedDate)}</span>
              <input type="date" value={selectedDate} max={today} onChange={(e) => e.target.value && onDateChange(e.target.value)} style={{ border: "var(--border-width) solid var(--border)", borderRadius: 8, padding: "5px 9px", fontSize: 12.5, color: "var(--text-tertiary)", background: "var(--surface-card)", fontFamily: "var(--font-sans)" }} />
            </div>
            <button onClick={() => onDateChange(wlAddDays(selectedDate, 1))} disabled={selectedDate >= today} aria-label="Next day" style={{ width: 34, height: 34, borderRadius: "50%", border: "var(--border-width) solid var(--border-strong)", background: "var(--surface-card)", color: selectedDate >= today ? "var(--border-strong)" : "var(--text-secondary)", cursor: selectedDate >= today ? "default" : "pointer", display: "flex", alignItems: "center", justifyContent: "center", opacity: selectedDate >= today ? 0.5 : 1 }}>
              <i className="ph ph-caret-right" style={{ fontSize: 14 }}></i>
            </button>
            {selectedDate !== today && (
              <button onClick={() => onDateChange(today)} style={{ fontSize: 13, color: "var(--teal-text)", background: "var(--teal-fill)", border: "none", borderRadius: 999, padding: "7px 14px", cursor: "pointer", fontFamily: "var(--font-sans)", fontWeight: 500 }}>Jump to today</button>
            )}
          </div>
          <button onClick={onEdit} style={{ display: "inline-flex", alignItems: "center", gap: 8, fontSize: 13.5, color: "var(--teal-text)", background: "var(--teal-fill)", borderRadius: 999, padding: "9px 16px", whiteSpace: "nowrap", border: "none", cursor: "pointer", fontFamily: "var(--font-sans)", fontWeight: 500 }}>
            <i className="ph ph-pencil-simple" style={{ fontSize: 15 }}></i>Edit {window.velourDayPhrase(wlFormatDateLabel(selectedDate))}'s entry
          </button>
        </div>
      </Card>

      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(min(100%, 200px), 1fr))", gap: 20 }}>
        {metrics.map((m) => <MetricCard key={m.id} m={m} />)}
      </div>

      <Card padding={26} style={{ display: "flex", flexDirection: "column" }}>
          <div style={{ fontSize: 11, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--text-tertiary)", fontWeight: 500, marginBottom: 16 }}>Tending to, gently</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 16, flex: 1 }}>
            {nudges.slice(0, 3).map((r) => (
              <div key={r.t} style={{ display: "flex", gap: 13, alignItems: "flex-start" }}>
                <span style={{ width: 38, height: 38, borderRadius: 11, flexShrink: 0, background: "var(--teal-fill)", display: "flex", alignItems: "center", justifyContent: "center" }}><i className={`ph ph-${r.icon}`} style={{ fontSize: 18, color: "var(--teal)" }}></i></span>
                <div>
                  <div style={{ fontSize: 14.5, color: "var(--text-primary)", fontWeight: 500 }}>{r.t}</div>
                  <div style={{ fontSize: 13, color: "var(--text-tertiary)", marginTop: 2, lineHeight: 1.5 }}>{r.s}</div>
                </div>
              </div>
            ))}
          </div>
          <div style={{ fontSize: 12.5, color: "var(--text-tertiary)", marginTop: 18, lineHeight: 1.6, paddingTop: 16, borderTop: "var(--border-width) solid var(--divider)" }}>No streaks, no guilt. These are nudges, not demands.</div>
        </Card>
    </main>
  );
}

function DashWellness() {
  const [log, setLog] = React.useState(loadWellnessLog);
  const [selectedDate, setSelectedDate] = React.useState(wlTodayISO());
  const [editing, setEditing] = React.useState(false);

  // The account's entries land after first paint on a second device — see the
  // same note in DashRituals.
  if (window.useVelourSynced) window.useVelourSynced("wellness", () => setLog(loadWellnessLog()));

  const handleSave = (date, form) => {
    const next = { ...log, [date]: wlStampManual(log[date], form) };
    setLog(next);
    saveWellnessLog(next);
    setEditing(false);
  };

  const dataForDay = log[selectedDate] || null;
  const today = wlTodayISO();
  const monthPrefix = today.slice(0, 7); // "2026-06"
  const entriesThisMonth = Object.keys(log).filter((d) => d.startsWith(monthPrefix)).length;

  if (!dataForDay || editing) {
    return (
      <WellnessOnboard
        onSave={handleSave}
        selectedDate={selectedDate}
        onDateChange={(d) => { setSelectedDate(d); setEditing(false); }}
        existingData={dataForDay}
      />
    );
  }

  return (
    <DashWellnessFilled
      data={dataForDay}
      selectedDate={selectedDate}
      onDateChange={setSelectedDate}
      onEdit={() => setEditing(true)}
      entriesThisMonth={entriesThisMonth}
    />
  );
}

window.DashWellness = DashWellness;
