// app.jsx — TMS Email Builder main app
// JWT bootstrap runs in jwt-bootstrap.js (loaded in <head>) before this script evaluates.

const { useState, useRef, useEffect } = React;

let _uid = 100;
const uid = () => `b${_uid++}`;

const CRUISE_API = 'https://tms-cruises-api.tms-travel-marketing-systems.workers.dev';

const DEFAULTS = {
  header: {
    logoText: 'TMS Travel Marketing',
    logoUrl: '',
    tagline: 'Your trusted travel experts',
    phone: '',
    bgColor: '#0A6E6E',
    textColor: '#ffffff',
    socials: { facebook: '', instagram: '', whatsapp: '', linkedin: '' },
  },
  offer: {
    destination: "Maldives", headline: "7 nights all-inclusive at a 5★ overwater resort — flights from London included.",
    price: "£1,299pp", badge: "ATOL Protected", availability: "Limited availability — book by 30 June",
    imageUrl: "", buttonText: "View this offer", buttonColor: "#0E8A99", ctaUrl: "", operator: "",
  },
  text: { html: "Add your email message here. <strong>Bold text</strong> and <a href=\"#\">links</a> are supported — tell your clients exactly why this trip is unmissable and add a personal note from the team." },
  image: { imageUrl: "", alt: "" },
  video: { thumbUrl: "", title: "Watch the destination film", link: "" },
  footer: {
    company: "Travel Marketing Systems Ltd", address: "123 High Street, London, UK",
    bgColor: '#F0F1F4', textColor: '#4D4A44',
  },
  cruise: {
    cruiseName: 'Mediterranean Discovery', operatorLine: 'MSC Cruises · MSC Bellissima',
    departureDate: '', duration: '7', departurePort: '', regions: '',
    price: 'From £899pp', imageUrl: '', ctaUrl: '', teaser: '', promoBadge: '',
    cruiseType: 'ocean', ctaColor: '#0A6E7E',
  },
};

const makeBlock = (type, override) => {
  const base = { ...DEFAULTS[type] };
  const brand = (window.TMS_CONFIG || {}).brandSettings || {};
  if (type === 'header') {
    if (brand.companyName) base.logoText = brand.companyName;
    if (brand.tagline)     base.tagline  = brand.tagline;
  }
  if (type === 'footer') {
    if (brand.companyName) base.company = brand.companyName;
    if (brand.address)     base.address = brand.address;
  }
  return { id: uid(), type, props: { ...base, ...(override || {}) } };
};

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "canvasSurface": "paper",
  "selectStyle": "ring",
  "density": "comfortable"
}/*EDITMODE-END*/;

