/* Lieblingsmarken — Community-Empfehlungen für nachhaltige Mode
   Reine Frontend-Demo. Brand-Style: minimalismuse (Creme, Anthrazit, Senf, Pfirsich, Montserrat). */
const { useState, useMemo, useEffect, useRef } = React;

/* ─── Beispieldaten ─────────────────────────────────────────── */
const SEED = [
  {
    name: "ARMEDANGELS",
    cats: ["Jeans", "Allerlei"],
    votes: [
      { t: "nachhaltigere Kleidung", kind: "pro" },
      { t: "inzwischen viele Kollektionen, kein slow fashion mehr", kind: "hint" },
    ],
  },
  {
    name: "Dilling",
    cats: ["Basics", "Sport BHs", "Kinderkleidung"],
    votes: [
      { t: "mulesing-freie Merinowolle", kind: "pro" },
      { t: "sehr gutes Preisleistungsverhältnis", kind: "pro" },
      { t: "Ripp Oberteile leiern aus, andere halten gut", kind: "hint" },
    ],
  },
  {
    name: "OSKA",
    cats: ["Hosen", "Allerlei"],
    votes: [
      { t: "zeitlose Slow Fashion", kind: "pro" },
      { t: "hochpreisig, aber die Qualität wert", kind: "hint" },
      { t: "sehr bequeme und schöne Hosen", kind: "pro" },
    ],
  },
  {
    name: "The Slow Label",
    cats: ["Basics", "Tops"],
    votes: [
      { t: "die besten Tops", kind: "pro" },
      { t: "blickdicht ohne BH", kind: "pro" },
      { t: "leider häufig ausverkauft", kind: "hint" },
    ],
  },
];

/* Fallback-Zähler, wenn keine API-Daten da sind: Anzahl O-Töne */
const withCount = (b) => ({ ...b, count: b.votes.length });

/* Vollständige Kategorienliste (Stand Notion-Schema) — für das Einreichen-Formular,
   damit auch neue Marken passend eingeordnet werden können. Die Filter-Chips oben
   nutzen dagegen die vom Backend gelieferten, tatsächlich vorhandenen Kategorien. */
const CATEGORIES = [
  "Allerlei", "Jeans", "Hosen", "Unterwäsche", "Schuhe", "Yoga Wear",
  "Kinderkleidung", "Basics", "Tops", "Langarmoberteile", "Sport BHs",
  "Strickjacken", "Pullover", "Hausschuhe", "Westen", "Handschuhe",
  "Activewear", "Leggins", "Hijabs",
];

const LOGO = "/Lieblingsmarken/assets/libelle.png";

/* ─── Kleine Bausteine ──────────────────────────────────────── */
function Logo({ size = 30 }) {
  return <img src={LOGO} alt="Lieblingsmarken" className="logo" style={{ width: size, height: size }} />;
}

function Chip({ label, active, onClick, small }) {
  return (
    <button
      type="button"
      className={"chip" + (active ? " chip--on" : "") + (small ? " chip--sm" : "")}
      onClick={onClick}
    >
      {label}
    </button>
  );
}

/* ─── Marken-Karte ──────────────────────────────────────────── */
/* ─── Marken-Attribute: Preis / Tempo / Stil / Siegel ───────── */
const IcoClock = (
  <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
    <circle cx="12" cy="12" r="9" />
    <path d="M12 12.4V7M12 12.4l3.4 2" fill="none" stroke="#fffef3" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" />
  </svg>
);
const IcoBolt = (
  <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M13 2 4.6 13.2H11l-1 8.8L19.4 9.6H13z" /></svg>
);
const IcoDiaO = (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" aria-hidden="true"><path d="M12 3l7.5 9-7.5 9-7.5-9z" strokeLinejoin="round" /></svg>
);
const IcoDiaF = (
  <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 3l7.5 9-7.5 9-7.5-9z" /></svg>
);
const IcoLeaf = (
  <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M6.05 8.05c-2.73 2.73-2.73 7.15-.02 9.88 1.47-3.4 4.09-6.24 7.36-7.93-2.77 2.34-4.71 5.61-5.39 9.32 2.6 1.23 5.8.78 7.95-1.37C19.43 14.47 20 4 20 4S9.53 4.57 6.05 8.05z" /></svg>
);

const STIL_LV = { Einfach: 1, Mittel: 2, Besonders: 3 };
const NACH_LV = { kaum: 1, manche: 2, alle: 3 };
const PREIS_TXT = { 1: "Preisniveau: günstig", 2: "Preisniveau: mittel", 3: "Preisniveau: hoch" };
const STIL_TXT = { 1: "Stil: einfach", 2: "Stil: mittel", 3: "Stil: besonders" };
const NACH_TXT = {
  1: "Nachhaltigkeit: kaum Nachhaltigkeitssiegel",
  2: "Nachhaltigkeit: manche Kleider mit Nachhaltigkeitssiegel",
  3: "Nachhaltigkeit: alle Kleider mit Nachhaltigkeits-Siegel",
};

/* drei Stufen-Marken, gefüllt bis n */
function marks(n, full, empty) {
  return [1, 2, 3].map((i) => (
    <span key={i} className={"fct__m" + (i <= n ? "" : " fct__off")}>{i <= n ? full : empty}</span>
  ));
}

