/* ─────────────────────────────────────────────────────────────────────────
   menu-designer.jsx — window.MFMenuDesigner
   The public, no-login menu design studio (route: /crear). The wedge.

   Everything here is free: pick a template, edit your dishes, see a true
   print preview. The two account-gated actions — Descargar PDF and
   Personalizar con IA — call onRequireAccount(draft); the parent opens signin
   and (Phase 3) claims the anonymous draft into the new account.

   Renders with the shared window.MFMenuPrint engine, so the on-screen preview
   is exactly what the Puppeteer print job (Phase 4) will produce.
   ───────────────────────────────────────────────────────────────────────── */

const { useState: useStateMD, useEffect: useEffectMD, useRef: useRefMD, useMemo: useMemoMD } = React;

function useMobileMD() {
  const [m, setM] = useStateMD(() => window.innerWidth < 860);
  useEffectMD(() => {
    const fn = () => setM(window.innerWidth < 860);
    window.addEventListener('resize', fn);
    return () => window.removeEventListener('resize', fn);
  }, []);
  return m;
}

const MD_DRAFT_KEY = 'mf_menu_draft';

// A friendly starter so the preview is alive on first paint. Fully editable.
function mdStarter() {
  return {
    templateId: 'olivo',
    paper: 'A4',
    brand: { name: 'Tu Restaurante', tagline: 'Cocina de autor', accent: '#8A7A50', logo: null },
    categories: [
      { id: 'c1', name: 'Entradas' },
      { id: 'c2', name: 'Platos Fuertes' },
      { id: 'c3', name: 'Postres' },
    ],
    items: [
      { id: 'i1', category: 'c1', name: 'Tostada de atún', description: 'Atún aleta azul, aguacate, chile serrano y aceite de ajonjolí.', price: 185, tags: [] },
      { id: 'i2', category: 'c1', name: 'Esquites de la casa', description: 'Maíz tatemado, epazote, mayonesa de chipotle.', price: 95, tags: [] },
      { id: 'i3', category: 'c2', name: 'Cochinita pibil', description: 'Cerdo en achiote, naranja agria, cebolla morada encurtida.', price: 240, tags: [] },
      { id: 'i4', category: 'c3', name: 'Flan de cajeta', description: '', price: 110, tags: [] },
    ],
  };
}

function mdLoad() {
  try {
    const raw = localStorage.getItem(MD_DRAFT_KEY);
    if (raw) { const d = JSON.parse(raw); if (d && d.brand && d.items) return d; }
  } catch (_) {}
  return mdStarter();
}

let _mdUid = Date.now();
function mdId(p) { return p + '_' + (++_mdUid).toString(36); }

// URL/file-safe slug for the downloaded filename.
function mdSlug(name) {
  return (String(name || 'carta').toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g, '')
    .replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'carta');
}

// Pull the first JSON object out of a model response (handles stray prose/fences).
function mdParseJSON(text) {
  if (text == null) return null;
  if (typeof text === 'object') return text;
  const m = String(text).match(/\{[\s\S]*\}/);
  if (!m) return null;
  try { return JSON.parse(m[0]); } catch (_) { return null; }
}
// Accept only a well-formed #rgb / #rrggbb hex.
function mdValidHex(h) {
  return (typeof h === 'string' && /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(h.trim())) ? h.trim() : null;
}

// Turn a base64 PDF (from renderMenuPdf) into a download in the browser.
function mdDownloadPdf(b64, filename) {
  const bin = atob(b64);
  const bytes = new Uint8Array(bin.length);
  for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
  const url = URL.createObjectURL(new Blob([bytes], { type: 'application/pdf' }));
  const a = document.createElement('a');
  a.href = url; a.download = filename || 'carta.pdf';
  document.body.appendChild(a); a.click(); a.remove();
  setTimeout(() => URL.revokeObjectURL(url), 4000);
}

