// RIVA — Gestion de la carte depuis le tableau de bord
// Permet d'ajouter, modifier ou masquer un plat sans toucher au code.
// Ces changements sont enregistrés dans le navigateur, par-dessus carte.js.

const { useState: useMA, useEffect: useMAE, useMemo: useMAM, useRef: useMAR } = React;

/* ============================================================
   L'ORDRE DES FAMILLES

   C'est la première chose que voit un client qui clique sur « Commander ».
   Le restaurant doit pouvoir décider ce qui passe en premier sans appeler
   personne : la spécialité du moment, ce qu'il faut écouler, la saison.
   ============================================================ */

function OrdreFamilles({ onChange }) {
  const [ordre, setOrdre] = useMA(() => ordreFamilles().map(f => f.id));
  const [enregistre, setEnregistre] = useMA(false);

  const parId = Object.fromEntries(famillesEffectives().map(f => [f.id, f]));

  const appliquer = (nouveau) => {
    setOrdre(nouveau);
    enregistrerOrdreFamilles(nouveau);
    setEnregistre(true);
    setTimeout(() => setEnregistre(false), 1600);
    if (onChange) onChange();
  };

  const deplacer = (index, sens) => {
    const cible = index + sens;
    if (cible < 0 || cible >= ordre.length) return;
    const copie = ordre.slice();
    [copie[index], copie[cible]] = [copie[cible], copie[index]];
    appliquer(copie);
  };

  const remettre = () => {
    reinitialiserOrdreFamilles();
    const defaut = famillesEffectives().map(f => f.id);
    setOrdre(defaut);
    setEnregistre(true);
    setTimeout(() => setEnregistre(false), 1600);
    if (onChange) onChange();
  };

  return (
    <div className="admin-card">
      <div className="flex items-baseline justify-between gap-3 flex-wrap mb-1">
        <div>
          <div className="kicker !mb-0">Ordre de la carte</div>
          <p className="text-xs text-[var(--muted)] mt-1 max-w-md">
            L'ordre dans lequel les familles apparaissent quand un client ouvre la carte.
            La première est celle qu'on veut faire découvrir.
          </p>
        </div>
        <div className="flex items-center gap-3">
          {enregistre && <span className="text-xs text-[var(--jade)] font-semibold">Enregistré</span>}
          <button onClick={remettre} className="btn btn-ghost !py-2 !px-3 !text-xs">
            Remettre l'ordre d'origine
          </button>
        </div>
      </div>

      <ol className="mt-4 space-y-2">
        {ordre.map((id, i) => {
          const f = parId[id];
          if (!f) return null;
          return (
            <li key={id}
                className="flex items-center gap-3 bg-[var(--bg)] border border-[var(--line)] rounded-xl px-3 py-2.5">
              <span className="font-display text-xl text-[var(--vert)] w-6 shrink-0">{i + 1}</span>
              <div className="flex-1 min-w-0">
                <div className="font-display text-xl text-[var(--cream)] leading-none">{f.nom}</div>
                <div className="text-[11px] text-[var(--muted)] mt-0.5">{f.accroche}</div>
              </div>
              <div className="flex gap-1.5 shrink-0">
                <button onClick={() => deplacer(i, -1)} disabled={i === 0}
                        aria-label={`Monter ${f.nom}`}
                        className="btn btn-ghost !py-1.5 !px-3 !text-xs disabled:opacity-25 disabled:cursor-not-allowed">↑</button>
                <button onClick={() => deplacer(i, 1)} disabled={i === ordre.length - 1}
                        aria-label={`Descendre ${f.nom}`}
                        className="btn btn-ghost !py-1.5 !px-3 !text-xs disabled:opacity-25 disabled:cursor-not-allowed">↓</button>
              </div>
            </li>
          );
        })}
      </ol>

      <p className="text-[11px] text-[var(--muted)] mt-3">
        Ce réglage est mémorisé dans ce navigateur. Sur l'ordinateur de la caisse,
        c'est celui que verront tous les clients servis depuis ce poste.
      </p>
    </div>
  );
}


