// Caffè Italia · back-office
// ==========================
// Catalogue, demandes pro et commandes. Tout est lu et écrit dans Supabase ;
// `caffe_products_override` en localStorage n'est plus qu'un vestige, migré
// une fois puis effacé (voir legacyReadOverrides).
//
// Accès : compte Supabase dont l'email figure dans `admin_emails`. C'est la
// même condition que les policies RLS (`is_admin()`), donc l'écran et la
// base ne peuvent pas diverger — un écran ouvert par erreur ne donnerait
// aucun droit d'écriture. Il n'y a plus de mot de passe partagé : c'était
// un simple drapeau en sessionStorage, posable depuis la console.
//
// Donner l'accès à quelqu'un = ajouter son email dans `admin_emails`.
//
// URL : #/fr/admin   (ou #/it/admin)

const STORAGE_KEY    = "caffe_products_override";

const { useState: _aUseState, useEffect: _aUseEffect, useMemo: _aUseMemo } = React;

// Message éphémère du back-office (« Produit enregistré », …). Vivait dans
// components.jsx tant que la boutique s'en servait pour l'ajout au panier ;
// l'admin est désormais le seul appelant, il l'héberge.
function AdminToast({ msg, onClose }){
  _aUseEffect(()=>{
    if(!msg) return;
    const id = setTimeout(onClose, 2400);
    return ()=>clearTimeout(id);
  },[msg]);
  return (
    <div style={{
      position:"fixed",bottom:24,left:"50%",transform:`translateX(-50%) translateY(${msg?0:80}px)`,
      opacity:msg?1:0,transition:"all .3s cubic-bezier(.2,.7,.2,1)",pointerEvents:"none",
      zIndex:100,
    }}>
      <div style={{
        background:"var(--ink)",color:"var(--paper)",borderRadius:99,
        padding:"12px 22px",fontSize:13,fontWeight:600,letterSpacing:".02em",
        display:"flex",alignItems:"center",gap:10,
        boxShadow:"0 12px 40px rgba(0,0,0,.25)",
      }}>
        <span style={{color:"var(--rosso)"}}>✦</span> {msg}
      </div>
    </div>
  );
}

// ─── Supabase product CRUD ────────────────────────────────────────────
// Schema mapping: Supabase row (snake_case, separate _fr/_it cols) ↔
// in-app product object (camelCase, { fr, it } sub-objects, palette as array).
function rowToProduct(row){
  return {
    id: row.id,
    name:    { fr: row.name_fr || "",  it: row.name_it || "" },
    sub:     { fr: row.sub_fr  || "",  it: row.sub_it  || "" },
    tasting: { fr: row.tasting_fr||"", it: row.tasting_it||"" },
    badge:   row.badge_fr || row.badge_it
               ? { fr: row.badge_fr||"", it: row.badge_it||"" }
               : null,
    price:    Number(row.price) || 0,
    weight:   row.weight || "",
    weightIt: row.weight_it || "",
    images:   Array.isArray(row.images) ? row.images.filter(Boolean) : [],
    intensity: row.intensity ?? null,
    category:  row.category || "",
    variantGroup: row.variant_group || "",
    image:     row.image || "",
    palette:   Array.isArray(row.palette) ? row.palette : ["#0e0d0c","#c8202c","#f4ede0"],
    active:    row.active !== false,
    sort:      row.sort ?? 0,
    stripePriceId: row.stripe_price_id || "",
  };
}
function productToRow(p){
  return {
    id: p.id,
    name_fr: p.name?.fr || "",   name_it: p.name?.it || "",
    sub_fr:  p.sub?.fr  || null, sub_it:  p.sub?.it  || null,
    tasting_fr: p.tasting?.fr || null, tasting_it: p.tasting?.it || null,
    badge_fr:   p.badge?.fr || null,   badge_it:   p.badge?.it || null,
    price:    Number(p.price) || 0,
    weight:   p.weight || null,
    weight_it: p.weightIt || null,
    images:   (p.images || []).filter(Boolean),
    intensity: (p.intensity===""||p.intensity==null) ? null : Number(p.intensity),
    category:  p.category || null,
    variant_group: p.variantGroup || null,
    image:     p.image || null,
    palette:   Array.isArray(p.palette) ? p.palette : ["#0e0d0c","#c8202c","#f4ede0"],
    active:    p.active !== false,
    sort:      p.sort ?? 0,
    stripe_price_id: p.stripePriceId || null,
    updated_at: new Date().toISOString(),
  };
}

async function loadProductsFromSupabase(){
  if (!window.sb) return { ok: false, products: [...(window.DEFAULT_PRODUCTS || [])], err: "Supabase non disponible" };
  const { data, error } = await window.sb.from("products")
    .select("*").order("sort", { ascending: true }).order("id", { ascending: true });
  if (error) return { ok: false, products: [...(window.DEFAULT_PRODUCTS || [])], err: error.message };
  return { ok: true, products: (data || []).map(rowToProduct), err: null };
}
async function upsertProductToSupabase(p){
  if (!window.sb) return { ok: false, err: "Supabase non disponible" };
  const { error } = await window.sb.from("products").upsert(productToRow(p), { onConflict: "id" });
  return { ok: !error, err: error?.message || null };
}
async function deleteProductFromSupabase(id){
  if (!window.sb) return { ok: false, err: "Supabase non disponible" };
  const { error } = await window.sb.from("products").delete().eq("id", id);
  return { ok: !error, err: error?.message || null };
}