function Facts({ brand }) {
  const [open, setOpen] = useState(null);
  const items = [];
  if (brand.price) {
    const n = brand.price.length;
    const node = [1, 2, 3].map((i) => (
      <span key={i} className={"fct__euro" + (i <= n ? "" : " fct__euro--off")}>€</span>
    ));
    items.push({ k: "preis", text: PREIS_TXT[n] || "Preisniveau", node });
  }
  if (brand.tempo) {
    items.push({ k: "tempo", text: brand.tempo === "Fast" ? "Fast Fashion" : "Slow Fashion", node: brand.tempo === "Fast" ? IcoBolt : IcoClock });
  }
  if (brand.stil && STIL_LV[brand.stil]) {
    const n = STIL_LV[brand.stil];
    items.push({ k: "stil", text: STIL_TXT[n], node: marks(n, IcoDiaF, IcoDiaF) });
  }
  if (brand.nachhaltigkeit && NACH_LV[brand.nachhaltigkeit]) {
    const n = NACH_LV[brand.nachhaltigkeit];
    items.push({ k: "nach", text: NACH_TXT[n], node: marks(n, IcoLeaf, IcoLeaf) });
  }
  if (!items.length) return null;
  return (
    <div className="facts">
      {items.map((it) => (
        <button
          key={it.k}
          type="button"
          className={"fct" + (open === it.k ? " fct--on" : "")}
          aria-label={it.text}
          onClick={() => setOpen(open === it.k ? null : it.k)}
        >
          {it.node}
          <span className="fct__tip" role="tooltip">{it.text}</span>
        </button>
      ))}
    </div>
  );
}

function BrandCard({ brand, open, onToggle, onAdd, isNew }) {
  const bodyRef = useRef(null);
  const [h, setH] = useState(0);
  useEffect(() => {
    if (bodyRef.current) setH(open ? bodyRef.current.scrollHeight : 0);
  }, [open, brand]);

  const hearts = Math.min(brand.count || 0, 5);
  return (
    <article className={"card" + (open ? " card--open" : "") + (isNew ? " card--new" : "")}>
      <div className="card__head">
        <div className="card__toprow">
          <button type="button" className="card__open" onClick={onToggle} aria-expanded={open}>
            <h3>{brand.name}</h3>
          </button>
          <div className="card__meta">
            <span className="count" aria-label={"Von " + brand.count + (brand.count === 1 ? " Frau" : " Frauen") + " empfohlen"}>
              {Array.from({ length: hearts }, (_, i) => (
                <svg key={i} className="count__heart" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
                  <path d="M12 21l-1.45-1.32C5.4 14.36 2 11.28 2 7.5 2 4.42 4.42 2 7.5 2c1.74 0 3.41.81 4.5 2.09C13.09 2.81 14.76 2 16.5 2 19.58 2 22 4.42 22 7.5c0 3.78-3.4 6.86-8.55 11.18L12 21z" />
                </svg>
              ))}
              <span className="count__tip" role="tooltip" aria-hidden="true">
                Von {brand.count} {brand.count === 1 ? "Frau" : "Frauen"} empfohlen
              </span>
            </span>
            <button
              type="button"
              className="card__add"
              onClick={onAdd}
              aria-label={"Feedback zu " + brand.name + " geben"}
              title={"Feedback zu " + brand.name + " geben"}
            >
              <svg width="17" height="17" viewBox="0 0 18 18" fill="none" aria-hidden="true">
                <path d="M9 3.5v11M3.5 9h11" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" />
              </svg>
            </button>
          </div>
        </div>
        {brand.slogan || brand.cats.length ? (
          <button type="button" className="card__sub" onClick={onToggle} aria-expanded={open}
            aria-label={(open ? "Einklappen: " : "Ausklappen: ") + brand.name}>
            {brand.slogan ? <p className="card__slogan">{brand.slogan}</p> : null}
            {brand.cats.length ? (
              <div className="card__cats">
                {(open ? brand.cats : brand.cats.slice(0, 2)).map((c) => (
                  <span key={c} className="tag">{c}</span>
                ))}
                {!open && brand.cats.length > 2 ? (
                  <span className="tag tag--more">+{brand.cats.length - 2}</span>
                ) : null}
              </div>
            ) : null}
          </button>
        ) : null}
      </div>

      <div className="card__factsrow">
        <Facts brand={brand} />
        <button type="button" className="chev" onClick={onToggle} aria-expanded={open}
          aria-label={open ? "Weniger anzeigen" : "Mehr anzeigen"}>
          <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
            <path d="M4 6l4 4 4-4" stroke="currentColor" strokeWidth="0.7" strokeLinecap="round" strokeLinejoin="round" />
          </svg>
        </button>
      </div>

      <div className="card__reveal" style={{ height: h }}>
        <div className="card__body" ref={bodyRef}>
          <p className="card__body-label">Das sagt die Community</p>
          <ul className="voices">
            {brand.votes.map((v, i) => (
              <li key={i} className={"voice voice--" + v.kind}>
                <span className="voice__dot" aria-hidden="true" />
                <span className="voice__text">{v.t}</span>
              </li>
            ))}
          </ul>
          {brand.website ? (
            <a className="card__shop" href={brand.website} target="_blank" rel="noopener noreferrer">
              Zum Shop
              <svg width="13" height="13" viewBox="0 0 14 14" fill="none" aria-hidden="true">
                <path d="M4.5 9.5l5-5M5.5 4.5h4v4" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </a>
          ) : null}
        </div>
      </div>
    </article>
  );
}