function MenuManager({ onChange }) {
  const [menu, setMenu] = useMA(() => getEffectiveMenu().menu);
  const [featuredId, setFeaturedId] = useMA(() => getEffectiveMenu().featuredId);
  const [editingItem, setEditingItem] = useMA(null); // { catId, item, isNew }
  const [activeCat, setActiveCat] = useMA(() => Object.keys(getEffectiveMenu().menu)[0]);
  const [confirmReset, setConfirmReset] = useMA(false);
  const [nouvelleRubrique, setNouvelleRubrique] = useMA(false);
  const [confirmSupprRubrique, setConfirmSupprRubrique] = useMA(false);
  const [versionFamilles, setVersionFamilles] = useMA(0);

  const reload = () => {
    const { menu, featuredId } = getEffectiveMenu();
    setMenu(menu);
    setFeaturedId(featuredId);
    if (onChange) onChange();
  };

  const startEdit = (catId, item) => {
    setEditingItem({ catId, item: { ...item }, isNew: false });
  };

  const startNew = (catId) => {
    setEditingItem({
      catId,
      isNew: true,
      item: {
        id: 'custom-' + Date.now(),
        name: '',
        tagline: '',
        desc: '',
        price: 0,
        img: '',
        composition: [],
        allergenes: [],
        halal: true,
        badges: [],
      },
    });
  };

  // catChoisie : la rubrique choisie dans le formulaire. Un plat ajouté au
  // tableau de bord peut changer de rubrique ; on le retire de l'ancienne.
  const saveItem = (item, catChoisie) => {
    const cat = catChoisie || editingItem.catId;
    if (cat !== editingItem.catId && !editingItem.isNew) deleteMenuItem(editingItem.catId, item.id);
    if (saveMenuItem(cat, item)) {
      setActiveCat(cat);
      reload();
      setEditingItem(null);
      showToast(editingItem.isNew ? 'Item ajouté au menu' : 'Item modifié');
    }
  };

  const deleteItem = (catId, itemId) => {
    if (deleteMenuItem(catId, itemId)) {
      reload();
      showToast('Item supprimé du menu');
    }
  };

  const toggleFeatured = (itemId) => {
    const newId = featuredId === itemId ? null : itemId;
    setPlatVedette(newId);
    setFeaturedId(newId);
    if (onChange) onChange();
    showToast(newId ? 'Plat mis en avant en haut du site' : 'Plus de plat en avant');
  };

  const basculerRupture = async (item) => {
    const enRupture = !item.rupture;
    const ok = await setRupture(item.id, enRupture);
    reload();
    showToast(!ok ? 'Non enregistré sur le restaurant — réessayez'
      : enRupture ? `${item.name} : en rupture` : `${item.name} : de nouveau disponible`);
  };

  const remettreTout = async () => {
    const ok = await viderRuptures();
    reload();
    showToast(ok ? 'Tous les plats sont de nouveau disponibles' : 'Non enregistré sur le restaurant — réessayez');
  };

  const enRupture = Object.values(menu).flatMap(c => c.items).filter(i => i.rupture);

  const creerRubrique = async (label, sub, famille) => {
    const { ok, id } = await ajouterRubrique(label, sub, famille);
    setNouvelleRubrique(false);
    reload();
    setActiveCat(id);
    setVersionFamilles(v => v + 1);
    showToast(ok ? `Catégorie « ${label} » créée : ajoutez-y vos plats` : 'Non enregistré sur le restaurant — réessayez');
  };

  const retirerRubrique = async (cat) => {
    const ok = await supprimerRubrique(cat.id);
    setConfirmSupprRubrique(false);
    reload();
    setActiveCat(Object.keys(getEffectiveMenu().menu)[0]);
    setVersionFamilles(v => v + 1);
    showToast(ok ? `Catégorie « ${cat.label} » supprimée` : 'Non enregistré sur le restaurant — réessayez');
  };

  const doReset = () => {
    resetMenuOverrides();
    setVersionFamilles(v => v + 1);
    reload();
    setConfirmReset(false);
    showToast('Menu réinitialisé');
  };

  const cats = Object.values(menu);
  const currentCat = cats.find(c => c.id === activeCat) || cats[0];

  return (
    <div className="mt-12">
      <div className="flex items-end justify-between gap-4 flex-wrap mb-4">
        <div>
          <h2 className="font-display text-3xl">Gérer le menu</h2>
          <p className="text-[var(--muted)] text-sm mt-1">Ajoute, modifie ou supprime des plats. Les changements s'appliquent tout de suite sur le site. Pour un changement définitif, modifie plutôt carte.js.</p>
        </div>
        <div className="flex gap-2 flex-wrap">
          <button onClick={() => startNew(activeCat)}
                  className="btn btn-primary !py-2 !px-4 !text-xs">
            <Icon.Plus className="w-4 h-4"/> Ajouter un item
          </button>
          <button onClick={() => setNouvelleRubrique(true)}
                  className="btn btn-ghost !py-2 !px-4 !text-xs">
            <Icon.Plus className="w-4 h-4"/> Ajouter une catégorie
          </button>
          {confirmReset ? (
            <>
              <button onClick={() => setConfirmReset(false)} className="btn btn-ghost !py-2 !px-3 !text-xs">Annuler</button>
              <button onClick={doReset} className="btn btn-rouge !py-2 !px-4 !text-xs">Confirmer la réinitialisation</button>
            </>
          ) : (
            <button onClick={() => setConfirmReset(true)} className="btn btn-ghost !py-2 !px-3 !text-xs"
                    title="Remet le menu aux valeurs d'origine">
              Réinitialiser
            </button>
          )}
        </div>
      </div>

      {/* Ce qui manque ce soir, visible d'un coup d'œil */}
      <div className={`mb-6 p-4 rounded-xl border ${enRupture.length ? 'border-[var(--rouge)] bg-[var(--rouge)]/10' : 'border-[var(--line)] bg-[var(--bg-2)]'}`}>
        <div className="flex items-center justify-between gap-3 flex-wrap">
          <div>
            <div className="font-display text-xl">Ruptures</div>
            <div className="text-xs text-[var(--muted)] mt-0.5">
              {enRupture.length
                ? `En rupture : ${enRupture.map(i => i.name).join(', ')}`
                : 'Tout est disponible. Pour retirer un plat le temps d’un service, touchez « En rupture » sur sa ligne.'}
            </div>
          </div>
          {enRupture.length > 0 && (
            <button onClick={remettreTout} className="btn btn-primary !py-2 !px-4 !text-xs">Tout remettre en vente</button>
          )}
        </div>
      </div>

      <div className="mb-6">
        <OrdreFamilles key={versionFamilles} onChange={onChange}/>
      </div>

      {/* Tabs catégories */}
      <div className="flex flex-wrap gap-1.5 pb-3 mb-5 border-b border-[var(--line)]">
        {cats.map(c => (
          <button key={c.id} onClick={() => setActiveCat(c.id)}
                  className={`px-4 py-2 rounded-full whitespace-nowrap font-display text-base tracking-wide transition-all shrink-0
                    ${activeCat === c.id
                      ? 'bg-[var(--vert)] text-[var(--bg)]'
                      : 'bg-transparent text-[var(--muted)] hover:text-[var(--cream)]'}`}>
            {c.label} <span className={`ml-1.5 text-[10px] font-bold ${activeCat === c.id ? 'text-[var(--bg)]/70' : 'text-[var(--muted)]/60'}`}>{c.items.length}</span>
            {c.items.some(i => i.rupture) && <span className="ml-1 inline-block w-2 h-2 rounded-full bg-[var(--rouge)] align-middle"/>}
          </button>
        ))}
      </div>

      {/* Une catégorie créée ici peut être supprimée (les plats de carte.js, non) */}
      {currentCat.perso && (
        <div className="flex items-center justify-between gap-3 flex-wrap mb-4 p-3 rounded-xl border border-[var(--line)] bg-[var(--bg-2)]">
          <div className="text-xs text-[var(--muted)]">
            Catégorie ajoutée au tableau de bord{currentCat.sub ? ` · « ${currentCat.sub} »` : ''}.
            {currentCat.items.length === 0 && ' Elle est vide : les clients ne la voient pas encore. Ajoutez-y un plat.'}
          </div>
          {confirmSupprRubrique ? (
            <div className="flex gap-2 items-center flex-wrap">
              <span className="text-xs text-[var(--cream-2)]">Supprimer la catégorie{currentCat.items.length ? ` et ses ${currentCat.items.length} plat(s)` : ''} ?</span>
              <button onClick={() => setConfirmSupprRubrique(false)} className="btn btn-ghost !py-2 !px-3 !text-xs">Annuler</button>
              <button onClick={() => retirerRubrique(currentCat)} className="btn !py-2 !px-3 !text-xs bg-[var(--rouge)] text-white">Oui, supprimer</button>
            </div>
          ) : (
            <button onClick={() => setConfirmSupprRubrique(true)} className="btn btn-ghost !py-2 !px-3 !text-xs">Supprimer cette catégorie</button>
          )}
        </div>
      )}

      {/* Liste des items de la catégorie active */}
      <div className="space-y-2">
        {currentCat.items.map(item => (
          <ItemRow
            key={item.id}
            item={item}
            isFeatured={featuredId === item.id}
            isSignature={currentCat.id === 'signature'}
            onEdit={() => startEdit(currentCat.id, item)}
            onDelete={() => deleteItem(currentCat.id, item.id)}
            onToggleFeatured={() => toggleFeatured(item.id)}
            onToggleRupture={() => basculerRupture(item)}
          />
        ))}
        {currentCat.items.length === 0 && (
          <div className="text-center py-10 text-[var(--muted)] text-sm">
            Aucun item dans cette catégorie. Clique "Ajouter un item" pour commencer.
          </div>
        )}
      </div>

      {nouvelleRubrique && (
        <RubriqueEditor onSave={creerRubrique} onCancel={() => setNouvelleRubrique(false)}/>
      )}

      {editingItem && (
        <ItemEditor
          catId={editingItem.catId}
          item={editingItem.item}
          isNew={editingItem.isNew}
          onSave={saveItem}
          onCancel={() => setEditingItem(null)}
        />
      )}

      {/* Le petit mot manuscrit du haut de page : on le met ou on ne le met pas. */}
      <HeroMessageAdmin onChange={onChange}/>

      {/* Les autres textes du haut de page : pastilles, titre, présentation. */}
      <HeroTextesAdmin onChange={onChange}/>
    </div>
  );
}