function ExportModal({ html, onClose }) {
  const [copied, setCopied] = React.useState(false);
  const copyTimer = React.useRef(null);
  const { Copy, Check, Download } = window.Icons;

  const handleCopy = () => {
    navigator.clipboard.writeText(html).then(() => {
      setCopied(true);
      clearTimeout(copyTimer.current);
      copyTimer.current = setTimeout(() => setCopied(false), 2000);
    });
  };

  const handleDownload = () => {
    const a = document.createElement('a');
    a.href = 'data:text/html;charset=utf-8,' + encodeURIComponent(html);
    a.download = 'email-campaign.html';
    a.click();
  };

  return (
    <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.5)', zIndex: 100, display: 'flex', alignItems: 'center', justifyContent: 'center' }}
         onClick={onClose}>
      <div style={{ width: 600, maxHeight: '85vh', display: 'flex', flexDirection: 'column', background: 'var(--product-surface)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-lg)', overflow: 'hidden' }}
           onClick={(e) => e.stopPropagation()}>
        <div style={{ padding: '20px 24px 16px', borderBottom: '1px solid var(--product-border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexShrink: 0 }}>
          <h3 style={{ margin: 0, fontSize: 'var(--fs-h4)', fontWeight: 600, color: 'var(--product-fg)' }}>Export email HTML</h3>
          <button className="bld-action" onClick={onClose} style={{ width: 32, height: 32, fontSize: 16 }}>✕</button>
        </div>
        <div style={{ flex: 1, overflow: 'auto', minHeight: 0 }}>
          <pre style={{ margin: 0, padding: '16px 20px', fontFamily: 'var(--font-mono)', fontSize: 11, lineHeight: 1.6, background: '#0F1C31', color: '#C5EAEE', overflow: 'auto', whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>
            <code>{html}</code>
          </pre>
        </div>
        <div style={{ padding: '16px 24px', borderTop: '1px solid var(--product-border)', display: 'flex', gap: 8, justifyContent: 'flex-end', flexShrink: 0 }}>
          <button className="bld-btn bld-btn--outline" onClick={handleDownload}><Download />Download .html</button>
          <button className="bld-btn bld-btn--primary" onClick={handleCopy}>
            {copied ? <><Check />Copied!</> : <><Copy />Copy HTML</>}
          </button>
        </div>
      </div>
    </div>
  );
}

function AddToHomePrompt({ onDismiss, deferredPrompt, onInstall }) {
  const isIOS = /iphone|ipad|ipod/i.test(navigator.userAgent);
  const canInstall = !!deferredPrompt;
  const btnStyle = {
    width: '100%', padding: '10px',
    background: '#0A6E6E', color: '#ffffff',
    border: 'none', borderRadius: '8px',
    fontSize: '13px', fontWeight: '600', cursor: 'pointer',
  };
  return (
    <div style={{
      position: 'fixed',
      bottom: 'calc(68px + env(safe-area-inset-bottom, 0px))',
      left: '12px', right: '12px',
      background: '#ffffff',
      borderRadius: '16px',
      padding: '16px',
      boxShadow: '0 4px 24px rgba(0,0,0,0.15)',
      border: '1px solid var(--product-border)',
      zIndex: 200,
      display: 'flex', flexDirection: 'column', gap: '12px',
      animation: 'slideUp 0.3s ease',
    }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', gap: '12px' }}>
        <div style={{
          width: '48px', height: '48px', borderRadius: '12px',
          background: '#0A6E6E', display: 'flex',
          alignItems: 'center', justifyContent: 'center',
          flexShrink: 0, fontSize: '24px',
        }}>✉️</div>
        <div style={{ flex: 1 }}>
          <div style={{ fontWeight: '600', fontSize: '14px', marginBottom: '4px', color: 'var(--product-fg)' }}>
            Add to Home Screen
          </div>
          <div style={{ fontSize: '12px', color: 'var(--product-fg-muted)', lineHeight: '1.5' }}>
            {canInstall
              ? <>Tap <strong>Install App</strong> below to add TMS Email Builder to your home screen</>
              : isIOS
                ? <>Tap <strong>Share</strong> <span style={{ fontSize: '16px' }}>⬆️</span> then <strong>"Add to Home Screen"</strong> for quick access</>
                : <>Tap the <strong>menu ⋮</strong> then <strong>"Add to Home Screen"</strong> for quick access</>
            }
          </div>
        </div>
        <button onClick={onDismiss} style={{
          background: 'none', border: 'none', fontSize: '20px',
          color: 'var(--product-fg-muted)', cursor: 'pointer', padding: '0',
          lineHeight: 1, flexShrink: 0,
        }}>×</button>
      </div>
      {!canInstall && isIOS && (
        <div style={{
          background: '#f5f4f1', borderRadius: '8px',
          padding: '10px 12px', fontSize: '12px', color: 'var(--product-fg-muted)',
          display: 'flex', alignItems: 'center', gap: '8px',
        }}>
          <span style={{ fontSize: '18px' }}>💡</span>
          Works offline once installed — build emails anywhere, even without signal
        </div>
      )}
      {canInstall
        ? <button onClick={onInstall} style={btnStyle}>Install App</button>
        : <button onClick={onDismiss} style={btnStyle}>Got it</button>
      }
    </div>
  );
}

// ── Settings modal ──────────────────────────────────────────────────────────
function SettingsModal({ onClose, onSubjectChange, subject: subjectProp }) {
  const cfg        = window.TMS_CONFIG || {};
  const workerUrl  = (cfg.workerUrl || 'https://tms-promotions-api.tms-travel-marketing-systems.workers.dev').replace(/\/$/, '');
  const token      = cfg.agentToken || '';
  const [tab, setTab]           = useState('email');
  const [apiKeyInput, setApiKeyInput] = useState('');
  const [showKey, setShowKey]   = useState(false);
  const [fromName, setFromName] = useState('');
  const [fromEmail, setFromEmail] = useState('');
  const [listId, setListId]     = useState('');
  const [lists, setLists]       = useState([]);
  const [subject, setSubject]   = useState(subjectProp || '');
  const [saving, setSaving]     = useState(false);
  const [status, setStatus]     = useState(null);
  const [listsLoading, setListsLoading] = useState(false);
  const [saveMsg, setSaveMsg]   = useState('');

  useEffect(() => {
    if (!token) { setStatus('no_token'); return; }
    fetch(`${workerUrl}/email-builder/cm-config`, {
      headers: { 'Authorization': `Bearer ${token}` },
    }).then(r => r.json()).then(d => {
      setStatus(d.hasApiKey ? 'connected' : 'not_configured');
      setFromName(d.fromName || '');
      setFromEmail(d.fromEmail || '');
      setListId(d.listId || '');
      if (d.hasApiKey) fetchLists();
    }).catch(() => setStatus('not_configured'));
  }, []); // eslint-disable-line

  const fetchLists = () => {
    if (!token) return;
    setListsLoading(true);
    fetch(`${workerUrl}/email-builder/cm-lists`, {
      headers: { 'Authorization': `Bearer ${token}` },
    }).then(r => r.json()).then(d => {
      if (Array.isArray(d)) setLists(d);
    }).catch(() => {}).finally(() => setListsLoading(false));
  };

  const handleSave = async () => {
    if (!token) return;
    setSaving(true); setSaveMsg('');
    try {
      const body = { fromName, fromEmail, listId };
      if (apiKeyInput.trim()) body.apiKey = apiKeyInput.trim();
      const selList = lists.find(l => l.id === listId);
      if (selList) body.listName = selList.name;
      const res  = await fetch(`${workerUrl}/email-builder/cm-config`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
        body: JSON.stringify(body),
      });
      const data = await res.json();
      if (data.ok) {
        setStatus('connected');
        setSaveMsg('Saved');
        fetchLists();
      } else {
        setSaveMsg(data.error || 'Error saving');
      }
    } catch (e) {
      setSaveMsg('Save failed');
    }
    setSaving(false);
    onSubjectChange(subject);
  };

  const statusColor = status === 'connected' ? '#0A6E6E' : '#9b988f';
  const statusLabel = status === 'connected' ? 'Connected'
    : status === 'no_token' ? 'No agent token (dev mode)'
    : 'Not configured';

  return (
    <div style={{position:'fixed', inset:0, background:'rgba(0,0,0,0.5)', zIndex:100, display:'flex', alignItems:'center', justifyContent:'center', padding:'16px'}}
         onClick={onClose}>
      <div style={{width:'100%', maxWidth:500, maxHeight:'85vh', display:'flex', flexDirection:'column', background:'var(--product-surface)', borderRadius:'var(--radius-lg)', boxShadow:'var(--shadow-lg)', overflow:'hidden'}}
           onClick={e => e.stopPropagation()}>

        {/* Header */}
        <div style={{padding:'20px 24px 0', borderBottom:'1px solid var(--product-border)', flexShrink:0}}>
          <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:16}}>
            <h3 style={{margin:0, fontSize:16, fontWeight:700, fontFamily:'var(--font-display)', color:'var(--product-fg)'}}>Settings</h3>
            <button className="bld-action" onClick={onClose} style={{width:32, height:32, fontSize:16}}>✕</button>
          </div>
          <div style={{display:'flex'}}>
            {['email', 'design'].map(t => (
              <button key={t} onClick={() => setTab(t)} style={{
                padding:'8px 16px', border:'none', background:'none', cursor:'pointer',
                fontFamily:'var(--font-display)', fontWeight:600, fontSize:12.5,
                color: tab === t ? 'var(--tms-teal-600)' : 'var(--product-fg-muted)',
                borderBottom: tab === t ? '2px solid var(--tms-teal-500)' : '2px solid transparent',
                marginBottom:'-1px', letterSpacing:'0.01em',
              }}>
                {t === 'email' ? 'Email Settings' : 'Design'}
              </button>
            ))}
          </div>
        </div>

        <div style={{flex:1, overflowY:'auto', padding:'20px 24px 24px'}}>
          {tab === 'email' && (<>
            <div style={{fontWeight:700, fontSize:10, letterSpacing:'.14em', textTransform:'uppercase', color:'var(--product-fg-muted)', marginBottom:10}}>Campaign Monitor</div>
            <div style={{display:'flex', alignItems:'center', gap:6, marginBottom:16, fontSize:12}}>
              <div style={{width:8, height:8, borderRadius:'50%', background:statusColor, flexShrink:0}} />
              <span style={{color:statusColor, fontWeight:600}}>{statusLabel}</span>
            </div>

            <div className="bld-field" style={{marginBottom:10}}>
              <label>API Key</label>
              <div style={{display:'flex', gap:6}}>
                <input
                  type={showKey ? 'text' : 'password'}
                  className="bld-input"
                  value={apiKeyInput}
                  onChange={e => setApiKeyInput(e.target.value)}
                  placeholder={status === 'connected' ? '(key saved — paste to replace)' : 'Paste your CM API key'}
                  style={{flex:1, fontFamily:'var(--font-mono)', fontSize:12}}
                />
                <button className="bld-btn bld-btn--outline" onClick={() => setShowKey(v => !v)}
                        style={{flexShrink:0, padding:'5px 10px', fontSize:12, minWidth:52}}>
                  {showKey ? 'Hide' : 'Show'}
                </button>
              </div>
            </div>

            <div className="bld-field" style={{marginBottom:10}}>
              <label>From name</label>
              <input type="text" className="bld-input" value={fromName} onChange={e => setFromName(e.target.value)} placeholder="Your Travel Agency" />
            </div>
            <div className="bld-field" style={{marginBottom:10}}>
              <label>From email</label>
              <input type="email" className="bld-input" value={fromEmail} onChange={e => setFromEmail(e.target.value)} placeholder="hello@youragency.co.uk" />
            </div>
            <div className="bld-field" style={{marginBottom:16}}>
              <label>Subscriber list</label>
              {listsLoading ? (
                <div style={{fontSize:12, color:'var(--product-fg-muted)', padding:'8px 0'}}>Loading lists…</div>
              ) : lists.length > 0 ? (
                <select className="bld-select" value={listId} onChange={e => setListId(e.target.value)}>
                  <option value="">Select list…</option>
                  {lists.map(l => <option key={l.id} value={l.id}>{l.name}</option>)}
                </select>
              ) : (
                <div style={{fontSize:12, color:'var(--product-fg-muted)', padding:'4px 0'}}>
                  {status === 'connected' ? 'No lists found — check your CM account' : 'Save your API key first to load lists'}
                </div>
              )}
            </div>

            <div style={{display:'flex', alignItems:'center', gap:10, marginBottom:24}}>
              <button className="bld-btn bld-btn--primary" onClick={handleSave} disabled={saving}
                      style={{flex:1, justifyContent:'center'}}>
                {saving ? 'Saving…' : 'Save settings'}
              </button>
              {saveMsg && <span style={{fontSize:12, color: saveMsg === 'Saved' ? '#0A6E6E' : 'var(--tms-coral-600)'}}>{saveMsg}</span>}
            </div>

            <div style={{borderTop:'1px solid var(--product-border)', paddingTop:16}}>
              <div style={{fontWeight:700, fontSize:10, letterSpacing:'.14em', textTransform:'uppercase', color:'var(--product-fg-muted)', marginBottom:10}}>Send Options</div>
              <div className="bld-field">
                <label>Subject line</label>
                <input type="text" className="bld-input" value={subject} onChange={e => setSubject(e.target.value)}
                       placeholder="Our latest travel deals" />
              </div>
              <button className="bld-btn bld-btn--outline" style={{marginTop:8}} onClick={() => { onSubjectChange(subject); onClose(); }}>
                Apply subject
              </button>
            </div>
          </>)}

          {tab === 'design' && (
            <div style={{fontSize:13, color:'var(--product-fg-muted)', lineHeight:1.6}}>
              Use the <strong>⚙ Tweaks</strong> panel (bottom-left corner) to adjust canvas surface, selection style, and density.
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ── Send dropdown ───────────────────────────────────────────────────────────
function SendDropdown({ onSendTest, onCreateCampaign }) {
  const [open, setOpen] = useState(false);
  const { Mail, ChevronDown } = window.Icons;
  return (
    <div style={{position:'relative'}}>
      {open && <div style={{position:'fixed', inset:0, zIndex:19}} onClick={() => setOpen(false)} />}
      <button className="bld-btn bld-btn--primary" onClick={() => setOpen(v => !v)}
              style={{gap:4}}>
        <Mail /><span className="bld-btn-label">Send</span><ChevronDown />
      </button>
      {open && (
        <div style={{
          position:'absolute', top:'calc(100% + 6px)', right:0, zIndex:20,
          background:'var(--product-surface)', border:'1px solid var(--product-border)',
          borderRadius:10, boxShadow:'var(--shadow-lg)', padding:6,
          minWidth:190, display:'flex', flexDirection:'column', gap:1,
        }}>
          <button onClick={() => { setOpen(false); onSendTest(); }}
                  style={{display:'flex', alignItems:'center', gap:9, padding:'9px 10px', border:'none', borderRadius:7, background:'transparent', cursor:'pointer', fontFamily:'var(--font-display)', fontWeight:600, fontSize:13, color:'var(--product-fg)', textAlign:'left', width:'100%'}}>
            <Mail style={{width:15, height:15}} />Send test email
          </button>
          <button onClick={() => { setOpen(false); onCreateCampaign(); }}
                  style={{display:'flex', alignItems:'center', gap:9, padding:'9px 10px', border:'none', borderRadius:7, background:'transparent', cursor:'pointer', fontFamily:'var(--font-display)', fontWeight:600, fontSize:13, color:'var(--product-fg)', textAlign:'left', width:'100%'}}>
            <Mail style={{width:15, height:15}} />Create CM campaign
          </button>
        </div>
      )}
    </div>
  );
}

function relTime(date) {
  if (!date) return null;
  const mins = Math.floor((Date.now() - date.getTime()) / 60000);
  if (mins < 1) return 'Saved just now';
  if (mins === 1) return 'Saved 1 min ago';
  return `Saved ${mins} min ago`;
}

function App() {
  const [t, setTweak] = window.useTweaks(TWEAK_DEFAULTS);
  const [blocks, setBlocks] = useState(() => {
    const saved = window.TMS_SAVED_DESIGN;
    if (saved) {
      try {
        const parsed = typeof saved === 'string' ? JSON.parse(saved) : saved;
        if (Array.isArray(parsed.blocks)) return parsed.blocks;
      } catch {}
    }
    return [makeBlock("header"), makeBlock("offer"), makeBlock("text"), makeBlock("footer")];
  });
  const [selectedId, setSelectedId] = useState(null);
  const [preview, setPreview] = useState(false);
  const [insertAt, setInsertAt] = useState(null);
  const [toast, setToast] = useState(null);
  const [exportHtml, setExportHtml] = useState(null);
  const [designId, setDesignId] = useState(null);
  const [designName] = useState('Untitled');
  const [mobileTab, setMobileTab] = useState(null);
  const [isMobile, setIsMobile] = useState(() => window.innerWidth < 768);
  const [showA2HS, setShowA2HS] = useState(false);
  const [deferredPrompt, setDeferredPrompt] = useState(null);
  const [showSettings, setShowSettings] = useState(false);
  const [subject, setSubject] = useState(() => localStorage.getItem('tms-eb-subject') || 'Our latest travel deals');
  const [lastSavedAt, setLastSavedAt] = useState(null);
  const toastTimer = useRef(null);
  const drawerRef = useRef(null);
  const autoSaveTimer = useRef(null);

  useEffect(() => {
    const offer = blocks.find((b) => b.type === "offer");
    if (offer) setSelectedId(offer.id);
  }, []); // eslint-disable-line

  useEffect(() => {
    if (window.TMS_SAVED_DESIGN) flash("Design loaded");
  }, []); // eslint-disable-line

  // Load design from ?design_id= URL param on mount
  useEffect(() => {
    const params    = new URLSearchParams(window.location.search);
    const urlDesignId = params.get('design_id');
    const cfg       = window.TMS_CONFIG || {};
    const token     = cfg.agentToken || '';
    const workerUrl = (cfg.workerUrl || 'https://tms-promotions-api.tms-travel-marketing-systems.workers.dev').replace(/\/$/, '');
    if (!urlDesignId || !token) return;
    fetch(`${workerUrl}/email-builder/load/${encodeURIComponent(urlDesignId)}`, {
      headers: { 'Authorization': `Bearer ${token}` },
    }).then(r => r.json()).then(data => {
      if (data.blocks) {
        setBlocks(data.blocks);
        setDesignId(urlDesignId);
        flash('Design loaded');
      }
    }).catch(() => {});
  }, []); // eslint-disable-line

  // Auto-save 60 s after any block change (debounced)
  useEffect(() => {
    const cfg   = window.TMS_CONFIG || {};
    const token = cfg.agentToken || '';
    if (!token) return;
    clearTimeout(autoSaveTimer.current);
    autoSaveTimer.current = setTimeout(() => doSaveDesign(blocks, designId, designName), 60000);
    return () => clearTimeout(autoSaveTimer.current);
  }, [blocks]); // eslint-disable-line

  useEffect(() => {
    const ta = document.getElementById('design-json');
    if (ta) ta.value = JSON.stringify({ blocks, savedAt: new Date().toISOString() });
  }, [blocks]);

  useEffect(() => {
    const mq = window.matchMedia('(max-width: 767px)');
    const h = (e) => { setIsMobile(e.matches); if (!e.matches) setMobileTab(null); };
    mq.addEventListener('change', h);
    return () => mq.removeEventListener('change', h);
  }, []);

  useEffect(() => {
    if (!isMobile) return;
    const isStandalone = window.navigator.standalone === true
      || window.matchMedia('(display-mode: standalone)').matches;
    if (isStandalone) return;
    if (sessionStorage.getItem('a2hs-dismissed')) return;
    const timer = setTimeout(() => setShowA2HS(true), 2000);
    return () => clearTimeout(timer);
  }, []); // eslint-disable-line

  useEffect(() => {
    const handler = (e) => { e.preventDefault(); setDeferredPrompt(e); };
    window.addEventListener('beforeinstallprompt', handler);
    return () => window.removeEventListener('beforeinstallprompt', handler);
  }, []);

  useEffect(() => {
    const el = drawerRef.current;
    if (!el) return;
    let startY = 0;
    const onTouchStart = (e) => { startY = e.touches[0].clientY; };
    const onTouchEnd = (e) => {
      if (e.changedTouches[0].clientY - startY > 80) setMobileTab(null);
    };
    el.addEventListener('touchstart', onTouchStart);
    el.addEventListener('touchend', onTouchEnd);
    return () => {
      el.removeEventListener('touchstart', onTouchStart);
      el.removeEventListener('touchend', onTouchEnd);
    };
  }, [mobileTab]);

  const flash = (msg) => {
    setToast(msg);
    clearTimeout(toastTimer.current);
    toastTimer.current = setTimeout(() => setToast(null), 2400);
  };

  const selected = blocks.find((b) => b.id === selectedId) || null;

  const updateProp = (id, key, value) =>
    setBlocks((bs) => bs.map((b) => (b.id === id ? { ...b, props: { ...b.props, [key]: value } } : b)));

  const moveBlock = (id, dir) => setBlocks((bs) => {
    const i = bs.findIndex((b) => b.id === id);
    const j = i + dir;
    if (j < 0 || j >= bs.length) return bs;
    const next = bs.slice();
    [next[i], next[j]] = [next[j], next[i]];
    return next;
  });

  const dupBlock = (id) => setBlocks((bs) => {
    const i = bs.findIndex((b) => b.id === id);
    const copy = { ...bs[i], id: uid(), props: { ...bs[i].props } };
    const next = bs.slice(); next.splice(i + 1, 0, copy);
    setSelectedId(copy.id);
    return next;
  });

  const delBlock = (id) => setBlocks((bs) => bs.filter((b) => b.id !== id));

  const handleBlockSelect = (id) => {
    console.log('block selected:', id, 'isMobile:', isMobile);
    setSelectedId(id);
    if (isMobile && !preview) {
      console.log('opening settings drawer');
      setMobileTab('settings');
    }
  };

  const appendBlock = (type) => {
    const b = makeBlock(type);
    setBlocks((bs) => [...bs, b]);
    setSelectedId(b.id);
    flash(`${window.TYPE_META[type].label} block added`);
  };

  const insertBlock = (type, index) => {
    const b = makeBlock(type);
    setBlocks((bs) => { const n = bs.slice(); n.splice(index, 0, b); return n; });
    setSelectedId(b.id);
    setInsertAt(null);
    flash(`${window.TYPE_META[type].label} block added`);
  };

  const addOffer = (o) => {
    const headlineParts = [
      o.title,
      o.nights && `${o.nights} night${o.nights === '1' ? '' : 's'}`,
      o.board,
      o.op && `with ${o.op}`,
      o.airport && `flying from ${o.airport}`,
    ].filter(Boolean);
    const b = makeBlock("offer", {
      destination:  o.dest,
      price:        o.price,
      badge:        o.badge,
      headline:     headlineParts.join(' · ') + '.',
      availability: o.availability || 'Limited availability',
      imageUrl:     o.imageUrl || '',
      ctaUrl:       o.ctaUrl || '',
      operator:     o.op || '',
    });
    setBlocks((bs) => [...bs, b]);
    setSelectedId(b.id);
    flash(`${o.dest} offer added`);
  };

  const addCruise = async (c) => {
    console.log('imageUrl written to block:', c.imageUrl);
    const b = makeBlock("cruise", {
      cruiseName:    c.cruiseName,
      operatorLine:  c.operatorLine,
      departureDate: c.departureDate,
      duration:      c.duration,
      departurePort: c.departurePort,
      regions:       c.regions,
      price:         c.price,
      imageUrl:      c.imageUrl,
      ctaUrl:        c.ctaUrl,
      teaser:        c.teaser || '',
      promoBadge:    c.promoBadge || '',
      cruiseType:    c.cruiseType || 'ocean',
    });
    setBlocks((bs) => [...bs, b]);
    setSelectedId(b.id);
    flash(`${c.cruiseName} added`);
    if (c._id) {
      try {
        const res = await fetch(`${CRUISE_API}/cruises/${c._id}/highlights`);
        const data = await res.json();
        const teaser = (data.highlights || [])[0] || '';
        if (teaser) updateProp(b.id, 'teaser', teaser);
      } catch {}
    }
  };

  const handleExport = () => {
    const html = window.buildEmailHtml(blocks);
    setExportHtml(html);
  };

  const doSaveDesign = async (currentBlocks, currentDesignId, name) => {
    const saveCfg   = window.TMS_CONFIG || {};
    const token     = saveCfg.agentToken || '';
    const workerUrl = (saveCfg.workerUrl || 'https://tms-promotions-api.tms-travel-marketing-systems.workers.dev').replace(/\/$/, '');
    const ta = document.getElementById('design-json');
    if (ta) ta.value = JSON.stringify({ blocks: currentBlocks, savedAt: new Date().toISOString() });
    if (!token) return;
    try {
      const res  = await fetch(`${workerUrl}/email-builder/save`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
        body: JSON.stringify({ blocks: currentBlocks, name: name || 'Untitled', designId: currentDesignId }),
      });
      const data = await res.json();
      if (data.designId) {
        setDesignId(data.designId);
        setLastSavedAt(new Date());
        const u = new URL(window.location.href);
        u.searchParams.set('design_id', data.designId);
        window.history.replaceState({}, '', u.toString());
      }
    } catch {}
  };

  const saveDesign = async () => {
    const cfg   = window.TMS_CONFIG || {};
    const token = cfg.agentToken || '';
    if (!token) { flash("Saved locally (no agent token configured)"); return; }
    await doSaveDesign(blocks, designId, designName);
    flash("Design saved");
  };

  const handleSendTest = async () => {
    const toEmail = window.prompt('Send test email to:');
    if (!toEmail) return;
    const cfg       = window.TMS_CONFIG || {};
    const token     = cfg.agentToken || '';
    const workerUrl = (cfg.workerUrl || 'https://tms-promotions-api.tms-travel-marketing-systems.workers.dev').replace(/\/$/, '');
    if (!token) { setShowSettings(true); return; }
    const html = window.buildEmailHtml(blocks);
    flash('Sending test email…');
    try {
      const res  = await fetch(`${workerUrl}/email-builder/send-test`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
        body: JSON.stringify({ html, subject, toEmail }),
      });
      const data = await res.json();
      flash(data.ok ? `Test sent to ${toEmail}` : (data.error || 'Send failed'));
    } catch {
      flash('Send failed — check connection');
    }
  };

  const handleCreateCampaign = async () => {
    const cfg       = window.TMS_CONFIG || {};
    const token     = cfg.agentToken || '';
    const workerUrl = (cfg.workerUrl || 'https://tms-promotions-api.tms-travel-marketing-systems.workers.dev').replace(/\/$/, '');
    if (!token) { setShowSettings(true); return; }
    flash('Creating campaign…');
    const html = window.buildEmailHtml(blocks);
    await doSaveDesign(blocks, designId, designName);
    const currentDesignId = designId;
    try {
      const res  = await fetch(`${workerUrl}/email-builder/create-campaign`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
        body: JSON.stringify({ html, subject, designId: currentDesignId }),
      });
      const data = await res.json();
      if (data.ok) {
        flash('Campaign created in CM!');
        if (data.previewUrl) window.open(data.previewUrl, '_blank');
      } else {
        if (data.error && data.error.includes('not configured')) setShowSettings(true);
        flash(data.error || 'Campaign creation failed');
      }
    } catch {
      flash('Campaign creation failed — check connection');
    }
  };

  const dismissA2HS = () => {
    setShowA2HS(false);
    sessionStorage.setItem('a2hs-dismissed', '1');
  };

  const handleInstall = async () => {
    if (deferredPrompt) {
      deferredPrompt.prompt();
      await deferredPrompt.userChoice;
      setDeferredPrompt(null);
    }
    dismissA2HS();
  };

  const { Eye, Download, Check, Plus, Layers, Save, Search, Settings, Mail } = window.Icons;

  const canvasClasses = ["bld-canvas-area", "surf-" + t.canvasSurface].join(" ");
  const appClasses = ["bld-app", "sel-" + t.selectStyle, "dens-" + t.density, preview ? "is-preview" : ""].join(" ");

  return (
    <div className={appClasses}>
      <header className="bld-topbar">
        <div className="bld-topbar-brand">
          <span className="bld-logo"><Layers /></span>
          <b>TMS Email Builder</b>
          <span className="bld-topbar-tag">Beta</span>
        </div>
        <div className="bld-topbar-spacer" />
        {preview ? (
          <span className="bld-preview-flag"><Eye />Preview mode</span>
        ) : lastSavedAt ? (
          <span className="bld-block-count" style={{fontSize:11}}>{relTime(lastSavedAt)}</span>
        ) : (
          <span className="bld-block-count"><span className="bld-dot" /><b>{blocks.length}</b>&nbsp;<span className="bld-btn-label">blocks</span></span>
        )}
        <button className="bld-btn bld-btn--outline" onClick={saveDesign}><Save /><span className="bld-btn-label">Save</span></button>
        <button className={"bld-btn " + (preview ? "bld-btn--primary" : "bld-btn--outline")} onClick={() => { setPreview((v) => !v); setSelectedId(null); }}>
          <Eye /><span className="bld-btn-label">{preview ? "Exit preview" : "Preview"}</span>
        </button>
        <button className="bld-btn bld-btn--outline" onClick={() => setShowSettings(true)} title="Email settings">
          <Settings /><span className="bld-btn-label">Settings</span>
        </button>
        <button className="bld-btn bld-btn--outline" onClick={handleExport}><Download /><span className="bld-btn-label">Export HTML</span></button>
        <SendDropdown onSendTest={handleSendTest} onCreateCampaign={handleCreateCampaign} />
      </header>

      <div className="bld-main">
        {!preview && !isMobile && <window.Sidebar onAddBlock={appendBlock} onAddOffer={addOffer} onAddCruise={addCruise} />}

        <div className={canvasClasses} onClick={() => { setSelectedId(null); setInsertAt(null); }}>
          <div className="bld-canvas-scroll">
            {blocks.length === 0 ? (
              <div className="bld-empty" onClick={(e) => e.stopPropagation()}>
                <Layers />
                <h3>Your email is empty</h3>
                <p>Add a block from the left to get started.</p>
              </div>
            ) : (
              <div className="bld-paper">
                <div className="bld-mail">
                  {blocks.map((b, i) => (
                    <React.Fragment key={b.id}>
                      <window.BlockShell
                        block={b} index={i} total={blocks.length}
                        selected={b.id === selectedId}
                        onSelect={handleBlockSelect}
                        onMove={moveBlock} onDup={dupBlock} onDelete={delBlock}
                        onChange={updateProp}
                      />
                      {!preview && (
                        <InsertSlot index={i + 1} open={insertAt === i + 1}
                                    onToggle={(e) => { e.stopPropagation(); setInsertAt(insertAt === i + 1 ? null : i + 1); }}
                                    onPick={(type) => insertBlock(type, i + 1)} />
                      )}
                    </React.Fragment>
                  ))}
                </div>
              </div>
            )}
          </div>
        </div>

        {!preview && !isMobile && <window.SettingsPanel block={selected} onChange={updateProp} isMobile={false} />}
      </div>

      {isMobile && !preview && (
        <>
          {mobileTab && <div className="bld-drawer-backdrop" onClick={() => setMobileTab(null)} />}
          <div ref={drawerRef} className={"bld-drawer" + (mobileTab ? " is-open" : "")}>
            <div className="bld-drawer-bar">
              <div className="bld-drawer-handle" />
              {mobileTab === 'settings' && (
                <button className="bld-drawer-done" onClick={() => setMobileTab(null)}>Done</button>
              )}
            </div>
            {(mobileTab === 'blocks' || mobileTab === 'search') && (
              <window.Sidebar
                onAddBlock={(t) => { appendBlock(t); setMobileTab(null); }}
                onAddOffer={(o) => { addOffer(o); setMobileTab(null); }}
                onAddCruise={(c) => { addCruise(c); setMobileTab(null); }}
                section={mobileTab}
              />
            )}
            {mobileTab === 'settings' && (
              <window.SettingsPanel block={selected} onChange={updateProp} isMobile={isMobile} />
            )}
          </div>
          <nav className="bld-mobile-tabs">
            <button className={"bld-mobile-tab" + (mobileTab === 'blocks' ? " is-active" : "")}
                    onClick={() => setMobileTab(mobileTab === 'blocks' ? null : 'blocks')}>
              <Layers />Blocks
            </button>
            <button className={"bld-mobile-tab" + (mobileTab === 'search' ? " is-active" : "")}
                    onClick={() => setMobileTab(mobileTab === 'search' ? null : 'search')}>
              <Search />Search
            </button>
            <button className={"bld-mobile-tab" + (mobileTab === 'settings' ? " is-active" : "")}
                    onClick={() => setMobileTab(mobileTab === 'settings' ? null : 'settings')}>
              <Settings />Settings
            </button>
          </nav>
        </>
      )}

      <window.TweaksPanel>
        <window.TweakSection label="Canvas surface" />
        <window.TweakSelect label="Treatment" value={t.canvasSurface}
          options={[
            { value: "paper", label: "Warm paper" },
            { value: "slate", label: "Cool slate" },
            { value: "sand", label: "Brand sand" },
            { value: "grid", label: "Dotted grid" },
            { value: "deep", label: "Deep teal" },
          ]}
          onChange={(v) => setTweak("canvasSurface", v)} />
        <window.TweakSection label="Editing" />
        <window.TweakRadio label="Selection style" value={t.selectStyle}
          options={["ring", "bar", "glow"]} onChange={(v) => setTweak("selectStyle", v)} />
        <window.TweakRadio label="Density" value={t.density}
          options={["comfortable", "compact"]} onChange={(v) => setTweak("density", v)} />
      </window.TweaksPanel>

      {exportHtml && <ExportModal html={exportHtml} onClose={() => setExportHtml(null)} />}
      {showSettings && <SettingsModal onClose={() => setShowSettings(false)} onSubjectChange={(s) => { setSubject(s); localStorage.setItem('tms-eb-subject', s); }} subject={subject} />}
      {toast && <div className="bld-toast"><Check />{toast}</div>}
      {showA2HS && <AddToHomePrompt onDismiss={dismissA2HS} deferredPrompt={deferredPrompt} onInstall={handleInstall} />}
    </div>
  );
}

function InsertSlot({ index, open, onToggle, onPick }) {
  const { Plus } = window.Icons;
  const TYPES = ["header", "offer", "cruise", "text", "image", "video", "footer"];
  return (
    <div className={"bld-insert" + (open ? " is-open" : "")} onClick={(e) => e.stopPropagation()}>
      <button className="bld-insert-btn" title="Insert block" onClick={onToggle}><Plus /></button>
      {open && (
        <div className="bld-insert-menu">
          {TYPES.map((type) => {
            const Ic = window.Icons[window.TYPE_META[type].label];
            return (
              <button key={type} className="bld-insert-menu-item" onClick={() => onPick(type)}>
                <Ic />{window.TYPE_META[type].label}
              </button>
            );
          })}
        </div>
      )}
    </div>
  );
}

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