// Legacy localStorage helpers — kept ONLY for the one-time migration step in
// AdminScreen. Remove after Phase 2 ships.
const _LEGACY_STORAGE_KEY = STORAGE_KEY;
function legacyReadOverrides(){
  try {
    const raw = localStorage.getItem(_LEGACY_STORAGE_KEY);
    if (raw) {
      const parsed = JSON.parse(raw);
      if (Array.isArray(parsed)) return parsed;
    }
  } catch {}
  return null;
}

function emptyProduct(){
  return {
    id: "new-product-" + Date.now(),
    name:    { fr: "", it: "" },
    sub:     { fr: "", it: "" },
    tasting: { fr: "", it: "" },
    badge:   null,
    price: 0,
    weight: "",
    weightIt: "",
    images: [],
    intensity: null,
    category: (window.CATEGORIES?.[0]?.id) || "grain",
    variantGroup: "",
    image: "",
    palette: ["#0e0d0c","#c8202c","#f4ede0"],
    stripePriceId: "",
  };
}

// ─── Écrans d'accès ──────────────────────────────────────────────────────────
// L'accès n'est plus un mot de passe partagé — c'était un drapeau dans
// sessionStorage, que n'importe qui pouvait poser depuis la console. Il
// dépend maintenant de l'identité : compte Supabase + appartenance à
// `admin_emails`, c'est-à-dire exactement ce que vérifient les policies RLS.
// Une seule source de vérité pour l'écran et pour la base : les deux ne
// peuvent plus diverger.
function AdminGate({ title, children }){
  return (
    <main className="wrap" style={{padding:"96px 32px",minHeight:"60vh",maxWidth:560}}>
      <div className="eyebrow" style={{color:"var(--rosso)"}}>Admin</div>
      <h1 className="display" style={{fontSize:"clamp(40px,5vw,72px)",margin:"6px 0 12px",lineHeight:1}}>{title}</h1>
      {children}
    </main>
  );
}