/* ---------- Message du haut de page ----------
   Deux choix nets : on affiche un message, ou on n'en affiche pas. Couper
   le message ne jette pas le texte : on peut le rallumer tel quel. Pour
   l'effacer vraiment, il y a « Supprimer le message ». */

function Interrupteur({ actif, onClick, libelleOui, libelleNon }) {
  return (
    <div className="inline-flex rounded-xl border border-[var(--line)] p-1 bg-[var(--bg)]" role="radiogroup">
      <button type="button" role="radio" aria-checked={actif} onClick={() => onClick(true)}
              className={`px-4 py-2 rounded-lg text-xs font-bold uppercase tracking-wider transition-colors
                ${actif ? 'bg-[var(--vert)] text-[var(--bg)]' : 'text-[var(--muted)] hover:text-[var(--cream)]'}`}>
        {libelleOui}
      </button>
      <button type="button" role="radio" aria-checked={!actif} onClick={() => onClick(false)}
              className={`px-4 py-2 rounded-lg text-xs font-bold uppercase tracking-wider transition-colors
                ${!actif ? 'bg-[var(--cream-2)] text-[var(--bg)]' : 'text-[var(--muted)] hover:text-[var(--cream)]'}`}>
        {libelleNon}
      </button>
    </div>
  );
}

function EtatEnvoi({ etat }) {
  if (etat === 'envoi') return <span className="text-xs text-[var(--muted)]">Envoi au restaurant…</span>;
  if (etat === 'ok') return <span className="text-xs text-[var(--jade)] font-semibold">✓ Enregistré, visible par les clients</span>;
  if (etat === 'erreur') return <span className="text-xs text-[var(--rouge)] font-semibold">Non enregistré sur le restaurant</span>;
  return null;
}