/* ─── Marken-Eingabe mit Vorschlägen ────────────────────────── */
/* Eigenes Dropdown im Website-Design (kein natives <datalist>). Erscheint erst,
   sobald getippt wird, und ist auf die Eingabe gefiltert. Eine Notiz darunter
   verrät, ob die Marke schon empfohlen wurde oder neu ist. */
function BrandNameField({ value, onChange, knownNames, placeholder, autoFocus }) {
  const known = knownNames || [];
  const [focused, setFocused] = useState(false);
  const q = value.trim().toLowerCase();
  const exists = q.length > 0 && known.some((n) => n.toLowerCase() === q);
  const matches = q
    ? known
        .filter((n) => {
          const nl = n.toLowerCase();
          return nl.startsWith(q) || nl.split(/\s+/).some((w) => w.startsWith(q));
        })
        .sort((a, b) => a.localeCompare(b, "de", { sensitivity: "base" }))
        .slice(0, 8)
    : [];
  // Liste nur zeigen, wenn getippt wurde und es Treffer gibt – nicht beim bloßen
  // Reinklicken und nicht, wenn die Eingabe exakt der einzige Treffer ist.
  const showList = focused && matches.length > 0 && !(matches.length === 1 && matches[0].toLowerCase() === q);

  return (
    <div className="bn">
      <input
        className="input"
        value={value}
        onChange={(e) => onChange(e.target.value)}
        onFocus={() => setFocused(true)}
        onBlur={() => setTimeout(() => setFocused(false), 120)}
        placeholder={placeholder}
        autoComplete="off"
        autoFocus={autoFocus}
      />
      {showList ? (
        <ul className="bn__list">
          {matches.map((n) => (
            <li key={n}>
              <button
                type="button"
                className="bn__opt"
                onMouseDown={(e) => e.preventDefault()}
                onClick={() => { onChange(n); setFocused(false); }}
              >
                {n}
              </button>
            </li>
          ))}
        </ul>
      ) : null}
      {!showList && value.trim().length > 1 ? (
        <span className={"brandhint" + (exists ? " brandhint--known" : " brandhint--new")}>
          {exists
            ? "Diese Marke wurde schon mal empfohlen – teile gerne deine Sicht dazu."
            : "Super, eine neue Marke 🤩 – schön, dass du sie ergänzt."}
        </span>
      ) : null}
    </div>
  );
}