// ─── Drawer d'édition produit ────────────────────────────────────────────────
function ProductEditor({ product, onSave, onCancel, isNew }){
  const [p, setP] = _aUseState(product);
  const [showRaw, setShowRaw] = _aUseState(false);

  const set = (path, val) => {
    setP(prev => {
      const next = JSON.parse(JSON.stringify(prev));
      // path: "name.fr" or "price"
      const parts = path.split(".");
      let cursor = next;
      for (let i = 0; i < parts.length - 1; i++) cursor = cursor[parts[i]];
      cursor[parts[parts.length - 1]] = val;
      return next;
    });
  };
  const toggleBadge = (on) => {
    setP(prev => ({ ...prev, badge: on ? { fr: "", it: "" } : null }));
  };

  return (
    <Drawer open={true} onClose={onCancel} side="right" width={560}>
      <div style={{display:"flex",flexDirection:"column",height:"100%"}}>
        <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",padding:"22px 26px",borderBottom:"1px solid var(--hairline)"}}>
          <div>
            <div className="eyebrow">{isNew ? "Nouveau produit" : "Édition produit"}</div>
            <div style={{fontFamily:"var(--font-display)",fontSize:22,marginTop:2}}>{p.name?.fr || p.id || "—"}</div>
          </div>
          <button onClick={onCancel} aria-label="Fermer"><IconClose size={22}/></button>
        </div>

        <div style={{flex:1,overflowY:"auto",padding:"20px 26px",fontSize:14}}>
          <AdminField label="ID (slug URL)" hint="Lettres minuscules + tirets. Ex: moreno-top-espresso-1kg">
            <input type="text" value={p.id} onChange={(e)=>set("id", e.target.value)} style={inputStyle}/>
          </AdminField>

          <AdminGroup title="Nom">
            <AdminField label="Français">
              <input type="text" value={p.name?.fr||""} onChange={(e)=>set("name.fr", e.target.value)} style={inputStyle}/>
            </AdminField>
            <AdminField label="Italien">
              <input type="text" value={p.name?.it||""} onChange={(e)=>set("name.it", e.target.value)} style={inputStyle}/>
            </AdminField>
          </AdminGroup>

          <AdminGroup title="Sous-titre">
            <AdminField label="Français">
              <input type="text" value={p.sub?.fr||""} onChange={(e)=>set("sub.fr", e.target.value)} style={inputStyle}/>
            </AdminField>
            <AdminField label="Italien">
              <input type="text" value={p.sub?.it||""} onChange={(e)=>set("sub.it", e.target.value)} style={inputStyle}/>
            </AdminField>
          </AdminGroup>

          <AdminGroup title="Notes de dégustation">
            <AdminField label="Français">
              <input type="text" value={p.tasting?.fr||""} onChange={(e)=>set("tasting.fr", e.target.value)} style={inputStyle}/>
            </AdminField>
            <AdminField label="Italien">
              <input type="text" value={p.tasting?.it||""} onChange={(e)=>set("tasting.it", e.target.value)} style={inputStyle}/>
            </AdminField>
          </AdminGroup>

          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:14}}>
            <AdminField label="Prix (€)">
              <input type="number" step="0.01" min="0" value={p.price} onChange={(e)=>set("price", parseFloat(e.target.value)||0)} style={inputStyle}/>
            </AdminField>
            <AdminField label="Poids / quantité" hint="Ex: 1 kg, 50 cps, 250 g">
              <input type="text" value={p.weight||""} onChange={(e)=>set("weight", e.target.value)} style={inputStyle}/>
            </AdminField>
          </div>

          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:14}}>
            <AdminField label="Poids / quantité (IT)" hint="Vide si identique au français">
              <input type="text" value={p.weightIt||""} onChange={(e)=>set("weightIt", e.target.value)} style={inputStyle}/>
            </AdminField>
            <AdminField label="Groupe de formats"
                        hint="Même valeur sur deux produits = un seul produit, deux formats (ex: moreno-aroma-top-nespresso)">
              <input type="text" value={p.variantGroup||""} onChange={(e)=>set("variantGroup", e.target.value)} style={inputStyle}/>
            </AdminField>
          </div>

          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:14}}>
            <AdminField label="Catégorie">
              <select value={p.category} onChange={(e)=>set("category", e.target.value)} style={{...inputStyle,cursor:"pointer"}}>
                {window.CATEGORIES.map(c=>(
                  <option key={c.id} value={c.id}>{pick(c.name)}</option>
                ))}
              </select>
            </AdminField>
            <AdminField label="Intensité" hint="1-10, ou vide pour les non-cafés">
              <input type="number" min="1" max="10" value={p.intensity ?? ""}
                onChange={(e)=>set("intensity", e.target.value===""?null:parseInt(e.target.value)||null)}
                style={inputStyle}/>
            </AdminField>
          </div>

          <AdminField label="Image (chemin local)" hint="Ex: images/products/moreno-top-extra-espresso-1kg.jpg">
            <input type="text" value={p.image||""} onChange={(e)=>set("image", e.target.value)} style={inputStyle}/>
            {p.image && (
              <div style={{marginTop:10,padding:8,background:"var(--paper-2)",borderRadius:4,display:"flex",alignItems:"center",justifyContent:"center",aspectRatio:"4/3",maxWidth:200}}>
                <img src={p.image} alt="" style={{maxWidth:"100%",maxHeight:"100%",objectFit:"contain"}}/>
              </div>
            )}
          </AdminField>

          <AdminField label="Photos supplémentaires"
                      hint="Un chemin par ligne. La fiche produit n'affiche de miniatures qu'à partir de deux photos — laisser vide s'il n'y en a qu'une.">
            <textarea rows={3}
              value={(p.images || []).join("\n")}
              onChange={(e)=>set("images", e.target.value.split("\n").map(x=>x.trim()).filter(Boolean))}
              placeholder="images/products/exemple-2.jpg"
              style={{...inputStyle, resize:"vertical", fontFamily:"inherit"}}/>
            {(p.images || []).length > 0 && (
              <div style={{marginTop:10,display:"flex",gap:8,flexWrap:"wrap"}}>
                {p.images.map((src,i)=>(
                  <div key={src+i} style={{width:72,height:72,padding:6,background:"var(--paper-2)",borderRadius:4,display:"flex",alignItems:"center",justifyContent:"center"}}>
                    <img src={src} alt="" style={{maxWidth:"100%",maxHeight:"100%",objectFit:"contain"}}/>
                  </div>
                ))}
              </div>
            )}
          </AdminField>

          <AdminField label="Stripe Price ID" hint="Coller le price_xxx créé dans Stripe Dashboard (test ou live mode). Vide = article non vendable.">
            <input type="text" value={p.stripePriceId||""} onChange={(e)=>set("stripePriceId", e.target.value)} placeholder="price_1Abc…" style={inputStyle}/>
          </AdminField>

          <AdminGroup title="Palette (3 couleurs)" hint="Utilisée pour le halo de la carte produit">
            <div style={{display:"flex",gap:10}}>
              {[0,1,2].map(i=>(
                <div key={i} style={{flex:1,display:"flex",flexDirection:"column",gap:6}}>
                  <input type="color" value={p.palette[i]} onChange={(e)=>{
                    const next = [...p.palette]; next[i] = e.target.value;
                    setP({...p, palette: next});
                  }} style={{width:"100%",height:42,border:0,padding:0,background:"transparent",cursor:"pointer"}}/>
                  <input type="text" value={p.palette[i]} onChange={(e)=>{
                    const next = [...p.palette]; next[i] = e.target.value;
                    setP({...p, palette: next});
                  }} style={{...inputStyle,fontSize:11.5,fontFamily:"ui-monospace,Menlo,monospace",padding:"6px 8px"}}/>
                </div>
              ))}
            </div>
          </AdminGroup>

          <AdminGroup title="Badge (optionnel)">
            <label style={{display:"flex",alignItems:"center",gap:10,marginBottom:10,fontSize:13.5,cursor:"pointer"}}>
              <input type="checkbox" checked={!!p.badge} onChange={(e)=>toggleBadge(e.target.checked)}/>
              <span>Afficher un badge sur la carte produit</span>
            </label>
            {p.badge && (
              <div style={{display:"grid",gridTemplateColumns:"1fr 1fr",gap:14}}>
                <AdminField label="Français">
                  <input type="text" value={p.badge.fr||""} onChange={(e)=>set("badge.fr", e.target.value)} placeholder="Best-seller" style={inputStyle}/>
                </AdminField>
                <AdminField label="Italien">
                  <input type="text" value={p.badge.it||""} onChange={(e)=>set("badge.it", e.target.value)} placeholder="Premium" style={inputStyle}/>
                </AdminField>
              </div>
            )}
          </AdminGroup>

          <details style={{marginTop:24}} open={showRaw}>
            <summary style={{cursor:"pointer",fontSize:12.5,color:"var(--muted)",letterSpacing:".06em",textTransform:"uppercase",fontWeight:600}}
              onClick={(e)=>{e.preventDefault();setShowRaw(!showRaw);}}>
              JSON brut
            </summary>
            <pre style={{marginTop:12,padding:12,background:"var(--paper-2)",borderRadius:4,fontSize:11,fontFamily:"ui-monospace,Menlo,monospace",overflow:"auto",whiteSpace:"pre-wrap"}}>
              {JSON.stringify(p, null, 2)}
            </pre>
          </details>
        </div>

        <div style={{borderTop:"1px solid var(--hairline)",padding:"16px 26px",display:"flex",gap:10}}>
          <button onClick={onCancel} className="btn btn-ghost" style={{flex:1}}>Annuler</button>
          <button onClick={()=>onSave(p)} className="btn btn-primary" style={{flex:2}}>
            {isNew ? "Créer le produit" : "Enregistrer"}
          </button>
        </div>
      </div>
    </Drawer>
  );
}