function HeroMessageAdmin({ onChange }) {
  const [quote, setQuote] = useMA(() => getHeroQuote());
  const [etat, setEtat] = useMA(null);   // null | 'envoi' | 'ok' | 'erreur'
  const [confirmSuppr, setConfirmSuppr] = useMA(false);

  const enregistrer = async (q, message) => {
    setQuote(q);
    setEtat('envoi');
    const ok = await setHeroQuote(q);
    setEtat(ok ? 'ok' : 'erreur');
    if (onChange) onChange();
    if (ok) showToast(message);
    setTimeout(() => setEtat(e => (e === 'ok' ? null : e)), 2500);
  };

  const actif = quote.actif !== false;

  return (
    <div className="mt-10 admin-card">
      <div className="flex items-start gap-3 mb-5">
        <Icon.Sparkles className="w-5 h-5 text-[var(--vert)] shrink-0 mt-0.5"/>
        <div className="flex-1">
          <h3 className="font-display text-xl">Message du haut de page</h3>
          <p className="text-xs text-[var(--muted)] mt-1">
            La petite note manuscrite posée sur la photo du plat vedette. Un slogan, une promo, un mot de bienvenue… ou rien du tout.
          </p>
        </div>
      </div>

      <div className="flex flex-wrap items-center gap-3 mb-5">
        <span className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)]">Afficher un message</span>
        <Interrupteur actif={actif} libelleOui="Oui" libelleNon="Non"
                      onClick={(oui) => enregistrer({ ...quote, actif: oui },
                                 oui ? 'Message affiché sur le site' : 'Message retiré du site')}/>
      </div>

      <div className={actif ? '' : 'opacity-40 pointer-events-none select-none'} aria-disabled={!actif}>
        <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-1.5 block">Ton message</label>
        <textarea value={quote.line1 || ''}
                  onChange={(e) => { setQuote({ ...quote, line1: e.target.value, line2: '' }); setEtat(null); }}
                  rows="3"
                  placeholder='Ex : "Nouveau : plateau à partager"'
                  className="w-full px-3 py-2.5 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)] text-2xl leading-tight resize-none"
                  style={{ fontFamily: "'Caveat', cursive" }}/>
        <div className="text-[10px] text-[var(--muted)] mt-1">Saute des lignes avec Entrée si tu veux. Un message vide n'est pas affiché.</div>

        <label className="text-[10px] uppercase tracking-wider text-[var(--muted)] font-bold mb-1.5 mt-3 block">Signature (facultatif)</label>
        <input type="text" value={quote.author || ''}
               onChange={(e) => { setQuote({ ...quote, author: e.target.value }); setEtat(null); }}
               placeholder="— Marine, Google ⭐⭐⭐⭐⭐"
               className="w-full px-3 py-2 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)] text-sm"/>
      </div>

      <div className="mt-4 flex flex-wrap items-center gap-3">
        <button onClick={() => enregistrer(quote, 'Message mis à jour')} disabled={!actif || etat === 'envoi'}
                className="btn btn-primary !py-2 !px-4 !text-xs disabled:opacity-40">
          <Icon.Check className="w-4 h-4"/> Enregistrer
        </button>
        {confirmSuppr ? (
          <>
            <span className="text-xs text-[var(--cream-2)]">Effacer le texte et retirer le message ?</span>
            <button onClick={() => { setConfirmSuppr(false); enregistrer({ actif: false, line1: '', line2: '', author: '' }, 'Message supprimé'); }}
                    className="btn !py-2 !px-4 !text-xs bg-[var(--rouge)] text-white">Oui, supprimer</button>
            <button onClick={() => setConfirmSuppr(false)} className="btn btn-ghost !py-2 !px-4 !text-xs">Annuler</button>
          </>
        ) : (
          <button onClick={() => setConfirmSuppr(true)} className="btn btn-ghost !py-2 !px-4 !text-xs">
            Supprimer le message
          </button>
        )}
        <EtatEnvoi etat={etat}/>
      </div>
    </div>
  );
}

/* ---------- Textes du haut de page ---------- */

const CHAMPS_HERO = [
  { cle: 'pastille1', libelle: 'Pastille 1', aide: 'Ex : 100% Halal. Vide = pas de pastille.' },
  { cle: 'pastille2', libelle: 'Pastille 2', aide: 'Ex : Denain · 59220. Vide = pas de pastille.' },
  { cle: 'titre1', libelle: 'Grand titre — ligne 1', aide: 'En blanc.' },
  { cle: 'titre2', libelle: 'Grand titre — ligne 2', aide: 'En couleur. Vide = pas de deuxième ligne.' },
  { cle: 'signature', libelle: 'Petite ligne manuscrite', aide: 'Sous le titre. Vide = rien.' },
  { cle: 'texte', libelle: 'Phrase de présentation', aide: '', long: true },
  { cle: 'texteFort', libelle: 'Fin de phrase mise en avant', aide: 'Écrite en couleur, en gras. Vide = rien.' },
];

function HeroTextesAdmin({ onChange }) {
  const [textes, setTextes] = useMA(() => getHeroTextes());
  const [etat, setEtat] = useMA(null);

  const envoyer = async (fn, message) => {
    setEtat('envoi');
    const ok = await fn();
    setEtat(ok ? 'ok' : 'erreur');
    if (onChange) onChange();
    if (ok) showToast(message);
    setTimeout(() => setEtat(e => (e === 'ok' ? null : e)), 2500);
  };

  const changer = (cle, valeur) => { setTextes({ ...textes, [cle]: valeur }); setEtat(null); };

  return (
    <div className="mt-6 admin-card">
      <div className="flex items-start gap-3 mb-5">
        <Icon.Sparkles className="w-5 h-5 text-[var(--vert)] shrink-0 mt-0.5"/>
        <div className="flex-1">
          <h3 className="font-display text-xl">Textes du haut de page</h3>
          <p className="text-xs text-[var(--muted)] mt-1">Les pastilles, le grand titre et la phrase d'accueil.</p>
        </div>
      </div>

      <div className="grid md:grid-cols-2 gap-4">
        {CHAMPS_HERO.map(ch => (
          <div key={ch.cle} className={ch.long ? 'md:col-span-2' : ''}>
            <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-1.5 block">{ch.libelle}</label>
            {ch.long ? (
              <textarea value={textes[ch.cle]} rows="3"
                        onChange={(e) => changer(ch.cle, e.target.value)}
                        className="w-full px-3 py-2.5 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)] text-sm resize-none"/>
            ) : (
              <input type="text" value={textes[ch.cle]}
                     onChange={(e) => changer(ch.cle, e.target.value)}
                     placeholder={TEXTES_HERO_DEFAUT[ch.cle]}
                     className="w-full px-3 py-2 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)] text-sm"/>
            )}
            {ch.aide && <div className="text-[10px] text-[var(--muted)] mt-1">{ch.aide}</div>}
          </div>
        ))}
      </div>

      <div className="mt-5 flex flex-wrap items-center gap-3">
        <button onClick={() => {
                  if (!textes.titre1.trim()) { showToast('Le grand titre ne peut pas être vide.'); return; }
                  envoyer(() => setHeroTextes(textes), 'Textes mis à jour');
                }}
                disabled={etat === 'envoi'}
                className="btn btn-primary !py-2 !px-4 !text-xs disabled:opacity-40">
          <Icon.Check className="w-4 h-4"/> Enregistrer
        </button>
        <button onClick={() => { setTextes({ ...TEXTES_HERO_DEFAUT }); envoyer(resetHeroTextes, "Textes d'origine remis"); }}
                className="btn btn-ghost !py-2 !px-4 !text-xs">
          Remettre les textes d'origine
        </button>
        <EtatEnvoi etat={etat}/>
      </div>
    </div>
  );
}