window.MFMenuDesigner = function MenuDesigner({ profile, authed, autorun, onAutorunDone, onClose, onRequireAccount, onBuildRestaurant }) {
  const mobile = useMobileMD();
  const [draft, setDraft] = useStateMD(mdLoad);
  // Debounced copy that actually drives the (relatively heavy) iframe renders.
  const [render, setRender] = useStateMD(draft);
  const [tab, setTab] = useStateMD('preview'); // mobile-only: 'preview' | 'editar'
  const [exp, setExp] = useStateMD(null);      // PDF export: null | 'loading' | 'done' | 'error'
  const [toast, setToast] = useStateMD(null);  // transient { msg, tone }
  const [aiOpen, setAiOpen] = useStateMD(false);
  const [aiText, setAiText] = useStateMD('');
  const [aiBusy, setAiBusy] = useStateMD('idle'); // 'idle' | 'loading' | 'error'
  const [reveal, setReveal] = useStateMD(false);  // post-signup platform reveal
  const [pasteOpen, setPasteOpen] = useStateMD(false);
  const [pasteText, setPasteText] = useStateMD('');
  const [pasteBusy, setPasteBusy] = useStateMD('idle'); // 'idle' | 'loading' | 'error'
  const wasAuthedRef = useRefMD(authed);
  const previewRef = useRefMD(null);
  const [pscale, setPscale] = useStateMD(mobile ? 0.42 : 0.7); // fit-to-width preview scale
  const watermark = !authed;

  // The print page is a fixed A4 (794×1123px). Scale it to fit the preview pane:
  // fit-to-width on mobile (scroll vertically), fit-whole on desktop.
  useEffectMD(() => {
    const el = previewRef.current;
    if (!el || typeof ResizeObserver === 'undefined') return;
    const compute = () => {
      const pad = mobile ? 24 : 48;
      const w = Math.max(0, el.clientWidth - pad);
      const h = Math.max(0, el.clientHeight - pad);
      const s = mobile ? (w / 794) : Math.min(w / 794, h / 1123);
      setPscale(Math.max(0.12, Math.min(s, 1.1)));
    };
    compute();
    const ro = new ResizeObserver(compute);
    ro.observe(el);
    return () => ro.disconnect();
  }, [mobile, tab]);

  // Sign anonymous users in silently so the free AI helpers (paste→extract) work.
  // Anonymous ≠ authed: the watermark + export/personalize gate still require a
  // real account — this only unlocks the no-login content conveniences.
  useEffectMD(() => {
    if (typeof firebase === 'undefined' || !firebase.auth) return;
    const auth = firebase.auth();
    if (!auth.currentUser) auth.signInAnonymously().catch((e) => console.warn('[md-anon]', e.message));
  }, []); // free/anon menus carry the Menu Factory mark; drops once they sign up

  // Persist the draft (debounced) + feed the debounced render state.
  useEffectMD(() => {
    const t = setTimeout(() => {
      setRender(draft);
      try { localStorage.setItem(MD_DRAFT_KEY, JSON.stringify(draft)); } catch (_) {}
    }, 320);
    return () => clearTimeout(t);
  }, [draft]);

  const data = useMemoMD(() => ({
    brand: render.brand, categories: render.categories, items: render.items, locale: 'es-MX',
  }), [render]);

  const previewHtml = useMemoMD(
    () => window.MFMenuPrint.render(render.templateId, data, { paper: render.paper, watermark }),
    [render.templateId, render.paper, data, watermark]
  );

  // ── mutators ──────────────────────────────────────────────────────────────
  const patch = (p) => setDraft((d) => ({ ...d, ...p }));
  const setBrand = (p) => setDraft((d) => ({ ...d, brand: { ...d.brand, ...p } }));
  const addCategory = () => setDraft((d) => ({ ...d, categories: [...d.categories, { id: mdId('c'), name: 'Nueva sección' }] }));
  const renameCategory = (id, name) => setDraft((d) => ({ ...d, categories: d.categories.map((c) => c.id === id ? { ...c, name } : c) }));
  const removeCategory = (id) => setDraft((d) => ({
    ...d, categories: d.categories.filter((c) => c.id !== id), items: d.items.filter((it) => it.category !== id),
  }));
  const addItem = (cid) => setDraft((d) => ({ ...d, items: [...d.items, { id: mdId('i'), category: cid, name: '', description: '', price: 0, tags: [] }] }));
  const patchItem = (id, p) => setDraft((d) => ({ ...d, items: d.items.map((it) => it.id === id ? { ...it, ...p } : it) }));
  const removeItem = (id) => setDraft((d) => ({ ...d, items: d.items.filter((it) => it.id !== id) }));

  // Build the print HTML for export — always without the watermark (the user
  // has earned a clean menu by creating an account at this point).
  const buildExportHtml = () => window.MFMenuPrint.render(
    draft.templateId, { brand: draft.brand, categories: draft.categories, items: draft.items, locale: 'es-MX' },
    { paper: draft.paper, watermark: false }
  );

  const exportPdf = async () => {
    setExp('loading');
    try {
      if (typeof firebase === 'undefined' || !firebase.functions) throw new Error('sin conexión');
      const fn = firebase.functions().httpsCallable('renderMenuPdf', { timeout: 120000 });
      const res = await fn({ html: buildExportHtml() });
      const b64 = res && res.data && res.data.pdf;
      if (!b64) throw new Error('respuesta vacía');
      mdDownloadPdf(b64, mdSlug(draft.brand.name) + '-carta.pdf');
      setExp('done');
      setTimeout(() => setExp(null), 2600);
    } catch (e) {
      console.warn('[export]', e);
      setExp('error');
      setToast({ msg: 'No se pudo generar el PDF — inténtalo de nuevo', tone: 'error' });
      setTimeout(() => setExp(null), 4000);
    }
  };

  const runAction = (action) => {
    if (action === 'export') exportPdf();
    else if (action === 'ai') setAiOpen(true);
  };

  // Gemini art-direction: a free-text vibe → template/accent/tagline + rewritten
  // dish descriptions. Routed through the auth'd generateAI Cloud Function.
  const aiPersonalize = async () => {
    const vibe = aiText.trim();
    if (!vibe) return;
    setAiBusy('loading');
    try {
      if (typeof window._geminiGenerate !== 'function') throw new Error('sin IA');
      const tpls = window.MFMenuPrint.TEMPLATES.map((t) => t.id + ' (' + t.desc + ')').join('; ');
      const items = draft.items.slice(0, 40).map((it) => ({ id: it.id, name: it.name, description: it.description }));
      const system = 'Eres director de arte y copywriter gastronómico. Respondes SOLO con JSON válido, sin markdown ni texto extra.';
      const prompt =
        'Restaurante: "' + (draft.brand.name || 'Restaurante') + '". Ambiente deseado: "' + vibe + '".\n' +
        'Plantillas disponibles: ' + tpls + '.\n' +
        'Platillos (id, name, description):\n' + JSON.stringify(items) + '\n\n' +
        'Devuelve EXACTAMENTE este JSON:\n' +
        '{"templateId":"<olivo|esmeralda|lino|cobre>","accent":"#RRGGBB","tagline":"<eslogan corto en español>",' +
        '"items":[{"id":"<id existente>","description":"<descripción apetitosa de 1 línea, mismo idioma>"}]}\n' +
        'Elige la plantilla y el color que mejor encajen con el ambiente. Reescribe SOLO las descriptions, conserva los id exactos. No inventes platillos nuevos.';
      const raw = await window._geminiGenerate({ systemInstruction: system, prompt, temperature: 0.6, maxOutputTokens: 2048, responseMimeType: 'application/json' });
      const j = mdParseJSON(raw);
      if (!j) throw new Error('respuesta no válida');
      setDraft((d) => {
        const validTpl = window.MFMenuPrint.TEMPLATES.some((t) => t.id === j.templateId) ? j.templateId : d.templateId;
        const descById = {};
        (j.items || []).forEach((x) => { if (x && x.id) descById[x.id] = x.description; });
        return {
          ...d, templateId: validTpl,
          brand: { ...d.brand, accent: mdValidHex(j.accent) || d.brand.accent, tagline: (j.tagline && String(j.tagline).slice(0, 60)) || d.brand.tagline },
          items: d.items.map((it) => descById[it.id] != null ? { ...it, description: String(descById[it.id]) } : it),
        };
      });
      setAiBusy('idle'); setAiOpen(false);
      setToast({ msg: 'Tu carta se personalizó con IA ✨', tone: 'info' });
    } catch (e) {
      console.warn('[ai]', e);
      setAiBusy('error');
    }
  };

  // Paste a raw menu (from a PDF, a Word doc, anywhere) → extractMenu structures
  // it into categories + dishes. Works for anonymous users (free convenience).
  const extractPasted = async () => {
    const text = pasteText.trim();
    if (text.length < 10) { setPasteBusy('error'); return; }
    setPasteBusy('loading');
    try {
      if (typeof firebase === 'undefined' || !firebase.functions) throw new Error('sin conexión');
      const fn = firebase.functions().httpsCallable('extractMenu', { timeout: 60000 });
      const res = await fn({ text });
      const out = res && res.data;
      const cats = (out && out.categories) || [];
      const its  = (out && out.items) || [];
      if (!cats.length && !its.length) throw new Error('vacío');
      // Normalise extractMenu's i18n category names to plain strings + fresh ids.
      const idMap = {};
      const categories = cats.map((c, i) => {
        const id = c.id || mdId('c');
        idMap[c.id] = id;
        const nm = c.name && typeof c.name === 'object' ? (c.name.es || c.name.en || '') : (c.name || 'Sección ' + (i + 1));
        return { id, name: nm };
      });
      const fallbackCat = categories[0] && categories[0].id;
      const items = its.map((it) => ({
        id: it.id || mdId('i'),
        category: idMap[it.category] || (categories.some((c) => c.id === it.category) ? it.category : fallbackCat),
        name: it.name || '', description: it.description || '', price: Number(it.price) || 0,
        tags: Array.isArray(it.tags) ? it.tags : [],
      })).filter((it) => it.name);
      if (!categories.length || !items.length) throw new Error('incompleto');
      setDraft((d) => ({ ...d, categories, items }));
      setPasteBusy('idle'); setPasteOpen(false); setPasteText('');
      setToast({ msg: 'Importamos ' + items.length + ' platillos ✨', tone: 'info' });
    } catch (e) {
      console.warn('[paste]', e);
      setPasteBusy('error');
    }
  };

  // Logged-in owner on /crear: pull their brand (name/eslogan/color) into the draft.
  const importBrand = () => {
    const b = (profile && profile.brand) || {};
    const name    = (b.name && (b.name.es || b.name)) || draft.brand.name;
    const tagline = (b.tagline && (b.tagline.es || b.tagline)) || draft.brand.tagline;
    const accent  = (b.palette && b.palette.gold) || b.accent || draft.brand.accent;
    setBrand({ name, tagline, accent });
    setToast({ msg: 'Usamos los datos de tu restaurante', tone: 'info' });
  };

  // The gate: a free user is sent to signup; an authed user runs the action now.
  const gate = (action) => {
    try { localStorage.setItem(MD_DRAFT_KEY, JSON.stringify(draft)); } catch (_) {}
    if (authed) runAction(action);
    else if (onRequireAccount) onRequireAccount(action);
  };

  // After signup the parent sets `autorun` to the action they were reaching for;
  // fire it once, then clear it so it never repeats.
  useEffectMD(() => {
    if (autorun && authed) {
      runAction(autorun);
      if (onAutorunDone) onAutorunDone();
    }
  }, [autorun, authed]);

  // auto-dismiss toasts
  useEffectMD(() => {
    if (!toast) return;
    const t = setTimeout(() => setToast(null), 3200);
    return () => clearTimeout(t);
  }, [toast]);

  // The reveal fires only on a fresh in-session signup (authed false → true),
  // never for a returning owner who arrives already logged in.
  useEffectMD(() => {
    if (authed && !wasAuthedRef.current) setReveal(true);
    wasAuthedRef.current = authed;
  }, [authed]);

  // ── layout ─────────────────────────────────────────────────────────────────
  const cap = { fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--mu)' };

  const Gallery = (
    <div style={{ display: 'grid', gridTemplateColumns: mobile ? 'repeat(4,1fr)' : '1fr 1fr', gap: 12 }}>
      {window.MFMenuPrint.TEMPLATES.map((t) => {
        const selected = render.templateId === t.id;
        return (
          <button key={t.id} onClick={() => patch({ templateId: t.id })} title={t.name}
            style={{
              padding: 0, border: '1px solid ' + (selected ? 'var(--accent)' : 'var(--line)'),
              boxShadow: selected ? '0 0 0 3px var(--accent-tint)' : 'var(--sh-1)',
              borderRadius: 'var(--r-md)', overflow: 'hidden', cursor: 'pointer', background: 'var(--paper-2)',
              transition: 'box-shadow 160ms ease, border-color 160ms ease', textAlign: 'left',
            }}>
            <div style={{ position: 'relative', height: mobile ? 96 : 150, overflow: 'hidden', background: t.tone === 'dark' ? '#15110a' : '#efeae0' }}>
              <iframe title={t.name} aria-hidden="true" tabIndex={-1}
                srcDoc={window.MFMenuPrint.render(t.id, data, { paper: 'A4', watermark: false })}
                style={{
                  position: 'absolute', top: 0, left: 0, width: 794, height: 1123, border: 'none',
                  transform: 'scale(' + (mobile ? 0.118 : 0.213) + ')', transformOrigin: 'top left', pointerEvents: 'none',
                }} />
            </div>
            {!mobile && (
              <div style={{ padding: '8px 12px' }}>
                <div style={{ fontWeight: 600, fontSize: 13 }}>{t.name}</div>
                <div style={{ fontSize: 11, color: 'var(--mu)', marginTop: 2, lineHeight: 1.3 }}>{t.desc}</div>
              </div>
            )}
          </button>
        );
      })}
    </div>
  );

  const Seg = ({ value, set, options }) => (
    <div className="seg" style={{ display: 'inline-flex', gap: 4, background: 'var(--paper-2)', padding: 4, borderRadius: 'var(--r-md)', border: '1px solid var(--line)' }}>
      {options.map((o) => (
        <button key={o} onClick={() => set(o)} style={{
          height: 30, padding: '0 12px', borderRadius: 'var(--r-sm)', cursor: 'pointer',
          border: '1px solid transparent', fontWeight: 600, fontSize: 12,
          background: value === o ? 'var(--ink)' : 'transparent', color: value === o ? 'var(--paper)' : 'var(--ink-2)',
          transition: 'background 160ms ease, color 160ms ease',
        }}>{o}</button>
      ))}
    </div>
  );

  const Editor = (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 24 }}>
      {/* Brand */}
      <section style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div style={cap}>Tu marca</div>
          {profile && <button className="btn ghost sm" onClick={importBrand} title="Usar los datos de mi restaurante">Usar mi marca</button>}
        </div>
        <MDField label="Nombre del restaurante">
          <input value={draft.brand.name} onChange={(e) => setBrand({ name: e.target.value })} style={mdInput} placeholder="Casa Lupita" />
        </MDField>
        <MDField label="Eslogan (opcional)">
          <input value={draft.brand.tagline} onChange={(e) => setBrand({ tagline: e.target.value })} style={mdInput} placeholder="Cocina de autor" />
        </MDField>
        <MDField label="Color de acento">
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <input type="color" value={draft.brand.accent || '#8A7A50'} onChange={(e) => setBrand({ accent: e.target.value })}
              style={{ width: 40, height: 40, padding: 2, border: '1px solid var(--line)', borderRadius: 'var(--r-sm)', cursor: 'pointer', background: 'var(--paper)' }} />
            <input value={draft.brand.accent || ''} onChange={(e) => setBrand({ accent: e.target.value })} style={{ ...mdInput, width: 120 }} placeholder="#8A7A50" />
          </div>
        </MDField>
      </section>

      {/* Sections + dishes */}
      <section style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div style={cap}>Tu carta</div>
          <div style={{ display: 'flex', gap: 6 }}>
            <button className="btn ghost sm" onClick={() => setPasteOpen(true)} title="Pegar mi carta y dejar que la IA la ordene">Pegar carta</button>
            <button className="btn ghost sm" onClick={addCategory} title="Añadir sección">+ Sección</button>
          </div>
        </div>
        {draft.categories.map((c) => {
          const its = draft.items.filter((it) => it.category === c.id);
          return (
            <div key={c.id} className="card" style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 10 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <input value={c.name} onChange={(e) => renameCategory(c.id, e.target.value)} style={{ ...mdInput, fontWeight: 600 }} placeholder="Nombre de la sección" />
                <button className="btn ghost sm" title="Eliminar sección" onClick={() => removeCategory(c.id)} style={{ color: 'var(--warn)', flexShrink: 0 }}>✕</button>
              </div>
              {its.map((it) => (
                <div key={it.id} style={{ display: 'flex', flexDirection: 'column', gap: 6, paddingLeft: 10, borderLeft: '2px solid var(--line)' }}>
                  <div style={{ display: 'flex', gap: 6 }}>
                    <input value={it.name} onChange={(e) => patchItem(it.id, { name: e.target.value })} style={mdInput} placeholder="Nombre del platillo" />
                    <div style={{ display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0 }}>
                      <span style={{ color: 'var(--mu)', fontSize: 13 }}>$</span>
                      <input type="number" value={it.price} onChange={(e) => patchItem(it.id, { price: Number(e.target.value) })} style={{ ...mdInput, width: 76 }} className="mono" />
                    </div>
                    <button className="btn ghost sm" title="Eliminar platillo" onClick={() => removeItem(it.id)} style={{ color: 'var(--warn)', flexShrink: 0 }}>✕</button>
                  </div>
                  <input value={it.description} onChange={(e) => patchItem(it.id, { description: e.target.value })} style={{ ...mdInput, fontSize: 12 }} placeholder="Descripción (opcional)" />
                </div>
              ))}
              <button className="btn ghost sm" onClick={() => addItem(c.id)} style={{ alignSelf: 'flex-start' }}>+ Platillo</button>
            </div>
          );
        })}
      </section>
    </div>
  );

  const Preview = (
    <div ref={previewRef} style={{ flex: 1, minHeight: 0, display: 'flex', alignItems: mobile ? 'flex-start' : 'center', justifyContent: 'center', overflow: 'auto', background: 'var(--paper-3, #e8e4dc)', borderRadius: mobile ? 0 : 'var(--r-lg)', padding: mobile ? 12 : 24 }}>
      <div style={{ width: 794 * pscale, height: 1123 * pscale, flexShrink: 0 }}>
        <iframe title="Vista previa de la carta" srcDoc={previewHtml}
          style={{ width: 794, height: 1123, border: 'none', background: '#fff', boxShadow: 'var(--sh-3)', borderRadius: 4, transform: 'scale(' + pscale + ')', transformOrigin: 'top left' }} />
      </div>
    </div>
  );

  const exporting = exp === 'loading';
  const exportLabel = exp === 'loading' ? 'Generando…' : exp === 'done' ? 'Descargado ✓' : 'Descargar PDF';
  const Actions = (
    <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
      <button className="btn ghost" onClick={() => gate('ai')} title="Personalizar con IA">✨ Personalizar con IA</button>
      <button className="btn accent" onClick={() => gate('export')} disabled={exporting} title="Descargar PDF"
        style={exporting ? { opacity: 0.7, cursor: 'not-allowed' } : undefined}>{exportLabel}</button>
    </div>
  );

  const ToastEl = toast ? (
    <div className="fade-up" style={{
      position: 'fixed', left: '50%', bottom: mobile ? 84 : 24, transform: 'translateX(-50%)', zIndex: 130,
      padding: '12px 20px', borderRadius: 999, fontSize: 13, fontWeight: 500, maxWidth: '90vw', textAlign: 'center',
      background: toast.tone === 'error' ? 'rgba(220,38,38,0.10)' : 'var(--ink)',
      color: toast.tone === 'error' ? '#b91c1c' : 'var(--paper)',
      border: toast.tone === 'error' ? '1px solid rgba(220,38,38,0.25)' : '1px solid transparent',
      boxShadow: 'var(--sh-3)',
    }}>{toast.msg}</div>
  ) : null;

  const AIModal = aiOpen ? (
    <div onClick={() => aiBusy !== 'loading' && setAiOpen(false)}
      style={{ position: 'fixed', inset: 0, zIndex: 140, background: 'rgba(10,8,5,0.55)', backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)', display: 'flex', alignItems: mobile ? 'flex-end' : 'center', justifyContent: 'center', padding: mobile ? 0 : 24 }}>
      <div onClick={(e) => e.stopPropagation()} className="fade-up" style={{ width: mobile ? '100%' : 560, maxWidth: '100%', maxHeight: '90vh', display: 'flex', flexDirection: 'column', background: 'var(--paper)', borderRadius: mobile ? 'var(--r-lg) var(--r-lg) 0 0' : 'var(--r-lg)', boxShadow: 'var(--sh-3)', overflow: 'hidden' }}>
        <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', padding: '28px 28px 16px' }}>
          <div>
            <div className="serif" style={{ fontStyle: 'italic', fontSize: 22 }}>Personaliza con IA</div>
            <div style={{ fontSize: 13, color: 'var(--mu)', marginTop: 4, maxWidth: 400, lineHeight: 1.45 }}>Describe el ambiente de tu restaurante y la IA ajustará la plantilla, el color y las descripciones de tus platillos.</div>
          </div>
          <button onClick={() => setAiOpen(false)} title="Cerrar" style={{ width: 36, height: 36, borderRadius: '50%', border: '1px solid var(--line)', background: 'var(--paper-2)', cursor: 'pointer', flexShrink: 0, fontSize: 15 }}>✕</button>
        </div>
        <div style={{ padding: '0 28px', overflow: 'auto' }}>
          <textarea value={aiText} onChange={(e) => setAiText(e.target.value)} rows={4}
            placeholder="Ej: elegante y oscuro, como un bar de vinos en Buenos Aires…"
            style={{ width: '100%', padding: '12px 14px', border: '1px solid var(--line)', borderRadius: 'var(--r-sm)', fontSize: 14, resize: 'vertical', outline: 'none', fontFamily: 'inherit', color: 'var(--ink)', background: 'var(--paper)', lineHeight: 1.5 }} />
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, marginTop: 12 }}>
            {['Elegante y minimalista', 'Cálido y rústico', 'Moderno y vibrante', 'Fino y nocturno'].map((s) => (
              <button key={s} onClick={() => setAiText(s)} className="chip" style={{ cursor: 'pointer', fontSize: 12, border: '1px solid var(--line)', background: 'var(--paper-2)', borderRadius: 999, padding: '6px 12px' }}>{s}</button>
            ))}
          </div>
          {aiBusy === 'error' && (
            <div style={{ marginTop: 14, padding: '10px 14px', borderRadius: 'var(--r-sm)', background: 'rgba(220,38,38,0.10)', color: '#b91c1c', fontSize: 13 }}>No se pudo personalizar — inténtalo de nuevo.</div>
          )}
        </div>
        <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end', padding: '20px 28px calc(20px + env(safe-area-inset-bottom, 0px))', marginTop: 8 }}>
          <button className="btn ghost" onClick={() => setAiOpen(false)}>Cancelar</button>
          <button className="btn accent" onClick={aiPersonalize} disabled={aiBusy === 'loading' || !aiText.trim()}
            style={aiBusy === 'loading' || !aiText.trim() ? { opacity: 0.7, cursor: 'not-allowed' } : undefined}>
            {aiBusy === 'loading' ? 'Personalizando…' : 'Personalizar'}
          </button>
        </div>
      </div>
    </div>
  ) : null;

  const PasteModal = pasteOpen ? (
    <div onClick={() => pasteBusy !== 'loading' && setPasteOpen(false)}
      style={{ position: 'fixed', inset: 0, zIndex: 140, background: 'rgba(10,8,5,0.55)', backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)', display: 'flex', alignItems: mobile ? 'flex-end' : 'center', justifyContent: 'center', padding: mobile ? 0 : 24 }}>
      <div onClick={(e) => e.stopPropagation()} className="fade-up" style={{ width: mobile ? '100%' : 560, maxWidth: '100%', maxHeight: '90vh', display: 'flex', flexDirection: 'column', background: 'var(--paper)', borderRadius: mobile ? 'var(--r-lg) var(--r-lg) 0 0' : 'var(--r-lg)', boxShadow: 'var(--sh-3)', overflow: 'hidden' }}>
        <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', padding: '28px 28px 16px' }}>
          <div>
            <div className="serif" style={{ fontStyle: 'italic', fontSize: 22 }}>Pega tu carta</div>
            <div style={{ fontSize: 13, color: 'var(--mu)', marginTop: 4, maxWidth: 400, lineHeight: 1.45 }}>Copia el texto de tu menú actual (PDF, Word, foto…). La IA lo ordena en secciones y platillos por ti.</div>
          </div>
          <button onClick={() => setPasteOpen(false)} title="Cerrar" style={{ width: 36, height: 36, borderRadius: '50%', border: '1px solid var(--line)', background: 'var(--paper-2)', cursor: 'pointer', flexShrink: 0, fontSize: 15 }}>✕</button>
        </div>
        <div style={{ padding: '0 28px', overflow: 'auto' }}>
          <textarea value={pasteText} onChange={(e) => setPasteText(e.target.value)} rows={8}
            placeholder={'Entradas\nGuacamole — 95\nTostada de atún, aguacate, serrano — 185\n\nPlatos fuertes\nCochinita pibil — 240'}
            style={{ width: '100%', padding: '12px 14px', border: '1px solid var(--line)', borderRadius: 'var(--r-sm)', fontSize: 13, resize: 'vertical', outline: 'none', fontFamily: 'inherit', color: 'var(--ink)', background: 'var(--paper)', lineHeight: 1.5 }} />
          {pasteBusy === 'error' && (
            <div style={{ marginTop: 14, padding: '10px 14px', borderRadius: 'var(--r-sm)', background: 'rgba(220,38,38,0.10)', color: '#b91c1c', fontSize: 13 }}>No pudimos leer la carta — revisa el texto e inténtalo de nuevo.</div>
          )}
          <div style={{ marginTop: 12, fontSize: 11, color: 'var(--mu-2, var(--mu))' }}>Reemplazará las secciones y platillos actuales.</div>
        </div>
        <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end', padding: '20px 28px calc(20px + env(safe-area-inset-bottom, 0px))', marginTop: 8 }}>
          <button className="btn ghost" onClick={() => setPasteOpen(false)}>Cancelar</button>
          <button className="btn accent" onClick={extractPasted} disabled={pasteBusy === 'loading' || pasteText.trim().length < 10}
            style={pasteBusy === 'loading' || pasteText.trim().length < 10 ? { opacity: 0.7, cursor: 'not-allowed' } : undefined}>
            {pasteBusy === 'loading' ? 'Analizando…' : 'Analizar con IA'}
          </button>
        </div>
      </div>
    </div>
  ) : null;

  // ── Phase 6: the platform reveal — reframes the menu-maker as the front door ─
  const RevealModal = reveal ? (
    <div style={{ position: 'fixed', inset: 0, zIndex: 150, background: 'rgba(10,8,5,0.6)', backdropFilter: 'blur(10px)', WebkitBackdropFilter: 'blur(10px)', display: 'flex', alignItems: mobile ? 'flex-end' : 'center', justifyContent: 'center', padding: mobile ? 0 : 24, overflow: 'auto' }}>
      <div className="fade-up" style={{ width: mobile ? '100%' : 600, maxWidth: '100%', background: 'var(--paper)', borderRadius: mobile ? 'var(--r-lg) var(--r-lg) 0 0' : 'var(--r-lg)', boxShadow: 'var(--sh-3)', overflow: 'hidden' }}>
        <div style={{ padding: '36px 32px 0', textAlign: 'center' }}>
          <div className="serif" style={{ fontStyle: 'italic', fontSize: 28, lineHeight: 1.15 }}>Tu carta está lista</div>
          <p style={{ fontSize: 14, color: 'var(--ink-2)', marginTop: 12, maxWidth: 430, marginLeft: 'auto', marginRight: 'auto', lineHeight: 1.55 }}>
            Acabas de diseñar tu menú en minutos. Pero tu restaurante puede ser mucho más — y la misma carta lo hace todo.
          </p>
        </div>
        <div style={{ padding: '24px 32px 8px', display: 'grid', gridTemplateColumns: mobile ? '1fr' : '1fr 1fr', gap: 12 }}>
          {[
            { icon: '📱', t: 'Carta digital con QR', d: 'Tus comensales la escanean en la mesa.' },
            { icon: '🧾', t: 'Pedidos a tu cocina', d: 'Directo a la consola, sin papel.' },
            { icon: '🍷', t: 'Sommelier IA', d: 'Sugiere y vende por ti.' },
            { icon: '📊', t: 'Mesas y ventas en vivo', d: 'Todo tu salón, en tiempo real.' },
          ].map((f) => (
            <div key={f.t} className="card" style={{ padding: 16, display: 'flex', gap: 12, alignItems: 'flex-start' }}>
              <div style={{ fontSize: 20, lineHeight: 1 }}>{f.icon}</div>
              <div><div style={{ fontWeight: 600, fontSize: 13 }}>{f.t}</div><div style={{ fontSize: 12, color: 'var(--mu)', marginTop: 2, lineHeight: 1.4 }}>{f.d}</div></div>
            </div>
          ))}
        </div>
        <div style={{ padding: '16px 32px calc(28px + env(safe-area-inset-bottom, 0px))', display: 'flex', flexDirection: mobile ? 'column-reverse' : 'row', gap: 10, justifyContent: 'center' }}>
          <button className="btn ghost" onClick={() => setReveal(false)} style={mobile ? { width: '100%' } : undefined}>Seguir editando mi carta</button>
          <button className="btn accent" onClick={() => { setReveal(false); if (onBuildRestaurant) onBuildRestaurant(draft); }} style={mobile ? { width: '100%' } : undefined}>Crear mi restaurante inteligente →</button>
        </div>
      </div>
    </div>
  ) : null;

  // ── desktop ──────────────────────────────────────────────────────────────
  if (!mobile) {
    return (
      <div style={{ position: 'fixed', inset: 0, background: 'var(--paper)', display: 'flex', flexDirection: 'column', zIndex: 90 }}>
        <header style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '14px 24px', borderBottom: '1px solid var(--line)', flexShrink: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
            <button className="btn ghost sm" onClick={onClose} title="Volver">← Volver</button>
            <div>
              <div className="serif" style={{ fontStyle: 'italic', fontSize: 18 }}>Diseña tu carta</div>
              <div style={{ fontSize: 11, color: 'var(--mu)' }}>Gratis · imprime o comparte en minutos</div>
            </div>
          </div>
          {Actions}
        </header>
        <div style={{ flex: 1, minHeight: 0, display: 'grid', gridTemplateColumns: '300px 1fr 360px' }}>
          <aside style={{ borderRight: '1px solid var(--line)', padding: 20, overflow: 'auto', display: 'flex', flexDirection: 'column', gap: 20 }}>
            <div>
              <div style={{ ...cap, marginBottom: 12 }}>Plantilla</div>
              {Gallery}
            </div>
            <div>
              <div style={{ ...cap, marginBottom: 10 }}>Tamaño de papel</div>
              <Seg value={draft.paper} set={(p) => patch({ paper: p })} options={['A4', 'Letter', 'A5']} />
            </div>
          </aside>
          {Preview}
          <aside style={{ borderLeft: '1px solid var(--line)', padding: 20, overflow: 'auto' }}>{Editor}</aside>
        </div>
        {ToastEl}
        {AIModal}
        {PasteModal}
        {RevealModal}
      </div>
    );
  }

  // ── mobile ───────────────────────────────────────────────────────────────
  return (
    <div style={{ position: 'fixed', inset: 0, background: 'var(--paper)', display: 'flex', flexDirection: 'column', zIndex: 90 }}>
      <header style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '12px 16px', borderBottom: '1px solid var(--line)', flexShrink: 0 }}>
        <button className="btn ghost sm" onClick={onClose} title="Volver">←</button>
        <div className="serif" style={{ fontStyle: 'italic', fontSize: 16 }}>Diseña tu carta</div>
        <Seg value={tab} set={setTab} options={['preview', 'editar']} />
      </header>
      {tab === 'preview' ? (
        <div style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>
          <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--line)' }}>
            <div style={{ ...cap, marginBottom: 10 }}>Plantilla</div>
            {Gallery}
          </div>
          {Preview}
        </div>
      ) : (
        <div style={{ flex: 1, minHeight: 0, overflow: 'auto', padding: '16px 16px 28px' }}>{Editor}</div>
      )}
      <div style={{ flexShrink: 0, padding: '12px 16px calc(12px + env(safe-area-inset-bottom, 0px))', borderTop: '1px solid var(--line)', display: 'flex', gap: 10 }}>
        <button className="btn ghost" style={{ flex: 1 }} onClick={() => gate('ai')}>✨ IA</button>
        <button className="btn accent" style={{ flex: 2, ...(exporting ? { opacity: 0.7, cursor: 'not-allowed' } : {}) }} disabled={exporting} onClick={() => gate('export')}>{exportLabel}</button>
      </div>
      {ToastEl}
      {AIModal}
      {PasteModal}
      {RevealModal}
    </div>
  );
};

const mdInput = {
  flex: 1, width: '100%', height: 38, padding: '8px 12px', border: '1px solid var(--line)',
  borderRadius: 'var(--r-sm)', fontSize: 13, color: 'var(--ink)', background: 'var(--paper)', outline: 'none',
};

function MDField({ label, children }) {
  return (
    <label style={{ display: 'block' }}>
      <div style={{ fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--mu)', marginBottom: 7 }}>{label}</div>
      {children}
    </label>
  );
}