const inputStyle = {
  width:"100%",padding:"10px 12px",fontSize:14,fontFamily:"inherit",
  background:"var(--paper-2)",color:"var(--ink)",
  border:"1px solid var(--hairline-strong)",borderRadius:6,outline:"none",
  boxSizing:"border-box",
};

function AdminField({ label, hint, children }){
  return (
    <div style={{marginBottom:14}}>
      <label style={{display:"block",fontSize:11.5,letterSpacing:".12em",textTransform:"uppercase",fontWeight:600,color:"var(--muted)",marginBottom:6}}>
        {label}
      </label>
      {children}
      {hint && <div style={{fontSize:11.5,color:"var(--muted)",marginTop:4,fontStyle:"italic"}}>{hint}</div>}
    </div>
  );
}
function AdminGroup({ title, hint, children }){
  return (
    <div style={{marginBottom:20,padding:"14px 14px 4px",border:"1px solid var(--hairline)",borderRadius:8}}>
      <div style={{fontSize:11,letterSpacing:".18em",textTransform:"uppercase",fontWeight:700,color:"var(--ink)",marginBottom:10}}>
        {title}
      </div>
      {hint && <div style={{fontSize:11.5,color:"var(--muted)",marginBottom:10,fontStyle:"italic"}}>{hint}</div>}
      {children}
    </div>
  );
}