function ItemRow({ item, isFeatured, isSignature, onEdit, onDelete, onToggleFeatured, onToggleRupture }) {
  const [confirmDel, setConfirmDel] = useMA(false);
  const isCustom = item.id.startsWith('custom-');

  return (
    <div className={`flex items-center gap-3 p-3 rounded-xl border transition-colors flex-wrap sm:flex-nowrap
      ${item.rupture ? 'border-[var(--rouge)] bg-[var(--rouge)]/10' : isFeatured ? 'border-[var(--vert)] bg-[var(--vert)]/5' : 'border-[var(--line)] bg-[var(--bg-2)]'}`}>
      <div className="w-14 h-14 rounded-lg shrink-0 bg-cover bg-center bg-[var(--bg-3)] flex items-center justify-center overflow-hidden border border-[var(--line)]"
           style={{ backgroundImage: item.img ? `url(${item.img})` : 'none' }}>
        {!item.img && (
          <svg viewBox="0 0 24 24" className="w-5 h-5 text-[var(--muted)]" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
            <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/>
            <circle cx="12" cy="13" r="4"/>
          </svg>
        )}
      </div>
      <div className="flex-1 min-w-0">
        <div className="flex items-center gap-2 flex-wrap">
          <span className="font-display text-lg leading-tight">{item.name || '(sans nom)'}</span>
          {isCustom && <span className="pill new !text-[9px] !py-0 !px-1.5">Custom</span>}
          {isFeatured && <span className="pill !text-[9px] !py-0 !px-1.5 bg-[var(--vert)] text-[var(--bg)] border-[var(--vert)]">⭐ En vedette</span>}
          {item.rupture && <span className="pill !text-[9px] !py-0 !px-1.5 bg-[var(--rouge)] text-white border-[var(--rouge)]">En rupture</span>}
          {item.badges?.includes('hot') && <span className="pill hot !text-[9px] !py-0 !px-1.5">Hot</span>}
          {item.badges?.includes('veg') && <span className="pill veg !text-[9px] !py-0 !px-1.5">Veg</span>}
        </div>
        <div className="text-xs text-[var(--muted)] truncate">{item.desc || item.tagline || 'Pas de description'}</div>
      </div>
      <div className="font-display text-lg text-[var(--vert)] shrink-0">{Number(item.price).toFixed(2)}€</div>
      <div className="flex gap-1 shrink-0 items-center">
        <button onClick={onToggleRupture}
                title={item.rupture ? 'Remettre en vente' : 'Mettre en rupture'}
                className={`h-9 px-3 rounded-full text-[11px] font-bold uppercase tracking-wider border transition-colors whitespace-nowrap
                  ${item.rupture
                    ? 'bg-[var(--vert)] text-[var(--bg)] border-[var(--vert)]'
                    : 'border-[var(--rouge)] text-[var(--rouge-2)] hover:bg-[var(--rouge)] hover:text-white'}`}>
          {item.rupture ? 'Remettre en vente' : 'En rupture'}
        </button>
        {isSignature && (
          <button onClick={onToggleFeatured}
                  title={isFeatured ? 'Retirer de la une' : 'Mettre en vedette dans le hero'}
                  className={`w-9 h-9 rounded-full flex items-center justify-center border transition-colors
                    ${isFeatured
                      ? 'bg-[var(--vert)] text-[var(--bg)] border-[var(--vert)]'
                      : 'border-[var(--line)] text-[var(--muted)] hover:border-[var(--vert)] hover:text-[var(--vert)]'}`}>
            <Icon.Star className="w-4 h-4"/>
          </button>
        )}
        <button onClick={onEdit}
                title="Modifier"
                className="w-9 h-9 rounded-full border border-[var(--line)] text-[var(--cream-2)] hover:border-[var(--cream)] flex items-center justify-center">
          <Icon.Sliders className="w-4 h-4"/>
        </button>
        {confirmDel ? (
          <>
            <button onClick={() => setConfirmDel(false)} title="Annuler"
                    className="w-9 h-9 rounded-full border border-[var(--line)] flex items-center justify-center">
              <Icon.Close className="w-4 h-4"/>
            </button>
            <button onClick={() => { onDelete(); setConfirmDel(false); }} title="Confirmer la suppression"
                    className="w-9 h-9 rounded-full bg-[var(--rouge)] text-white flex items-center justify-center">
              <Icon.Check className="w-4 h-4"/>
            </button>
          </>
        ) : (
          <button onClick={() => setConfirmDel(true)}
                  title="Supprimer"
                  className="w-9 h-9 rounded-full border border-[var(--line)] text-[var(--muted)] hover:border-[var(--rouge)] hover:text-[var(--rouge-2)] flex items-center justify-center">
            <Icon.Trash className="w-4 h-4"/>
          </button>
        )}
      </div>
    </div>
  );
}