/* ─── Einreichen-Formular (Modal) ───────────────────────────── */
function SubmitSheet({ onClose, onSubmit, knownNames }) {
  const [name, setName] = useState("");
  const [pieces, setPieces] = useState("");
  const [why, setWhy] = useState("");
  const [extra, setExtra] = useState("");
  const [author, setAuthor] = useState("");
  const [done, setDone] = useState(false);
  const [sending, setSending] = useState(false);
  const [err, setErr] = useState("");

  // Pflicht: Marke + Warum. Der Rest ist optional.
  const canSend = name.trim().length > 1 && why.trim().length > 1;

  const send = async () => {
    if (!canSend || sending) return;
    setSending(true);
    setErr("");
    try {
      await onSubmit({
        name: name.trim(),
        votes: [{ t: why.trim(), kind: "pro" }],
        pieces: pieces.trim(),
        extra: extra.trim(),
        empfohlenVon: author.trim(),
      });
      setDone(true);
    } catch (e) {
      setErr("Das hat gerade nicht geklappt. Bitte versuch es nochmal.");
    } finally {
      setSending(false);
    }
  };

  return (
    <div className="sheet-overlay" onClick={onClose}>
      <div className="sheet" onClick={(e) => e.stopPropagation()}>
        <button className="sheet__close" onClick={onClose} aria-label="Schließen">
          <svg width="18" height="18" viewBox="0 0 18 18"><path d="M4 4l10 10M14 4L4 14" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>
        </button>

        {done ? (
          <div className="sheet__thanks">
            <Logo size={40} />
            <h2>Danke, dass du teilst.</h2>
            <p className="muted">Deine Empfehlung wird kurz geprüft und erscheint dann in der Liste. Magst du noch eine teilen?</p>
            <button className="btn btn--ghost" onClick={onClose}>Zurück zur Übersicht</button>
          </div>
        ) : (
          <React.Fragment>
            <h2 className="sheet__h">Teile deine Lieblingsmarke mit der Community</h2>

            <label className="field">
              <span className="field__lbl">Marke</span>
              <BrandNameField value={name} onChange={setName} knownNames={knownNames} placeholder="z. B. Dilling" />
            </label>

            <label className="field">
              <span className="field__lbl">Welche Kleidungsstücke macht diese Marke besonders gut?</span>
              <input className="input" value={pieces} onChange={(e) => setPieces(e.target.value)} placeholder="z. B. Tops, Pullover, Jeans, …" />
            </label>

            <label className="field">
              <span className="field__lbl">Warum?</span>
              <input className="input" value={why} onChange={(e) => setWhy(e.target.value)} placeholder="Was gefällt dir besonders daran …" />
            </label>

            <label className="field">
              <span className="field__lbl">Was magst du noch zu dieser Marke teilen?</span>
              <textarea className="input input--area" value={extra} onChange={(e) => setExtra(e.target.value)} rows={3}
                placeholder="Hinweise, gute Erfahrungen, schlechte Erfahrungen, …" />
            </label>

            <label className="field">
              <span className="field__lbl">Dein Name</span>
              <input className="input" value={author} onChange={(e) => setAuthor(e.target.value)} placeholder="Optional" />
            </label>

            <button className={"btn btn--cta" + (canSend && !sending ? "" : " btn--off")} onClick={send}>
              {sending ? "Wird gesendet …" : "Lieblingsmarke teilen"}
            </button>
            {err ? <p className="field__err">{err}</p> : null}
            <p className="sheet__note muted">Sichtbar wird sie nach einer kurzen Prüfung.</p>
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

/* ─── Feedback-Sheet (Marke vorausgewählt) ──────────────────── */
/* Minimaler Weg vom Kachel-Plus: nur Name (Pflicht) + Freitext. Die Marke
   steht fest, Kategorien existieren schon, die Art (Pro/Hinweis/Kontra)
   bestimmt die Notion-Automatisierung später per Sentiment. */
function FeedbackSheet({ brand, onClose, onSubmit }) {
  const [by, setBy] = useState("");
  const [note, setNote] = useState("");
  const [done, setDone] = useState(false);
  const [sending, setSending] = useState(false);
  const [err, setErr] = useState("");

  const canSend = by.trim().length > 1 && note.trim().length > 1;

  const send = async () => {
    if (!canSend || sending) return;
    setSending(true);
    setErr("");
    try {
      await onSubmit({ name: brand.name, note: note.trim(), empfohlenVon: by.trim() });
      setDone(true);
    } catch (e) {
      setErr("Das hat gerade nicht geklappt. Bitte versuch es nochmal.");
    } finally {
      setSending(false);
    }
  };

  return (
    <div className="sheet-overlay" onClick={onClose}>
      <div className="sheet" onClick={(e) => e.stopPropagation()}>
        <button className="sheet__close" onClick={onClose} aria-label="Schließen">
          <svg width="18" height="18" viewBox="0 0 18 18"><path d="M4 4l10 10M14 4L4 14" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>
        </button>

        {done ? (
          <div className="sheet__thanks">
            <Logo size={40} />
            <h2>Danke für dein Feedback.</h2>
            <p className="muted">Es wird kurz geprüft und fließt dann in {brand.name} ein.</p>
            <button className="btn btn--ghost" onClick={onClose}>Zurück zur Übersicht</button>
          </div>
        ) : (
          <React.Fragment>
            <h2 className="sheet__h">Dein Feedback zu <em className="sheet__brand">{brand.name}</em>:</h2>

            <label className="field">
              <textarea className="input input--area" value={note} onChange={(e) => setNote(e.target.value)} rows={3}
                placeholder="Was möchtest du anderen zu dieser Marke mitgeben? Lob, Hinweis oder Kritik – alles ist willkommen." />
            </label>

            <label className="field">
              <span className="field__lbl">Dein Name</span>
              <input className="input" value={by} onChange={(e) => setBy(e.target.value)} placeholder="z. B. Anna" />
            </label>

            <button className={"btn btn--cta" + (canSend && !sending ? "" : " btn--off")} onClick={send}>
              {sending ? "Wird gesendet …" : "Feedback senden"}
            </button>
            {err ? <p className="field__err">{err}</p> : null}
            <p className="sheet__note muted">Sichtbar wird es erst nach einer Prüfung.</p>
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

/* ─── Wunsch-Sheet (Feature-Wunsch ans Team) ────────────────── */
/* Landet als "Wunsch" in der Originale-DB – getrennt von Empfehlungen,
   zählt NICHT als Onboarding-Beitrag. */
function WishSheet({ onClose, onSubmit }) {
  const [wish, setWish] = useState("");
  const [by, setBy] = useState("");
  const [done, setDone] = useState(false);
  const [sending, setSending] = useState(false);
  const [err, setErr] = useState("");

  const canSend = wish.trim().length > 2;

  const send = async () => {
    if (!canSend || sending) return;
    setSending(true);
    setErr("");
    try {
      await onSubmit({ wish: wish.trim(), empfohlenVon: by.trim() });
      setDone(true);
    } catch (e) {
      setErr("Das hat gerade nicht geklappt. Bitte versuch es nochmal.");
    } finally {
      setSending(false);
    }
  };

  return (
    <div className="sheet-overlay" onClick={onClose}>
      <div className="sheet" onClick={(e) => e.stopPropagation()}>
        <button className="sheet__close" onClick={onClose} aria-label="Schließen">
          <svg width="18" height="18" viewBox="0 0 18 18"><path d="M4 4l10 10M14 4L4 14" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>
        </button>

        {done ? (
          <div className="sheet__thanks">
            <Logo size={40} />
            <h2>Danke für deinen Wunsch.</h2>
            <p className="muted">Wir lesen jeden einzelnen und nehmen ihn mit in die Weiterentwicklung.</p>
            <button className="btn btn--ghost" onClick={onClose}>Zurück zur Übersicht</button>
          </div>
        ) : (
          <React.Fragment>
            <h2 className="sheet__h">Was wünschst du dir?</h2>

            <label className="field">
              <textarea className="input input--area" value={wish} onChange={(e) => setWish(e.target.value)} rows={4}
                placeholder="Welche Funktion oder Marke fehlt dir? Was würde die Plattform noch nützlicher machen?" />
            </label>

            <label className="field">
              <span className="field__lbl">Dein Name</span>
              <input className="input" value={by} onChange={(e) => setBy(e.target.value)} placeholder="Optional" />
            </label>

            <div className="sheet__ctarow">
              <button className={"btn btn--cta sheet__cta--auto" + (canSend && !sending ? "" : " btn--off")} onClick={send}>
                {sending ? "Wird gesendet …" : "Wunsch absenden"}
              </button>
            </div>
            {err ? <p className="field__err">{err}</p> : null}
            <p className="sheet__note muted">Wird in Kürze vom Team geprüft.</p>
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

/* ─── Onboarding-Gate (erster Login: erst eine Empfehlung teilen) ──
   Wird vor der Übersicht gezeigt, solange die Userin noch keine Empfehlung
   abgegeben hat. Nach erfolgreichem Teilen öffnet sich das Tool. */
function OnboardingGate({ vorname, onDone, onLogout }) {
  const [name, setName] = useState("");
  const [pieces, setPieces] = useState("");
  const [why, setWhy] = useState("");
  const [extra, setExtra] = useState("");
  const [done, setDone] = useState(false);
  const [sending, setSending] = useState(false);
  const [err, setErr] = useState("");
  const [knownNames, setKnownNames] = useState([]);

  // Bekannte Marken für die Vorschlagsliste laden (Fallback: Beispieldaten).
  useEffect(() => {
    let alive = true;
    fetch("/api/brands")
      .then((r) => (r.ok ? r.json() : Promise.reject()))
      .then((d) => { if (alive) setKnownNames((d.brands || []).map((b) => b.name)); })
      .catch(() => { if (alive) setKnownNames(SEED.map((b) => b.name)); });
    return () => { alive = false; };
  }, []);

  const canSend = name.trim().length > 1 && why.trim().length > 1;

  const send = async (e) => {
    if (e) e.preventDefault();
    if (!canSend || sending) return;
    setSending(true);
    setErr("");
    try {
      const res = await fetch("/api/submit", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          kind: "empfehlung",
          name: name.trim(),
          note: why.trim(),
          pieces: pieces.trim(),
          extra: extra.trim(),
          empfohlenVon: vorname || "",
        }),
      });
      if (!res.ok) {
        const info = await res.json().catch(() => ({}));
        throw new Error(info.error || "Speichern fehlgeschlagen");
      }
      setDone(true);
    } catch (e2) {
      setErr("Das hat gerade nicht geklappt. Bitte versuch es nochmal.");
    } finally {
      setSending(false);
    }
  };

  return (
    <div className="login onboard">
      <div className="onboard__card">
        <Logo size={44} />
        {done ? (
          <div className="onboard__thanks">
            <p className="eyebrow">Danke für deine Empfehlung</p>
            <h1 className="login__h onboard__thanks-h">Willkommen in der Community{vorname ? ", " + vorname : ""}.</h1>
            <p className="login__sub">Deine Empfehlung wird jetzt geprüft.</p>
            <button className="btn btn--cta" onClick={onDone}>Zur Plattform</button>
          </div>
        ) : (
          <React.Fragment>
            <p className="eyebrow">Willkommen{vorname ? ", " + vorname : ""}</p>
            <h1 className="login__h">Welche Kleidungsmarke würdest du deiner besten Freundin empfehlen?</h1>
            <p className="login__sub">
              Diese Plattform lebt von Geheimtipps und Empfehlungen.
              Teile eine Lieblingsmarke und erhalte danach Zugang zu allen Community Empfehlungen.
            </p>

            <form className="onboard__form" onSubmit={send} noValidate>
              <label className="field">
                <span className="field__lbl">Marke</span>
                <BrandNameField value={name} onChange={setName} knownNames={knownNames} placeholder="z. B. Dilling" autoFocus />
              </label>

              <label className="field">
                <span className="field__lbl">Welche Kleidungsstücke macht diese Marke besonders gut?</span>
                <input className="input" value={pieces} onChange={(e) => setPieces(e.target.value)} placeholder="z. B. Tops, Pullover, Jeans, …" />
              </label>

              <label className="field">
                <span className="field__lbl">Warum?</span>
                <input className="input" value={why} onChange={(e) => setWhy(e.target.value)} placeholder="Was gefällt dir besonders daran …" />
              </label>

              <label className="field">
                <span className="field__lbl">Was magst du noch zu dieser Marke teilen?</span>
                <textarea className="input input--area" value={extra} onChange={(e) => setExtra(e.target.value)} rows={3}
                  placeholder="Hinweise, gute Erfahrungen, schlechte Erfahrungen, …" />
              </label>

              <div className="onboard__submit">
                <button className={"btn btn--cta" + (canSend && !sending ? "" : " btn--off")} type="submit">
                  {sending ? "Wird gesendet …" : "Einreichen & loslegen"}
                </button>
              </div>
              {err ? <p className="field__err">{err}</p> : null}
            </form>
            {onLogout ? (
              <button className="linklike linklike--quiet" onClick={onLogout}>Abmelden</button>
            ) : null}
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

/* ─── Lade-Splash (während der Login-Status geprüft wird) ────── */
function Splash() {
  return (
    <div className="login">
      <div className="login__card">
        <Logo size={46} />
        <p className="login__sub" style={{ marginTop: 22 }}>Einen Moment …</p>
      </div>
    </div>
  );
}

/* ─── Login-Gate (E-Mail → 6-stelliger Code) ────────────────── */
function LoginView({ onAuthed }) {
  const [step, setStep] = useState("email"); // "email" | "code"
  const [email, setEmail] = useState("");
  const [code, setCode] = useState("");
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState("");

  const validEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim());

  // Schritt 1: Code anfordern. Antwort ist bewusst generisch (verrät nicht,
  // ob die Adresse berechtigt ist) — wir gehen daher immer zur Code-Eingabe.
  const requestCode = async (e) => {
    e.preventDefault();
    if (busy) return;
    if (!validEmail) { setErr("Bitte gib eine gültige E-Mail-Adresse ein."); return; }
    setErr(""); setBusy(true);
    try {
      const r = await fetch("/api/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email: email.trim() }),
      });
      if (!r.ok) throw new Error();
      setCode("");
      setStep("code");
    } catch {
      setErr("Das hat gerade nicht geklappt. Bitte versuch es gleich nochmal.");
    } finally {
      setBusy(false);
    }
  };

  // Schritt 2: Code prüfen. Erfolg setzt die Session (Cookie kommt vom Server).
  const verify = async (e) => {
    e.preventDefault();
    if (busy) return;
    const c = code.replace(/\D/g, "");
    if (c.length !== 6) { setErr("Bitte gib den 6-stelligen Code ein."); return; }
    setErr(""); setBusy(true);
    try {
      const r = await fetch("/api/verify", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email: email.trim(), code: c }),
      });
      const data = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(data.error || "Der Code stimmt nicht. Bitte prüfe ihn.");
      onAuthed(data.vorname || "", data.contributed);
    } catch (e2) {
      setErr(e2.message || "Der Code stimmt nicht. Bitte prüfe ihn.");
    } finally {
      setBusy(false);
    }
  };

  return (
    <div className="login">
      <div className="login__card">
        <Logo size={46} />
        {step === "code" ? (
          <React.Fragment>
            <h1 className="login__h">Code eingeben.</h1>
            <p className="login__sub">
              Wir haben einen 6-stelligen Code an <strong>{email.trim()}</strong> geschickt.
              Gib ihn hier ein – er gilt 15 Minuten und nur in diesem Browser.
            </p>
            <form onSubmit={verify} className="login__form" noValidate>
              <input
                className={"input" + (err ? " input--err" : "")}
                inputMode="numeric"
                autoComplete="one-time-code"
                pattern="[0-9]*"
                maxLength={6}
                value={code}
                onChange={(e) => { setCode(e.target.value.replace(/\D/g, "").slice(0, 6)); if (err) setErr(""); }}
                placeholder="123456"
                style={{ textAlign: "center", fontSize: "1.4rem", letterSpacing: "0.4em", fontWeight: 500 }}
                autoFocus
              />
              {err ? <p className="field__err">{err}</p> : null}
              <button className={"btn btn--cta" + (busy ? " btn--off" : "")} type="submit">
                {busy ? "Wird geprüft …" : "Einloggen"}
              </button>
            </form>
            <button className="linklike" onClick={() => { setStep("email"); setErr(""); }}>
              Andere E-Mail verwenden
            </button>
          </React.Fragment>
        ) : (
          <React.Fragment>
            <p className="eyebrow">Lieblingsmarken</p>
            <h1 className="login__h">Schön, dass du hier bist.</h1>
            <p className="login__sub">
              Gib deine E-Mail ein, wir schicken dir einen 6-stelligen Code (schau auch im Spam-Ordner).
            </p>
            <form onSubmit={requestCode} className="login__form" noValidate>
              <input
                className={"input" + (err ? " input--err" : "")}
                type="email"
                value={email}
                onChange={(e) => { setEmail(e.target.value); if (err) setErr(""); }}
                placeholder="deine@email.de"
                autoComplete="email"
              />
              {err ? <p className="field__err">{err}</p> : null}
              <button className={"btn btn--cta btn--auto" + (busy ? " btn--off" : "")} type="submit">
                {busy ? "Code wird gesendet …" : "Code anfordern"}
              </button>
            </form>
            <p className="login__fine muted">
              Der Zugang gehört zu deinem Kurs. Verwende daher bitte deine Login-E-Mail von The Miracle Wardrobe.
            </p>
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

/* Spaltenzahl fürs Masonry je Fensterbreite (passt zu den CSS-Breakpoints) */
const colsForWidth = (w) => (w >= 1080 ? 4 : w >= 720 ? 2 : 1);

/* ─── Haupt-App ─────────────────────────────────────────────── */
function CommunityView({ vorname, onLogout }) {
  const [brands, setBrands] = useState(null);   // null = lädt noch
  const [filterCats, setFilterCats] = useState(CATEGORIES); // Chips: vom Backend gefüllt
  const [active, setActive] = useState([]);   // gewählte Kategorien (ODER)
  const [q, setQ] = useState("");
  const [openName, setOpenName] = useState(null);
  const [sheet, setSheet] = useState(false);
  const [wish, setWish] = useState(false);    // Wunsch-Sheet offen?
  const [feedbackBrand, setFeedbackBrand] = useState(null); // Kachel-Plus -> Marke
  const [newName, setNewName] = useState(null);
  const [toast, setToast] = useState("");
  // Spaltenzahl fürs Masonry (eigene, unabhängige Spalten -> ruhiges Aufklappen)
  const [cols, setCols] = useState(() => (typeof window !== "undefined" ? colsForWidth(window.innerWidth) : 1));
  useEffect(() => {
    const onResize = () => setCols(colsForWidth(window.innerWidth));
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  // Daten aus der API holen; bei Fehler (z.B. lokale Vorschau ohne Backend)
  // auf die Beispieldaten zurückfallen, damit die Ansicht nie leer bleibt.
  useEffect(() => {
    let alive = true;
    fetch("/api/brands")
      .then((r) => (r.ok ? r.json() : Promise.reject(r.status)))
      .then((data) => {
        if (!alive) return;
        setBrands((data.brands || []).map((b) => ({ ...b, votes: b.votes || [] })));
        if (data.categories && data.categories.length) setFilterCats(data.categories);
      })
      .catch(() => { if (alive) setBrands(SEED.map(withCount)); });
    return () => { alive = false; };
  }, []);

  const toggleCat = (c) =>
    setActive((p) => (p.includes(c) ? p.filter((x) => x !== c) : [...p, c]));

  const results = useMemo(() => {
    const needle = q.trim().toLowerCase();
    const isAllerlei = (b) => b.cats.some((c) => c.toLowerCase() === "allerlei");
    // "Allerlei"-Marken (führen von allem etwas) bleiben sichtbar, wenn nach einem
    // Kleidungsstück gefiltert/gesucht wird – nicht aber bei Schuhen, Unterwäsche etc.
    const APPAREL = [
      "hose", "hosen", "oberteil", "t-shirt", "tshirt", "top", "tops", "rock",
      "basics", "jeans", "langarmoberteil", "langarmoberteile", "strickjacke", "strickjacken",
    ];
    const allerleiKeep =
      active.some((c) => APPAREL.includes(c.toLowerCase())) ||
      (needle.length >= 2 && APPAREL.some((t) => t.includes(needle) || needle.includes(t)));
    return (brands || [])
      .filter((b) => active.length === 0 || b.cats.some((c) => active.includes(c)) || (allerleiKeep && isAllerlei(b)))
      .filter((b) => {
        if (!needle) return true;
        return (
          b.name.toLowerCase().includes(needle) ||
          b.cats.some((c) => c.toLowerCase().includes(needle)) ||
          b.votes.some((v) => v.t.toLowerCase().includes(needle)) ||
          (allerleiKeep && isAllerlei(b))
        );
      })
      .sort((a, b) => b.count - a.count);
  }, [brands, active, q]);

  const addBrand = async (data) => {
    // Einreichung wandert nach "Empfehlungen Originale" (Roh-Eingang). Sie erscheint
    // bewusst NICHT im Frontend — erst nach manuellem Ableiten/Freigeben in die
    // "Empfehlungen"-DB liefert /api/brands sie aus.
    const res = await fetch("/api/submit", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        kind: "empfehlung",
        name: data.name,
        note: data.votes[0].t,
        pieces: data.pieces,
        extra: data.extra,
        empfohlenVon: data.empfohlenVon,
      }),
    });
    if (!res.ok) {
      const info = await res.json().catch(() => ({}));
      throw new Error(info.error || "Speichern fehlgeschlagen");
    }

    setToast("Danke! Deine Empfehlung wird geprüft.");
    setTimeout(() => setToast(""), 3200);
  };

  // Feedback zu einer bestehenden Marke (Kachel-Plus). Marke steht fest,
  // darum nur Name + O-Ton; die Art bestimmt Notion später per Sentiment.
  const addFeedback = async ({ name, note, empfohlenVon }) => {
    const res = await fetch("/api/submit", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ kind: "feedback", name, note, empfohlenVon }),
    });
    if (!res.ok) {
      const info = await res.json().catch(() => ({}));
      throw new Error(info.error || "Speichern fehlgeschlagen");
    }
    // Kein optimistisches Einblenden: Feedback sammelt sich nur in "Originale".
    setToast("Danke! Dein Feedback wird geprüft.");
    setTimeout(() => setToast(""), 3200);
  };

  // Feature-Wunsch ans Team. Landet als "Wunsch" in der Originale-DB.
  const addWish = async ({ wish, empfohlenVon }) => {
    const res = await fetch("/api/submit", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ kind: "wunsch", note: wish, empfohlenVon }),
    });
    if (!res.ok) {
      const info = await res.json().catch(() => ({}));
      throw new Error(info.error || "Speichern fehlgeschlagen");
    }
    setToast("Danke! Dein Wunsch ist angekommen.");
    setTimeout(() => setToast(""), 3200);
  };

  return (
    <div className="app">
      {/* Kopf / Intro */}
      <header className="hdr">
        <div className="hdr__bar">
          {vorname
            ? <span className="hdr__greet">Schön, dass du hier bist, {vorname}.</span>
            : <span />}
          <div className="hdr__bar-right">
            <Logo size={18} />
            <button className="linklike linklike--quiet" onClick={onLogout}>
              Abmelden
            </button>
          </div>
        </div>
        <div className="hdr__intro">
          <h1>Lieblingsmarken<span className="hdr__byline">der Miracle Wardrobe Community</span></h1>
          <div className="hdr__rule" aria-hidden="true"></div>
          <p>Ehrliche Empfehlungen, von Frauen wie dir.</p>
        </div>
      </header>

      {/* Suche + Einreichen-Button */}
      <div className="searchrow">
      <div className="search">
        <svg className="search__ic" width="17" height="17" viewBox="0 0 17 17" fill="none">
          <circle cx="7.2" cy="7.2" r="5.2" stroke="currentColor" strokeWidth="1.3" />
          <path d="M11.2 11.2L15 15" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" />
        </svg>
        <input className="search__in" value={q} onChange={(e) => setQ(e.target.value)} placeholder="Marke oder Stichwort suchen" />
        {q ? <button className="search__clear" onClick={() => setQ("")} aria-label="Suche leeren">×</button> : null}
      </div>
        <button className="btn btn--cta searchrow__cta" onClick={() => setSheet(true)} aria-label="Empfehlung oder Änderung einreichen" title="Empfehlung oder Änderung einreichen">
          <svg width="29" height="29" viewBox="0 0 24 24" fill="none" aria-hidden="true">
            <path d="M12 4V20M4 12H20" stroke="currentColor" strokeWidth="1" strokeLinecap="round" />
          </svg>
        </button>
      </div>

      {/* Kategorie-Filter */}
      <div className="filters">
        <div className="chips chips--scroll">
          {filterCats.map((c) => (
            <Chip key={c} label={c} active={active.includes(c)} onClick={() => toggleCat(c)} />
          ))}
        </div>
        {active.length > 0 ? (
          <button className="linklike linklike--quiet filters__reset" onClick={() => setActive([])}>
            Filter zurücksetzen
          </button>
        ) : null}
      </div>

      {/* Ergebnis-Zeile */}
      <div className="resultline muted">
        {brands === null
          ? "lädt …"
          : results.length === brands.length
          ? `${brands.length} Marken`
          : `${results.length} von ${brands.length} Marken`}
      </div>

      {/* Marken-Übersicht. Bei wenigen Treffern (1–2) mittig, ab 3 in eigenen
          Spalten (Masonry) – so klappt eine Karte ruhig auf, ohne die anderen
          Spalten zu verschieben. */}
      {(() => {
        const card = (b) => (
          <BrandCard
            key={b.name}
            brand={b}
            open={openName === b.name}
            isNew={newName === b.name}
            onToggle={() => setOpenName((p) => (p === b.name ? null : b.name))}
            onAdd={() => setFeedbackBrand(b)}
          />
        );
        const few = brands !== null && results.length > 0 && results.length < 3;
        const masonry = brands !== null && results.length >= 3;
        return (
          <main className={"list" + (few ? " list--center" : masonry ? " list--cols" : "")}>
            {brands === null ? (
              <div className="empty">
                <Logo size={36} />
                <p className="muted">Einen Moment, die Marken werden geladen.</p>
              </div>
            ) : results.length === 0 ? (
              <div className="empty">
                <Logo size={36} />
                <p>Noch keine Marke in dieser Auswahl.</p>
                <p className="muted">Magst du die erste teilen, die hierher gehört?</p>
                <button className="btn btn--ghost" onClick={() => setSheet(true)}>Empfehlung teilen</button>
              </div>
            ) : few ? (
              results.map(card)
            ) : (
              Array.from({ length: cols }, (_, c) => (
                <div className="mcol" key={c}>
                  {results.filter((_, i) => i % cols === c).map(card)}
                </div>
              ))
            )}
          </main>
        );
      })()}

      <button className="wishfab" onClick={() => setWish(true)} aria-label="Wunsch einreichen" title="Wunsch einreichen">
        <svg width="13" height="13" viewBox="0 0 18 18" fill="none" aria-hidden="true">
          <path d="M9 2.5l1.9 3.9 4.3.6-3.1 3 .7 4.3L9 12.3 5.2 14.3l.7-4.3-3.1-3 4.3-.6z"
            stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round" />
        </svg>
        <span className="wishfab__txt">Wunsch einreichen</span>
      </button>

      {toast ? <div className="toast">{toast}</div> : null}
      {sheet ? <SubmitSheet onClose={() => setSheet(false)} onSubmit={addBrand} knownNames={(brands || []).map((b) => b.name)} /> : null}
      {wish ? <WishSheet onClose={() => setWish(false)} onSubmit={addWish} /> : null}
      {feedbackBrand ? (
        <FeedbackSheet brand={feedbackBrand} onClose={() => setFeedbackBrand(null)} onSubmit={addFeedback} />
      ) : null}
    </div>
  );
}

/* ─── Root: prüft Login-Status und wählt die Ansicht ────────── */
function App() {
  // null = wird geprüft, false = ausgeloggt, { vorname, contributed } = eingeloggt
  const [auth, setAuth] = useState(null);

  useEffect(() => {
    let alive = true;
    fetch("/api/me")
      .then((r) => r.json())
      .then((d) => {
        if (!alive) return;
        setAuth(d.authenticated ? { vorname: d.vorname || "", contributed: d.contributed !== false } : false);
      })
      .catch(() => { if (alive) setAuth(false); });
    return () => { alive = false; };
  }, []);

  const logout = async () => {
    try { await fetch("/api/logout", { method: "POST" }); } catch {}
    setAuth(false);
  };

  if (auth === null) return <Splash />;
  if (!auth) {
    return (
      <LoginView
        onAuthed={(vorname, contributed) => setAuth({ vorname: vorname || "", contributed: contributed !== false })}
      />
    );
  }
  // Onboarding-Gate: erst eine Empfehlung teilen, dann das Tool nutzen.
  if (!auth.contributed) {
    return (
      <OnboardingGate
        vorname={auth.vorname}
        onDone={() => setAuth((a) => ({ ...a, contributed: true }))}
        onLogout={logout}
      />
    );
  }
  return <CommunityView vorname={auth.vorname} onLogout={logout} />;
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