// ─── Admin screen ────────────────────────────────────────────────────────────
function AdminScreen({ navigate }){
  const { session, isAdmin, ready } = useAdmin();
  const [tab, setTab] = _aUseState("catalog");  // catalog · pro · customers
  const [products, setProducts] = _aUseState([]);
  const [loadErr, setLoadErr]   = _aUseState(null);
  const [booted,  setBooted]    = _aUseState(false);
  const [editing, setEditing] = _aUseState(null);     // product being edited, or null
  const [isNew, setIsNew] = _aUseState(false);
  const [filter, setFilter] = _aUseState("");
  const [cat, setCat] = _aUseState("all");
  const [toast, setToast] = _aUseState(null);

  const flash = (msg) => { setToast(msg); setTimeout(()=>setToast(null), 2400); };

  const reloadFromSupabase = async () => {
    const { ok, products: rows, err } = await loadProductsFromSupabase();
    setProducts(rows);
    setLoadErr(ok ? null : err);
    return ok;
  };

  // Le catalogue ne se charge que pour un admin confirmé.
  _aUseEffect(() => {
    if (!isAdmin) return;
    let cancelled = false;
    (async () => {
      const { ok, products: rows, err } = await loadProductsFromSupabase();
      if (cancelled) return;
      setLoadErr(ok ? null : err);
      setProducts(rows);
      setBooted(true);
    })();
    return () => { cancelled = true; };
  }, [isAdmin]);

  // One-time migration: push any localStorage overrides into Supabase.
  _aUseEffect(() => {
    if (!isAdmin || !booted) return;
    const local = legacyReadOverrides();
    if (!local || local.length === 0) return;
    if (!confirm(`Des modifications locales (${local.length} produits) sont présentes dans localStorage. Les pousser dans Supabase et nettoyer ?`)) return;
    (async () => {
      for (const p of local) {
        const { ok, err } = await upsertProductToSupabase(p);
        if (!ok) { flash("Migration : erreur sur " + p.id + " : " + err); return; }
      }
      try { localStorage.removeItem(_LEGACY_STORAGE_KEY); } catch {}
      await reloadFromSupabase();
      flash("Migration terminée — localStorage nettoyé");
    })();
  }, [isAdmin, booted]);

  // `ready` ne passe à true qu'une fois la question « est-ce un admin »
  // tranchée. Rendre avant, c'est faire clignoter le mauvais écran.
  if (!ready) {
    return (
      <main className="wrap" style={{padding:"96px 32px",minHeight:"60vh",color:"var(--muted)"}}>
        Vérification des droits…
      </main>
    );
  }
  if (!session) {
    return (
      <AdminGate title="Accès réservé">
        <p style={{color:"var(--muted)",fontSize:14.5,marginBottom:24}}>
          Cette zone gère le catalogue, les demandes pro et les commandes.
          Connectez-vous avec un compte autorisé.
        </p>
        <button onClick={()=>navigate({page:"account"})} className="btn btn-primary" style={{height:48}}>
          Se connecter →
        </button>
      </AdminGate>
    );
  }
  if (!isAdmin) {
    return (
      <AdminGate title="Compte non autorisé">
        <p style={{color:"var(--muted)",fontSize:14.5,marginBottom:12}}>
          Vous êtes connecté en tant que <b style={{color:"var(--ink)"}}>{session.user.email}</b>,
          mais ce compte n'a pas les droits d'administration.
        </p>
        <p style={{fontSize:13,color:"var(--muted)",marginBottom:24}}>
          Les droits se donnent en ajoutant l'email dans la table <code>admin_emails</code>.
        </p>
        <button onClick={()=>navigate({page:"home"})} className="btn btn-ghost" style={{height:48}}>
          Retour à la boutique
        </button>
      </AdminGate>
    );
  }

  const filtered = products.filter(p => {
    if (cat !== "all" && p.category !== cat) return false;
    if (filter) {
      const q = filter.toLowerCase();
      return (
        (p.id || "").toLowerCase().includes(q) ||
        (p.name?.fr || "").toLowerCase().includes(q) ||
        (p.name?.it || "").toLowerCase().includes(q)
      );
    }
    return true;
  });

  const handleSave = async (p) => {
    if (isNew && products.find(x => x.id === p.id)) {
      flash(`ID déjà utilisé : ${p.id}`);
      return;
    }
    const { ok, err } = await upsertProductToSupabase(p);
    if (!ok) { flash("Erreur : " + err); return; }
    await reloadFromSupabase();
    flash("Sauvegardé ✓");
    setEditing(null);
    setIsNew(false);
  };

  const handleDelete = async (id) => {
    if (!confirm(`Supprimer définitivement « ${id} » ?`)) return;
    const { ok, err } = await deleteProductFromSupabase(id);
    if (!ok) { flash("Erreur : " + err); return; }
    await reloadFromSupabase();
    flash("Supprimé");
  };

  const handleNew = () => {
    setEditing(emptyProduct());
    setIsNew(true);
  };

  // Re-seed catalog from data.jsx defaults (re-upserts the original products).
  const handleReset = async () => {
    if (!confirm("Re-seeder le catalogue avec les valeurs par défaut de data.jsx ? Les produits existants avec le même ID seront écrasés.")) return;
    const defaults = window.DEFAULT_PRODUCTS || [];
    for (const p of defaults) {
      const { ok, err } = await upsertProductToSupabase(p);
      if (!ok) { flash("Erreur sur " + p.id + " : " + err); return; }
    }
    await reloadFromSupabase();
    flash("Catalogue re-seedé depuis data.jsx");
  };

  // Export = snapshot the current Supabase catalog as JSON (handy backup).
  const handleExport = () => {
    const blob = new Blob([JSON.stringify(products, null, 2)], { type: "application/json" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `caffe-italia-products-${new Date().toISOString().slice(0,10)}.json`;
    document.body.appendChild(a); a.click(); document.body.removeChild(a);
    URL.revokeObjectURL(url);
    flash("Export téléchargé");
  };

  // Import = bulk upsert a JSON file into Supabase. Useful to restore a backup.
  const handleImport = (e) => {
    const file = e.target.files?.[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = async () => {
      try {
        const parsed = JSON.parse(reader.result);
        if (!Array.isArray(parsed)) throw new Error("not an array");
        if (!confirm(`Importer ${parsed.length} produits dans Supabase ? Les IDs existants seront écrasés.`)) return;
        for (const p of parsed) {
          const { ok, err } = await upsertProductToSupabase(p);
          if (!ok) { flash("Erreur sur " + p.id + " : " + err); return; }
        }
        await reloadFromSupabase();
        flash("Import terminé");
      } catch (err) {
        flash("JSON invalide : " + err.message);
      }
    };
    reader.readAsText(file);
    e.target.value = "";  // allow re-uploading same file
  };

  // Vraie déconnexion : on quitte la session Supabase. useAdmin repasse
  // aussitôt sur l'écran « Accès réservé ».
  const handleLogout = async () => {
    if (window.sb) await window.sb.auth.signOut();
    navigate({ page: "home" });
  };

  const tabs = [
    { id:"catalog",   label:"Catalogue" },
    { id:"pro",       label:"Demandes pro" },
    { id:"customers", label:"Clients" },
  ];

  return (
    <main className="wrap admin-wrap" style={{padding:"22px 32px 80px",maxWidth:1400,width:"100%",boxSizing:"border-box"}}>
      {/* Breadcrumb */}
      <div style={{fontSize:12,color:"var(--muted)",display:"flex",gap:8,alignItems:"center",marginBottom:14}}>
        <a onClick={()=>navigate({page:"home"})} style={{cursor:"pointer"}}>{t("cat.crumb_home")}</a>
        <span>/</span>
        <span style={{color:"var(--ink)",fontWeight:600}}>Admin</span>
      </div>

      {/* Header */}
      <div style={{display:"flex",alignItems:"flex-end",justifyContent:"space-between",gap:24,paddingBottom:18,borderBottom:"1px solid var(--hairline)",flexWrap:"wrap"}}>
        <div style={{minWidth:0,flex:"1 1 320px"}}>
          <div className="eyebrow" style={{color:"var(--rosso)"}}>Admin · Caffè Italia</div>
          <h1 className="display" style={{fontSize:"clamp(28px,4vw,56px)",margin:"12px 0 0",lineHeight:1.05}}>
            {tab==="catalog" ? "Catalogue produits" :
             tab==="pro"     ? "Demandes pro" :
                               "Clients"}
          </h1>
        </div>
        <button onClick={handleLogout} className="btn btn-ghost btn-sm" style={{flex:"0 0 auto"}}>Déconnexion</button>
      </div>

      {/* Tabs */}
      <div style={{display:"flex",gap:4,borderBottom:"1px solid var(--hairline)",marginTop:18,marginBottom:24,overflowX:"auto"}}>
        {tabs.map(tb => (
          <button key={tb.id} onClick={()=>setTab(tb.id)} style={{
            padding:"12px 18px",fontSize:13.5,fontWeight:600,letterSpacing:".02em",
            color: tab===tb.id ? "var(--ink)" : "var(--muted)",
            borderBottom: "2px solid " + (tab===tb.id ? "var(--rosso)" : "transparent"),
            marginBottom:-1,whiteSpace:"nowrap",
          }}>{tb.label}</button>
        ))}
      </div>

      <style>{`
        @media (max-width:720px){
          .admin-wrap{padding-left:18px !important; padding-right:18px !important}
        }
      `}</style>

      {tab === "pro"       && <ProRequestsPanel flash={flash}/>}
      {tab === "customers" && <CustomersPanel flash={flash}/>}
      {tab === "catalog" && (<>

      {!booted && (
        <div style={{padding:"14px 16px",background:"var(--paper-2)",borderRadius:8,fontSize:13,color:"var(--muted)",marginBottom:14,border:"1px solid var(--hairline)"}}>
          Chargement du catalogue…
        </div>
      )}
      {loadErr && (
        <div style={{padding:"14px 16px",background:"rgba(220,40,50,.1)",border:"1px solid var(--rosso)",borderRadius:8,fontSize:13,color:"var(--rosso)",marginBottom:14}}>
          Erreur de chargement : {loadErr}
        </div>
      )}

      {/* Catalog actions */}
      <div style={{display:"flex",gap:8,flexWrap:"wrap",marginBottom:18}}>
        <p style={{fontSize:13,color:"var(--muted)",margin:0,flex:"1 1 300px"}}>
          Modifications sauvegardées dans Supabase. Visibles immédiatement par tous les visiteurs (une fois la Phase 2 livrée).
        </p>
        <label className="btn btn-ghost btn-sm" style={{cursor:"pointer"}}>
          ⬆ Import
          <input type="file" accept="application/json" onChange={handleImport} style={{display:"none"}}/>
        </label>
        <button onClick={handleExport} className="btn btn-ghost btn-sm">⬇ Export</button>
        <button onClick={handleReset} className="btn btn-ghost btn-sm" style={{color:"var(--rosso)",borderColor:"var(--rosso)"}}>↺ Reset</button>
      </div>

      {/* Toolbar */}
      <div style={{display:"flex",alignItems:"center",gap:12,padding:"18px 0",flexWrap:"wrap"}}>
        <input type="search" placeholder="Rechercher par nom ou ID…" value={filter} onChange={(e)=>setFilter(e.target.value)}
          style={{...inputStyle,maxWidth:320,flex:"1 1 200px"}}/>
        <select value={cat} onChange={(e)=>setCat(e.target.value)} style={{...inputStyle,maxWidth:220,flex:"0 1 auto",cursor:"pointer"}}>
          <option value="all">Toutes catégories</option>
          {window.CATEGORIES.map(c=>(<option key={c.id} value={c.id}>{pick(c.name)}</option>))}
        </select>
        <span style={{fontSize:12.5,color:"var(--muted)"}}>
          <b style={{color:"var(--ink)"}}>{filtered.length}</b> / {products.length} produits
        </span>
        <button onClick={handleNew} className="btn btn-rosso" style={{marginLeft:"auto",height:42}}>
          + Nouveau produit
        </button>
      </div>

      {/* Table */}
      <div style={{border:"1px solid var(--hairline)",borderRadius:8,overflow:"auto"}} className="admin-table-wrap">
        <table style={{width:"100%",borderCollapse:"collapse",fontSize:13.5}} className="admin-table">
          <thead>
            <tr style={{background:"var(--paper-2)",fontSize:11,letterSpacing:".1em",textTransform:"uppercase",color:"var(--muted)"}}>
              <th style={{...th, width:64}}></th>
              <th style={th}>Nom / ID</th>
              <th style={th}>Catégorie</th>
              <th style={{...th,textAlign:"right"}}>Prix</th>
              <th style={th}>Poids</th>
              <th style={{...th,width:60,textAlign:"center"}}>Int.</th>
              <th style={{...th,textAlign:"right",width:140}}>Actions</th>
            </tr>
          </thead>
          <tbody>
            {filtered.map(p => {
              const catName = pick((window.CATEGORIES.find(c=>c.id===p.category)||{name:p.category}).name);
              return (
                <tr key={p.id} style={{borderTop:"1px solid var(--hairline)"}}>
                  <td style={td}>
                    {p.image ? (
                      <div style={{width:48,height:48,background:"var(--paper-2)",borderRadius:4,display:"flex",alignItems:"center",justifyContent:"center",padding:4,overflow:"hidden"}}>
                        <img src={p.image} alt="" loading="lazy" style={{maxWidth:"100%",maxHeight:"100%",objectFit:"contain"}}/>
                      </div>
                    ) : (
                      <div style={{width:48,height:48,background:"var(--paper-3)",borderRadius:4,display:"flex",alignItems:"center",justifyContent:"center",fontSize:18,color:"var(--muted)"}}>—</div>
                    )}
                  </td>
                  <td style={td}>
                    <div style={{fontWeight:600,color:"var(--ink)"}}>{pick(p.name) || <span style={{color:"var(--muted)",fontStyle:"italic"}}>(sans nom)</span>}</div>
                    <div style={{fontSize:11.5,color:"var(--muted)",marginTop:2,fontFamily:"ui-monospace,Menlo,monospace"}}>{p.id}</div>
                  </td>
                  <td style={td}>{catName}</td>
                  <td style={{...td,textAlign:"right",fontVariantNumeric:"tabular-nums"}}>
                    {typeof p.price === "number" ? p.price.toFixed(2).replace(".",",") + " €" : "—"}
                  </td>
                  <td style={td}>{p.weight || "—"}</td>
                  <td style={{...td,textAlign:"center",color:p.intensity?"var(--ink)":"var(--muted)"}}>
                    {p.intensity ? p.intensity + "/10" : "—"}
                  </td>
                  <td style={{...td,textAlign:"right"}}>
                    <button onClick={()=>{setEditing(p);setIsNew(false);}} style={iconBtn}>Éditer</button>
                    <button onClick={()=>handleDelete(p.id)} style={{...iconBtn,color:"var(--rosso)",marginLeft:6}}>Suppr.</button>
                  </td>
                </tr>
              );
            })}
            {filtered.length === 0 && (
              <tr>
                <td colSpan="7" style={{padding:"40px 16px",textAlign:"center",color:"var(--muted)"}}>
                  Aucun produit ne correspond.
                </td>
              </tr>
            )}
          </tbody>
        </table>
      </div>

      <style>{`
        @media (max-width:720px){
          .admin-table thead{display:none}
          .admin-table, .admin-table tbody, .admin-table tr, .admin-table td{display:block;width:100%}
          .admin-table tr{padding:14px 12px;border-top:1px solid var(--hairline)}
          .admin-table td{padding:4px 0;border:0}
        }
      `}</style>

      {editing && (
        <ProductEditor product={editing} isNew={isNew} onSave={handleSave} onCancel={()=>{setEditing(null);setIsNew(false);}}/>
      )}
      </>)}

      <AdminToast msg={toast} onClose={()=>setToast(null)}/>
    </main>
  );
}

// ─── Pro requests panel ─────────────────────────────────────────────────────
function ProRequestsPanel({ flash }){
  const [rows, setRows] = _aUseState(null);
  const [err, setErr]   = _aUseState(null);
  const [filter, setFilter] = _aUseState("all"); // all | new | contacted | won | lost

  const load = async () => {
    if (!window.sb) { setErr("Supabase non disponible · pas de DB"); return; }
    const { data, error } = await window.sb.from("pro_requests")
      .select("*").order("created_at", { ascending: false });
    if (error) { setErr(error.message); return; }
    setRows(data || []);
  };
  _aUseEffect(() => { load(); }, []);

  const updateStatus = async (id, status) => {
    const { error } = await window.sb.from("pro_requests").update({ status }).eq("id", id);
    if (error) { flash(error.message); return; }
    setRows(prev => prev.map(r => r.id===id ? {...r, status} : r));
  };

  if (err) return <PanelError msg={err}/>;
  if (rows === null) return <PanelLoading/>;

  const filtered = filter === "all" ? rows : rows.filter(r => r.status === filter);
  const counts = rows.reduce((acc,r)=>{acc[r.status]=(acc[r.status]||0)+1;return acc;}, {});

  return (
    <div>
      <div style={{display:"flex",gap:8,marginBottom:18,flexWrap:"wrap"}}>
        {[["all","Toutes",rows.length],["new","Nouvelles",counts.new||0],["contacted","Contactées",counts.contacted||0],["won","Gagnées",counts.won||0],["lost","Perdues",counts.lost||0]].map(([id,label,n])=>(
          <button key={id} onClick={()=>setFilter(id)} style={{
            padding:"7px 13px",borderRadius:99,fontSize:12,fontWeight:600,
            background: filter===id ? "var(--ink)" : "transparent",
            color: filter===id ? "var(--paper)" : "var(--ink)",
            border: "1px solid " + (filter===id ? "var(--ink)" : "var(--hairline-strong)"),
          }}>{label} <span style={{opacity:.6,marginLeft:4}}>{n}</span></button>
        ))}
      </div>

      {filtered.length === 0 ? (
        <EmptyState label="Aucune demande." hint="Les demandes envoyées via le formulaire /page/pro apparaîtront ici."/>
      ) : (
        <div style={{display:"grid",gap:12}}>
          {filtered.map(r => (
            <div key={r.id} style={{padding:18,background:"var(--paper-2)",borderRadius:8,border:"1px solid var(--hairline)"}}>
              <div style={{display:"grid",gridTemplateColumns:"1fr auto",gap:14,alignItems:"flex-start"}}>
                <div>
                  <div style={{display:"flex",gap:10,alignItems:"baseline",flexWrap:"wrap"}}>
                    <span style={{fontFamily:"var(--font-display)",fontSize:20,letterSpacing:".01em"}}>{r.full_name}</span>
                    <span style={{color:"var(--muted)",fontSize:13}}>· {r.company}</span>
                    {r.needs_machine && <span className="chip chip-rosso" style={{fontSize:10}}>Machine pro</span>}
                  </div>
                  <div style={{display:"flex",gap:14,marginTop:6,fontSize:12.5,color:"var(--muted)",flexWrap:"wrap"}}>
                    <a href={`mailto:${r.email}`} style={{color:"var(--ink)",textDecoration:"underline"}}>{r.email}</a>
                    <a href={`tel:${r.phone}`} style={{color:"var(--ink)"}}>{r.phone}</a>
                    {r.volume && <span>Volume : <b style={{color:"var(--ink)"}}>{r.volume}</b></span>}
                    <span>Lang : {r.lang}</span>
                    <span>{new Date(r.created_at).toLocaleString("fr-FR")}</span>
                  </div>
                  {r.message && (
                    <p style={{marginTop:10,fontSize:14,lineHeight:1.5,padding:"10px 14px",background:"var(--paper)",borderRadius:6,borderLeft:"2px solid var(--rosso)"}}>{r.message}</p>
                  )}
                </div>
                <select value={r.status} onChange={(e)=>updateStatus(r.id, e.target.value)} style={{
                  padding:"8px 12px",fontSize:12.5,fontWeight:600,fontFamily:"inherit",
                  background:"var(--paper)",color:"var(--ink)",
                  border:"1px solid var(--hairline-strong)",borderRadius:99,cursor:"pointer",
                }}>
                  <option value="new">Nouvelle</option>
                  <option value="contacted">Contactée</option>
                  <option value="won">Gagnée</option>
                  <option value="lost">Perdue</option>
                </select>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ─── Customers panel (lecture profiles) ─────────────────────────────────────
function CustomersPanel({ flash }){
  const [rows, setRows] = _aUseState(null);
  const [err, setErr]   = _aUseState(null);

  _aUseEffect(() => {
    (async () => {
      if (!window.sb) { setErr("Supabase non disponible"); return; }
      const { data, error } = await window.sb.from("profiles")
        .select("*").order("created_at", { ascending: false });
      if (error) { setErr(error.message); return; }
      setRows(data || []);
    })();
  }, []);

  if (err) return <PanelError msg={err}/>;
  if (rows === null) return <PanelLoading/>;

  if (rows.length === 0) {
    return <EmptyState label="Aucun client inscrit pour le moment." hint="Les comptes créés depuis le site (Supabase Auth) apparaîtront ici."/>;
  }

  return (
    <>
      <div style={{border:"1px solid var(--hairline)",borderRadius:8,overflow:"auto"}}>
        <table style={{width:"100%",borderCollapse:"collapse",fontSize:13.5}} className="admin-table">
          <thead>
            <tr style={{background:"var(--paper-2)",fontSize:11,letterSpacing:".1em",textTransform:"uppercase",color:"var(--muted)"}}>
              <th style={th}>Nom</th>
              <th style={th}>Téléphone</th>
              <th style={th}>Ville</th>
              <th style={th}>Pays</th>
              <th style={th}>Inscrit le</th>
            </tr>
          </thead>
          <tbody>
            {rows.map(p => (
              <tr key={p.id} style={{borderTop:"1px solid var(--hairline)"}}>
                <td style={td} data-label="Nom">
                  <div style={{fontWeight:600}}>{p.full_name || <span style={{color:"var(--muted)",fontStyle:"italic"}}>(sans nom)</span>}</div>
                  <div style={{fontSize:11,color:"var(--muted)",fontFamily:"ui-monospace,Menlo,monospace",marginTop:2}}>{p.id.slice(0,8)}…</div>
                </td>
                <td style={td} data-label="Téléphone">{p.phone || "—"}</td>
                <td style={td} data-label="Ville">{[p.address_zip, p.address_city].filter(Boolean).join(" ") || "—"}</td>
                <td style={td} data-label="Pays">{p.address_country || "—"}</td>
                <td style={{...td,fontSize:12,color:"var(--muted)"}} data-label="Inscrit le">
                  {p.created_at ? new Date(p.created_at).toLocaleDateString("fr-FR") : "—"}
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <style>{`
        @media (max-width:720px){
          .admin-table thead{display:none}
          .admin-table, .admin-table tbody, .admin-table tr, .admin-table td{display:block;width:100%}
          .admin-table tr{padding:14px 12px;border-top:1px solid var(--hairline)}
          .admin-table td{padding:4px 0;border:0;display:flex;justify-content:space-between;gap:14px}
          .admin-table td[data-label]::before{content:attr(data-label);color:var(--muted);font-size:11px;letter-spacing:.1em;text-transform:uppercase;font-weight:600;flex:0 0 auto}
        }
      `}</style>
    </>
  );
}

function PanelLoading(){
  return <div style={{padding:"48px 16px",textAlign:"center",color:"var(--muted)"}}>Chargement…</div>;
}
function EmptyState({ label, hint }){
  return (
    <div style={{
      padding:"56px 24px",textAlign:"center",
      border:"1px dashed var(--hairline-strong)",borderRadius:8,
      background:"var(--paper-2)",
    }}>
      <div style={{fontSize:15,color:"var(--ink)",fontWeight:600}}>{label}</div>
      {hint && <div style={{fontSize:13,color:"var(--muted)",marginTop:8,maxWidth:420,marginLeft:"auto",marginRight:"auto",lineHeight:1.5}}>{hint}</div>}
    </div>
  );
}
function PanelError({ msg }){
  return (
    <div style={{padding:"24px",background:"rgba(220,40,50,.08)",border:"1px solid var(--rosso)",borderRadius:8,color:"var(--rosso)",fontSize:13.5}}>
      <b>Erreur :</b> {msg}
      <p style={{color:"var(--ink)",fontSize:13,marginTop:8,lineHeight:1.5}}>
        Pour voir cette section, ajoute ton email d'admin dans la table <code style={{padding:"1px 6px",background:"var(--paper-2)",borderRadius:3}}>admin_emails</code> :
        <br/>
        <code style={{display:"inline-block",marginTop:6,padding:"6px 10px",background:"var(--paper-2)",borderRadius:4,fontSize:12}}>
          insert into admin_emails (email) values ('ton-email@example.com');
        </code>
      </p>
    </div>
  );
}

const th = { padding:"12px 14px", textAlign:"left", fontWeight:600 };
const td = { padding:"12px 14px", verticalAlign:"middle" };
const iconBtn = {
  fontSize:12,fontWeight:600,letterSpacing:".02em",
  padding:"6px 10px",borderRadius:99,
  border:"1px solid var(--hairline-strong)",background:"transparent",color:"var(--ink)",cursor:"pointer",
};

Object.assign(window, { AdminScreen });