/* ---------- Nouvelle catégorie ----------
   Dans une famille existante (« Pizzas › Les Calzones »), ou comme une
   nouvelle famille avec sa propre case sur la carte (« Salades »). */
function RubriqueEditor({ onSave, onCancel }) {
  const [label, setLabel] = useMA('');
  const [sub, setSub] = useMA('');
  const [famille, setFamille] = useMA('__nouvelle');
  const [envoi, setEnvoi] = useMA(false);
  const familles = famillesEffectives();

  const valider = async (e) => {
    e.preventDefault();
    if (!label.trim()) { showToast('Le nom de la catégorie est obligatoire'); return; }
    setEnvoi(true);
    await onSave(label.trim(), sub.trim(), famille === '__nouvelle' ? null : famille);
    setEnvoi(false);
  };

  const champ = 'w-full px-3 py-2.5 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)]';
  return (
    <div className="fixed inset-0 z-[200] voile-fonce backdrop-blur-sm flex items-center justify-center p-3 md:p-6" onClick={onCancel}>
      <form onSubmit={valider} onClick={(e) => e.stopPropagation()}
            className="w-full max-w-[560px] bg-[var(--bg-2)] rounded-3xl border border-[var(--line)] p-6 space-y-4">
        <div>
          <div className="kicker">Nouvelle catégorie</div>
          <h3 className="font-display text-3xl mt-1">{label || 'Nouvelle catégorie'}</h3>
        </div>
        <div>
          <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-1.5 block">Nom <span className="text-[var(--rouge-2)]">*</span></label>
          <input type="text" value={label} onChange={(e) => setLabel(e.target.value)} required autoFocus
                 placeholder="ex : Les Calzones, Salades, Menus enfant" className={champ}/>
        </div>
        <div>
          <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-1.5 block">Petite phrase (facultatif)</label>
          <input type="text" value={sub} onChange={(e) => setSub(e.target.value)}
                 placeholder="ex : Pliées et dorées au four" className={champ}/>
        </div>
        <div>
          <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-1.5 block">Où la mettre sur la carte ?</label>
          <select value={famille} onChange={(e) => setFamille(e.target.value)} className={champ}>
            <option value="__nouvelle">Sa propre case sur la carte (nouvelle famille)</option>
            {familles.map(f => <option key={f.id} value={f.id}>Dans « {f.nom} », avec les autres</option>)}
          </select>
          <div className="text-[10px] text-[var(--muted)] mt-1">
            {famille === '__nouvelle'
              ? 'Une nouvelle case apparaît sur la carte, à la fin. Vous pouvez la déplacer dans « Ordre de la carte ».'
              : 'La catégorie apparaît comme un onglet de plus dans cette famille.'}
            {' '}Elle reste invisible pour les clients tant qu'elle n'a aucun plat.
          </div>
        </div>
        <div className="flex items-center justify-between gap-3 pt-2">
          <button type="button" onClick={onCancel} className="btn btn-ghost !py-3 !px-5">Annuler</button>
          <button type="submit" disabled={envoi} className="btn btn-primary !py-3 !px-6 disabled:opacity-40">
            <Icon.Check className="w-4 h-4"/> Créer la catégorie
          </button>
        </div>
      </form>
    </div>
  );
}

/* Les rubriques rangées par famille, comme le client les voit :
   « Pizzas › Les Classiques », « Pizzas › Les Signatures »… */
function rubriquesParFamille() {
  const menu = getEffectiveMenu().menu;
  const vues = new Set();
  const groupes = famillesEffectives().map(f => {
    const rubriques = f.categories.filter(id => menu[id]).map(id => { vues.add(id); return menu[id]; });
    return { nom: f.nom, rubriques };
  }).filter(g => g.rubriques.length);
  const autres = Object.values(menu).filter(c => !vues.has(c.id));
  if (autres.length) groupes.push({ nom: 'Autres', rubriques: autres });
  return groupes;
}

function ItemEditor({ catId, item, isNew, onSave, onCancel }) {
  const [form, setForm] = useMA(item);
  const [rubrique, setRubrique] = useMA(catId);
  // Les plats de carte.js restent dans leur rubrique ; ceux ajoutés ici se déplacent.
  const peutChangerRubrique = isNew || String(item.id).startsWith('custom-');
  const [imgPreview, setImgPreview] = useMA(item.img || '');
  const [imgError, setImgError] = useMA(false);
  const fileInputRef = useMAR(null);

  useMAE(() => {
    document.body.style.overflow = 'hidden';
    return () => { document.body.style.overflow = ''; };
  }, []);

  const setField = (k, v) => setForm(prev => ({ ...prev, [k]: v }));

  const onFile = (e) => {
    const file = e.target.files?.[0];
    if (!file) return;
    if (file.size > 1.5 * 1024 * 1024) {
      showToast('Image trop lourde (max 1.5 Mo). Réduis-la avant.');
      return;
    }
    const reader = new FileReader();
    reader.onload = () => {
      const data = reader.result;
      setField('img', data);
      setImgPreview(data);
      setImgError(false);
    };
    reader.readAsDataURL(file);
  };

  const submit = (e) => {
    e.preventDefault();
    if (!form.name?.trim()) {
      showToast('Le nom est obligatoire');
      return;
    }
    if (!form.price || isNaN(form.price)) {
      showToast('Le prix est obligatoire');
      return;
    }
    const cleaned = {
      ...form,
      price: parseFloat(form.price),
      composition: Array.isArray(form.composition) ? form.composition : (form.composition || '').split(',').map(s => s.trim()).filter(Boolean),
      allergenes: Array.isArray(form.allergenes) ? form.allergenes : (form.allergenes || '').split(',').map(s => s.trim()).filter(Boolean),
    };
    onSave(cleaned, rubrique);
  };

  const toggleBadge = (badge) => {
    const badges = form.badges || [];
    setField('badges', badges.includes(badge) ? badges.filter(b => b !== badge) : [...badges, badge]);
  };

  return (
    <div className="fixed inset-0 z-[200] voile-fonce backdrop-blur-sm flex items-center justify-center p-3 md:p-6"
         onClick={onCancel}>
      <div onClick={(e) => e.stopPropagation()}
           className="w-full max-w-[720px] max-h-[92vh] bg-[var(--bg-2)] rounded-3xl border border-[var(--line)] flex flex-col overflow-hidden">
        <form onSubmit={submit} className="contents">
          <div className="px-6 py-5 border-b border-[var(--line)] flex items-center justify-between shrink-0">
            <div>
              <div className="kicker">{isNew ? 'Nouvel item' : 'Modifier'}</div>
              <h3 className="font-display text-3xl mt-1">{form.name || (isNew ? 'Nouveau plat' : '…')}</h3>
            </div>
            <button type="button" onClick={onCancel}
                    className="w-10 h-10 rounded-full bg-[var(--bg)] flex items-center justify-center hover:bg-[var(--bg-3)]">
              <Icon.Close className="w-5 h-5"/>
            </button>
          </div>

          <div className="overflow-y-auto flex-1 p-6 space-y-5">
            {/* Image */}
            <div>
              <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-2 block">Photo</label>
              <div className="flex gap-3">
                <div className="relative shrink-0">
                  <div className="w-28 h-28 rounded-xl bg-cover bg-center bg-[var(--bg)] border border-[var(--line)] flex items-center justify-center overflow-hidden"
                       style={{ backgroundImage: imgPreview && !imgError ? `url(${imgPreview})` : 'none' }}>
                    {(!imgPreview || imgError) && (
                      <div className="text-[var(--muted)] text-xs text-center px-2">Pas de photo</div>
                    )}
                  </div>
                  {imgPreview && (
                    <button type="button"
                            onClick={() => { setField('img', ''); setImgPreview(''); setImgError(false); if (fileInputRef.current) fileInputRef.current.value = ''; }}
                            title="Supprimer la photo"
                            className="absolute -top-2 -right-2 w-7 h-7 rounded-full bg-[var(--rouge)] text-white flex items-center justify-center shadow-lg hover:bg-[var(--rouge-2)] transition-colors">
                      <Icon.Close className="w-4 h-4"/>
                    </button>
                  )}
                </div>
                <div className="flex-1 space-y-2">
                  <input type="url" value={form.img?.startsWith('data:') ? '' : (form.img || '')}
                         onChange={(e) => { setField('img', e.target.value); setImgPreview(e.target.value); setImgError(false); }}
                         placeholder="Coller une URL d'image…"
                         className="w-full px-3 py-2 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)] text-sm"/>
                  <div className="text-xs text-[var(--muted)] text-center">— ou —</div>
                  <input ref={fileInputRef} type="file" accept="image/*" onChange={onFile} className="hidden"/>
                  <button type="button" onClick={() => fileInputRef.current?.click()}
                          className="w-full btn btn-ghost !py-2 !text-xs flex items-center justify-center gap-2">
                    <svg viewBox="0 0 24 24" className="w-4 h-4" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                      <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/>
                      <circle cx="12" cy="13" r="4"/>
                    </svg>
                    Choisir une photo depuis l'ordinateur
                  </button>
                  <div className="text-[10px] text-[var(--muted)]">Max 1.5 Mo. Format carré ou 4:3 idéalement.</div>
                </div>
              </div>
              {imgPreview && (
                <img src={imgPreview} alt="" onError={() => setImgError(true)} onLoad={() => setImgError(false)}
                     style={{ display: 'none' }}/>
              )}
            </div>

            {/* Rubrique : où le plat apparaît sur la carte */}
            <div>
              <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-1.5 block">
                Catégorie <span className="text-[var(--rouge-2)]">*</span>
              </label>
              {peutChangerRubrique ? (
                <select value={rubrique} onChange={(e) => setRubrique(e.target.value)}
                        className="w-full px-3 py-2.5 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)]">
                  {rubriquesParFamille().map(g => (
                    <optgroup key={g.nom} label={g.nom}>
                      {g.rubriques.map(r => <option key={r.id} value={r.id}>{g.nom} › {r.label}</option>)}
                    </optgroup>
                  ))}
                </select>
              ) : (
                <div className="px-3 py-2.5 bg-[var(--bg)] border border-[var(--line)] rounded-lg text-[var(--muted)] text-sm">
                  {(rubriquesParFamille().flatMap(g => g.rubriques.map(r => ({ g, r }))).find(x => x.r.id === rubrique) || {}).r?.label || rubrique}
                  <span className="text-[10px] ml-2">(plat de la carte d'origine : il reste dans sa catégorie)</span>
                </div>
              )}
              <div className="text-[10px] text-[var(--muted)] mt-1">Le plat apparaît dans cette catégorie de la carte, avec les autres.</div>
            </div>

            {/* Nom + tagline */}
            <div className="grid sm:grid-cols-2 gap-3">
              <div>
                <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-1.5 block">Nom <span className="text-[var(--rouge-2)]">*</span></label>
                <input type="text" value={form.name || ''} onChange={(e) => setField('name', e.target.value)} required
                       placeholder="ex : Roll saumon avocat"
                       className="w-full px-3 py-2.5 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)]"/>
              </div>
              <div>
                <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-1.5 block">Prix (€) <span className="text-[var(--rouge-2)]">*</span></label>
                <input type="number" step="0.10" min="0" value={form.price || ''} onChange={(e) => setField('price', e.target.value)} required
                       placeholder="9.90"
                       className="w-full px-3 py-2.5 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)] font-mono"/>
              </div>
            </div>

            <div>
              <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-1.5 block">Phrase d'accroche (facultatif)</label>
              <input type="text" value={form.tagline || ''} onChange={(e) => setField('tagline', e.target.value)}
                     placeholder="ex : le best-seller de la maison"
                     className="w-full px-3 py-2.5 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)]"/>
            </div>

            <div>
              <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-1.5 block">Description</label>
              <textarea value={form.desc || ''} onChange={(e) => setField('desc', e.target.value)}
                        rows="3"
                        placeholder="8 pièces, saumon, avocat, cheese, sauce spicy maison"
                        className="w-full px-3 py-2.5 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)] resize-none"/>
            </div>

            <div>
              <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-1.5 block">
                Composition (sépare par des virgules)
              </label>
              <textarea value={Array.isArray(form.composition) ? form.composition.join(', ') : (form.composition || '')}
                        onChange={(e) => setField('composition', e.target.value)}
                        rows="2"
                        placeholder="Riz vinaigré, Saumon, Avocat, Cheese, Sésame"
                        className="w-full px-3 py-2.5 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)] resize-none text-sm"/>
              <div className="text-[10px] text-[var(--muted)] mt-1">Le client pourra retirer ces ingrédients à la commande.</div>
            </div>

            <div>
              <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-1.5 block">
                Allergènes (sépare par des virgules)
              </label>
              <input type="text" value={Array.isArray(form.allergenes) ? form.allergenes.join(', ') : (form.allergenes || '')}
                     onChange={(e) => setField('allergenes', e.target.value)}
                     placeholder="poisson cru, gluten, soja, sésame, lactose"
                     className="w-full px-3 py-2.5 bg-[var(--bg)] border border-[var(--line)] rounded-lg focus:border-[var(--vert)] outline-none text-[var(--cream)] font-mono text-sm"/>
            </div>

            <div>
              <label className="text-xs font-bold uppercase tracking-wider text-[var(--cream-2)] mb-2 block">Étiquettes</label>
              <div className="flex flex-wrap gap-2">
                {[
                  { id: 'signature', label: 'Signature', icon: (
                    <svg viewBox="0 0 24 24" className="w-3.5 h-3.5" fill="currentColor"><path d="M12 2l3 7h7l-5.5 4.5L18 21l-6-4-6 4 1.5-7.5L2 9h7z"/></svg>
                  )},
                  { id: 'hot', label: 'Épicé', icon: (
                    <svg viewBox="0 0 24 24" className="w-3.5 h-3.5" fill="currentColor"><path d="M8.5 14.5c0-2 1.5-3 1.5-4.5C10 8 8 6.5 8 6.5s2 0 3.5 1.5C13 5.5 12 2 12 2s4 3.5 4 7c0 0 1-1 1.5-2 .5 2 1 4 1 5.5 0 3.5-3 6.5-6.5 6.5S5 16 5 13.5s2-3.5 2-3.5-.5 2 1.5 4.5z"/></svg>
                  )},
                  { id: 'new', label: 'Nouveau', icon: (
                    <svg viewBox="0 0 24 24" className="w-3.5 h-3.5" fill="currentColor"><path d="M12 2l1.5 5.5L19 9l-5.5 1.5L12 16l-1.5-5.5L5 9l5.5-1.5z" opacity="0.95"/><path d="M19 14l.7 2.3L22 17l-2.3.7L19 20l-.7-2.3L16 17l2.3-.7z" opacity="0.7"/></svg>
                  )},
                  { id: 'veg', label: 'Sans viande', icon: (
                    <svg viewBox="0 0 24 24" className="w-3.5 h-3.5" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12s2-9 9-9 9 9 9 9-2 9-9 9-9-9-9-9z"/><path d="M9 12l2 2 4-4"/></svg>
                  )},
                ].map(b => (
                  <button key={b.id} type="button" onClick={() => toggleBadge(b.id)}
                          className={`px-3 py-1.5 rounded-full text-xs font-semibold border transition-all flex items-center gap-1.5
                            ${(form.badges || []).includes(b.id)
                              ? 'border-[var(--vert)] bg-[var(--vert)]/15 text-[var(--vert)]'
                              : 'border-[var(--line)] text-[var(--muted)] hover:border-[var(--cream)]/30'}`}>
                    {b.icon}
                    {b.label}
                  </button>
                ))}
              </div>
            </div>

            <label className="flex items-center gap-3 cursor-pointer">
              <input type="checkbox" checked={form.halal !== false}
                     onChange={(e) => setField('halal', e.target.checked)}
                     className="w-5 h-5 accent-[var(--vert)]"/>
              <span className="text-sm">Halal</span>
            </label>
          </div>

          <div className="px-6 py-4 border-t border-[var(--line)] flex items-center justify-between gap-3 shrink-0 bg-[var(--bg)]/50">
            <button type="button" onClick={onCancel} className="btn btn-ghost !py-3 !px-5">Annuler</button>
            <button type="submit" className="btn btn-primary !py-3 !px-6 flex-1 sm:flex-none">
              <Icon.Check className="w-4 h-4"/>
              {isNew ? 'Ajouter au menu' : 'Enregistrer'}
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

Object.assign(window, { MenuManager, ItemRow, ItemEditor, OrdreFamilles, RubriqueEditor });
