/* ============================================================
   create.jsx — screen 5 (배너 만들기) & 6 (생성 결과)
   ============================================================ */
const { useState: useS2, useRef: useR2 } = React;

const STYLE_A = { g: 'linear-gradient(120deg,#1f1147,#3b1d6e)', accent: '#FFD84D', primary: '#3B1D6E' };

/* ---- FilledBanner: a real composed promo banner, scales via cqh ---- */
function FilledBanner({ content, image, variant = 'a1', sty = STYLE_A }) {
  const c = content;
  const centered = variant === 'a2';
  const productSlot =
  <div style={{
    borderRadius: '50%', overflow: 'hidden',
    background: image ? 'transparent' : 'rgba(255,255,255,0.13)',
    border: '1px solid rgba(255,255,255,0.22)',
    width: '100%', height: '100%',
    backgroundImage: image ? `url(${image})` : 'none',
    backgroundSize: 'cover', backgroundPosition: 'center'
  }} />;

  return (
    <div className="fbanner" style={{ background: sty.g, color: '#fff' }}>
      {/* legibility overlay */}
      <div className="fb-pad" style={{ background: 'linear-gradient(0deg,rgba(0,0,0,.28),transparent 55%)' }} />

      {/* badge */}
      {c.discount &&
      <div style={{
        position: 'absolute', zIndex: 3,
        top: centered ? '8cqh' : '12cqh', right: '7cqh',
        transform: 'rotate(-5deg)', background: sty.accent, color: '#1a1530',
        fontWeight: 900, fontSize: '7cqh', lineHeight: 1, padding: '2.4cqh 3cqh',
        borderRadius: '2.2cqh', boxShadow: '0 1.4cqh 3cqh rgba(0,0,0,0.25)',
        fontVariantNumeric: 'tabular-nums'
      }}>{c.discount}%<span style={{ fontSize: '3.6cqh', display: 'block', fontWeight: 700, letterSpacing: '0.04em' }}>SALE</span></div>
      }

      {/* product (a1 only, right) */}
      {!centered &&
      <div style={{ position: 'absolute', zIndex: 2, right: '6cqh', top: '50%', transform: 'translateY(-50%)', width: '64cqh', height: '64cqh' }}>
          {productSlot}
        </div>
      }
      {/* product faint (a2, behind) */}
      {centered &&
      <div style={{ position: 'absolute', zIndex: 1, right: '-10cqh', bottom: '-30cqh', width: '90cqh', height: '90cqh', opacity: 0.5 }}>
          {productSlot}
        </div>
      }

      {/* text group */}
      <div style={{
        position: 'absolute', zIndex: 3, top: '50%',
        transform: 'translateY(-50%)',
        left: centered ? '50%' : '8cqh',
        ...(centered ? { transform: 'translate(-50%,-50%)', textAlign: 'center', width: 'auto', maxWidth: '84%' } : { maxWidth: '58%' }),
        display: 'flex', flexDirection: 'column', alignItems: centered ? 'center' : 'flex-start'
      }}>
        <div style={{ fontWeight: 800, fontSize: '11.5cqh', lineHeight: 1.05, letterSpacing: '-0.03em', textShadow: '0 0.4cqh 1.6cqh rgba(0,0,0,0.35)', textWrap: 'balance' }}>
          {c.head}
        </div>
        {c.sub &&
        <div style={{ fontWeight: 600, fontSize: '4.8cqh', lineHeight: 1.3, marginTop: '2.6cqh', opacity: 0.94, letterSpacing: '-0.01em' }}>
            {c.sub}
          </div>
        }
        <div style={{ display: 'flex', alignItems: 'center', gap: '2.4cqh', marginTop: '4.5cqh', flexWrap: 'wrap', justifyContent: centered ? 'center' : 'flex-start' }}>
          {c.cta &&
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: '1.4cqh', background: sty.accent, color: '#1a1530', fontWeight: 800, fontSize: '4cqh', padding: '2.6cqh 5cqh', borderRadius: '99px' }}>
              {c.cta} <span style={{ fontSize: '4.4cqh' }}>→</span>
            </div>
          }
          {c.period &&
          <span style={{ fontSize: '3.2cqh', fontWeight: 600, opacity: 0.8 }}>{c.period}</span>
          }
        </div>
      </div>
    </div>);

}

/* 만들기 화면 공통 헤더 — ‹ 뒤로 + 카테고리 제목 + (옆) 유형 드롭다운 */
function CreateHead({ category, onBack, sub, children }) {
  return (
    <div className="page-head create-head">
      <h1 className="page-title" style={{ display: 'flex', alignItems: 'center', gap: 8, margin: 0 }}>
        <button type="button" className="title-back-btn" title="돌아가기" onClick={onBack}>
          <S2Icon name="chevronRight" size={20} style={{ transform: 'rotate(180deg)' }} />
        </button>
        {category}
      </h1>
      {children && <div className="create-head-type">{children}</div>}
    </div>);
}

/* ============ Screen 5: Create banner ============ */
function CreateBanner({ guide, onBack, onGenerate }) {
  const g = guide || GUIDE_A;
  const [content, setContent] = useS2({
    head: '여름맞이 시즌오프', sub: '인기 상품 최대 50% 특가', cta: '지금 구매하기',
    discount: '50', period: '6.1 ~ 6.30'
  });
  const [image, setImage] = useS2(null);
  const [variant, setVariant] = useS2('a1');
  const fileRef = useR2(null);
  const _types = window.BANNER_TYPES || [];
  const _catId = (() => {const f = (g.name || '').trim()[0];return _types.some((t) => t.id === f) ? f : 'A';})();
  const activeCat = _types.find((t) => t.id === _catId) || _types[0];
  const [sub, setSub] = useS2(activeCat ? activeCat.subs[0].id : 'A1');
  const activeSub = activeCat && (activeCat.subs.find((s) => s.id === sub) || activeCat.subs[0]);
  // 세부 유형별 샘플 이미지 — 업로드한 카테고리 자산만 사용 (단일 출처)
  const _SAMPLES = { '상품배너 550': window.G550_IMG, '상품배너 H1': window.H1_IMG, '앱푸시': window.PUSH_IMG };
  const _sampleArr = _SAMPLES[g.category] || window.G550_IMG || [];
  const _subIdx = activeCat ? activeCat.subs.findIndex((s) => s.id === sub) : 0;
  const _sampleSrc = _sampleArr.length ? _sampleArr[(_subIdx < 0 ? 0 : _subIdx) % _sampleArr.length] : null;
  const _sampleAR = g.spec ? `${g.spec.w} / ${g.spec.h}` : '1 / 1';
  const set = (k) => (e) => setContent((c) => ({ ...c, [k]: e.target.value }));

  const onFile = (e) => {
    const f = e.target.files && e.target.files[0];
    if (!f) return;
    const r = new FileReader();
    r.onload = () => setImage(r.result);
    r.readAsDataURL(f);
  };

  return (
    <div className="content"><div className="content-pad">
      {(g.category === '상품배너 550' || g.category === '상품배너 H1') && window.Schema550Create ?
        <Schema550Create guide={g} onBack={onBack} onGenerate={onGenerate} /> :
       g.category === '앱푸시' && window.PushCreate ?
        <PushCreate guide={g} onBack={onBack} onGenerate={onGenerate} /> :
      <React.Fragment>
      <div className="page-head" style={{ marginBottom: 18 }}>
        <h1 className="page-title" style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <button type="button" className="title-back-btn" title="돌아가기" onClick={onBack}>
            <S2Icon name="chevronRight" size={20} style={{ transform: 'rotate(180deg)' }} />
          </button>
          {g.category}
        </h1>
        <p className="page-sub">이미지와 로고만 업로드하면, 가이드 규칙에 맞춰 배너를 자동 제작합니다.</p>
      </div>
      {/* 배너 유형 (가이드가 카테고리를 결정 → 세부 유형만 선택) — 예시 썸네일 카드 */}
      <div className="card" style={{ padding: 20, borderStyle: 'none', marginBottom: 16 }}>
        <div className="section-title">배너 세부 유형 <span style={{ color: 'var(--text-faint)', fontWeight: 500 }}>· {g.category}</span></div>
        <div className="type-cards">
          {activeCat && activeCat.subs.map((s, i) => {
            const src = _sampleArr.length ? _sampleArr[i % _sampleArr.length] : null;
            return (
              <button key={s.id} className={`type-card-v ${sub === s.id ? 'on' : ''}`} onClick={() => setSub(s.id)}>
                <div className="tcv-thumb" style={{ aspectRatio: _sampleAR }}>
                  {src ? <img src={src} alt={s.label} /> : <div className="tcv-ph" />}
                  {sub === s.id && <span className="tcv-check"><S2Icon name="check" size={13} strokeWidth={3} /></span>}
                </div>
                <div className="tcv-meta">
                  <span className="tcv-id">{s.id}</span>
                  <span className="tcv-label">{s.label}</span>
                </div>
              </button>);
          })}
        </div>
      </div>

      {_catId === 'A' && window.NukkiCreate &&
        <NukkiCreate guide={g} sub={activeSub}
        onGenerate={(data) => onGenerate({ content, image: data.images && data.images[0], sty: STYLE_A, nukki: data })} />}

      {_catId !== 'A' &&
        <div className="create-grid">
        {/* form */}
        <div className="card" style={{ padding: 22, borderStyle: "none" }}>
          <div className="section-title">기획서 입력</div>
          <div className="field">
            <label className="field-label">메인 문구</label>
            <input className="input" value={content.head} onChange={set('head')} placeholder="예: 여름맞이 시즌오프" />
          </div>
          <div className="field">
            <label className="field-label">서브 문구</label>
            <input className="input" value={content.sub} onChange={set('sub')} placeholder="예: 인기 상품 최대 50% 특가" />
          </div>
          <div className="field">
            <label className="field-label">CTA 텍스트</label>
            <input className="input" value={content.cta} onChange={set('cta')} placeholder="예: 지금 구매하기" />
          </div>
          <div className="row-2">
            <div className="field">
              <label className="field-label">할인율</label>
              <div className="input-group">
                <input className="input" style={{ borderRadius: '8px 0 0 8px' }} value={content.discount} onChange={set('discount')} placeholder="50" inputMode="numeric" />
                <span className="input-prefix" style={{ borderRight: '1px solid var(--border-input)', borderLeft: 'none', borderRadius: '0 8px 8px 0' }}>%</span>
              </div>
            </div>
            <div className="field">
              <label className="field-label">기간</label>
              <input className="input" value={content.period} onChange={set('period')} placeholder="6.1 ~ 6.30" />
            </div>
          </div>

          <div className="field" style={{ marginBottom: 6 }}>
            <label className="field-label">상품 이미지</label>
            <input ref={fileRef} type="file" accept="image/*" style={{ display: 'none' }} onChange={onFile} />
            <div className={`dropzone ${image ? 'has' : ''}`} onClick={() => fileRef.current && fileRef.current.click()}>
              {image ?
                <div className="dz-thumb">
                  <img src={image} alt="업로드" />
                  <button className="dz-remove" onClick={(e) => {e.stopPropagation();setImage(null);}}><S2Icon name="x" size={15} /></button>
                </div> :

                <>
                  <div className="dz-icon"><S2Icon name="upload" size={20} /></div>
                  <div style={{ fontSize: 13.5, fontWeight: 600 }}>이미지를 끌어다 놓거나 클릭해 업로드</div>
                  <div style={{ fontSize: 12, color: 'var(--text-subtle)', marginTop: 4 }}>PNG · JPG · 누끼 이미지 권장</div>
                </>
                }
            </div>
          </div>

          <button className="btn btn-primary btn-lg btn-block" style={{ marginTop: 18, borderRadius: "6px" }}
            disabled={!content.head.trim()}
            onClick={() => onGenerate({ content, image, sty: STYLE_A })}>
            <S2Icon name="sparkles" size={17} /> 배너 생성하기
          </button>
        </div>

        {/* live preview */}
        <div className="preview-col">
          <div className="card" style={{ padding: 16, borderStyle: "none" }}>
            <div className="variant-head">
              <div className="section-title" style={{ margin: 0 }}>실시간 미리보기</div>
              <div className="seg" style={{ width: 'auto' }}>
                <button className={variant === 'a1' ? 'on' : ''} onClick={() => setVariant('a1')} style={{ padding: '0 12px' }}>A1</button>
                <button className={variant === 'a2' ? 'on' : ''} onClick={() => setVariant('a2')} style={{ padding: '0 12px' }}>A2</button>
              </div>
            </div>
            <div style={{ aspectRatio: '1920 / 600' }}>
              <FilledBanner content={content} image={image} variant={variant} />
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 12, fontSize: 12, color: 'var(--text-muted)' }}>
              <S2Icon name="layers" size={13} /> {g.name} 슬롯 템플릿 · 1920 × 600
            </div>
          </div>
          <p style={{ fontSize: 12, color: 'var(--text-subtle)', textAlign: 'center', marginTop: 12, lineHeight: 1.5 }}>
            입력값이 실시간으로 반영됩니다. 생성 시 변형안과 사이즈별 출력이 함께 만들어져요.
          </p>
        </div>
      </div>}
      </React.Fragment>}
    </div></div>);

}

/* ============ Screen 6: Result ============ */
/* ---- P-08: 사용자 옵션(로고/부가정보/컬러칩)을 오버레이 rect로 변환 (SAFE 기준 좌표) ---- */
function apOverlays(sel, S) {
  if (!sel || !S) return [];
  const ov = [];
  const logos = (sel.logoImgs || []).filter(Boolean).slice(0, sel.logoCount || 0);
  const lw = Math.round(S.w * 0.26), lh = Math.round(S.w * 0.10), gap = 8;
  logos.forEach((url, i) => ov.push({ type: 'img', url, x: S.x + S.w - lw - (lw + gap) * i, y: S.y, w: lw, h: lh }));
  if (sel.extra === 'addtext' && sel.extraText) ov.push({ type: 'text', text: sel.extraText, x: S.x, y: S.y + S.h - Math.round(S.h * 0.17), size: Math.round(S.h * 0.09), color: '#1A1530', bg: '#FFD84D' });
  if (sel.extra === 'addimg' && sel.extraImg) { const s = Math.round(S.w * 0.22); ov.push({ type: 'img', url: sel.extraImg, x: S.x, y: S.y + S.h - s, w: s, h: s }); }
  if (sel.extra === 'colorchip' && sel.hex && sel.hex.replace('#', '').length >= 3) { const s = 30; ov.push({ type: 'chip', color: (sel.hex[0] === '#' ? '' : '#') + sel.hex, x: S.x + S.w - s - 4, y: S.y + S.h - s - 4, w: s, h: s }); }
  return ov;
}

/* ---- P-01/P-08: AP550 실제 자동배치 후보 카드 (엔진 rects + 옵션 오버레이) ---- */
function AutoCandidateCard({ cand, canvas, index, selected, onSelect, overlays }) {
  const cw = canvas.w, ch = canvas.h;
  const exp = cand.metrics && cand.metrics.exposure != null ? Math.round(cand.metrics.exposure) : null;
  const pos = (o) => ({ position: 'absolute', left: `${o.x / cw * 100}%`, top: `${o.y / ch * 100}%`, width: `${o.w / cw * 100}%`, height: `${o.h / ch * 100}%` });
  return (
    <div className={`variant-card ${selected ? 'primary' : ''} fade-up`} onClick={onSelect} style={{ cursor: 'pointer' }}>
      <div className="variant-head">
        <div className="lab"><span className={`num ${selected ? '' : 'alt'}`}>{index + 1}</span> {cand.strategyLabel || cand.strategy}{cand.rowsLabel ? ' · ' + cand.rowsLabel : ''}</div>
        {exp != null && <div style={{ fontSize: 11, color: 'var(--text-subtle)' }}>노출 {exp}%</div>}
      </div>
      <div style={{ position: 'relative', width: '100%', aspectRatio: `${cw} / ${ch}`, background: '#fff', overflow: 'hidden', boxShadow: 'inset 0 0 0 1px rgba(0,0,0,.06)', containerType: 'size' }}>
        {cand.rects.map((r, i) =>
          <img key={r.id != null ? r.id : i} src={r.url} alt=""
            style={{ position: 'absolute', left: `${r.x / cw * 100}%`, top: `${r.y / ch * 100}%`, width: `${r.w / cw * 100}%`, height: `${r.h / ch * 100}%`, zIndex: r.z || 1, objectFit: 'contain' }} />)}
        {(overlays || []).map((o, i) =>
          o.type === 'img' ? <img key={'ov' + i} src={o.url} alt="" style={{ ...pos(o), zIndex: 900, objectFit: 'contain' }} /> :
          o.type === 'chip' ? <div key={'ov' + i} style={{ ...pos(o), zIndex: 900, background: o.color, borderRadius: '50%', border: '2px solid #fff', boxShadow: '0 1px 3px rgba(0,0,0,.3)' }} /> :
          <div key={'ov' + i} style={{ position: 'absolute', left: `${o.x / cw * 100}%`, top: `${o.y / ch * 100}%`, zIndex: 900, background: o.bg, color: o.color, fontWeight: 800, padding: '0.08em 0.32em', borderRadius: '0.16em', fontSize: `${o.size / ch * 100}cqh`, lineHeight: 1.12, whiteSpace: 'nowrap' }}>{o.text}</div>)}
      </div>
    </div>);
}

function BannerResult({ guide, data, onBack, onHome, ga4Source }) {
  const ga4Src = ga4Source === 'edit' ? 'edit' : 'asst';
  const g = guide || GUIDE_A;
  const d = data || { content: { head: '여름맞이 시즌오프', sub: '인기 상품 최대 50% 특가', cta: '지금 구매하기', discount: '50', period: '6.1 ~ 6.30' }, image: null, sty: STYLE_A };

  // ── P-01: 상품배너550/H1 + 이미지가 있으면 실제 AP550 자동배치 엔진 사용 (앱푸시/이미지없음은 기존 경로) ──
  const AP = window.AP550;
  const imgs = (d.images && d.images.length) ? d.images : (d.image ? [d.image] : []);
  // 엔진 대상 카테고리: 상품배너550(550×550) · 상품배너 H1(776×388) — 같은 누끼 엔진, 캔버스만 다름(configure).
  const engineCat = g.category === '상품배너 550' ? window.SCHEMA_550 :
                    g.category === '상품배너 H1'  ? window.SCHEMA_H1 : null;
  // 엔진은 "A 누끼형"(cutout) 전용 — split/full 등 다른 레이아웃은 사용자 선택을 존중해 기존 경로로.
  const useEngine = !!(AP && imgs.length && engineCat && d.schema550 && d.schema550.layout === 'nukki');

  const [generating, setGenerating] = useS2(true);
  const [cands, setCands] = useS2(null);
  const [sel, setSel] = useS2(0);
  const [engineErr, setEngineErr] = useS2(null);
  const [dling, setDling] = useS2(false);
  const [saving, setSaving] = useS2(false);   // 완료 저장 중
  const [savedOk, setSavedOk] = useS2(false);
  const [drafting, setDrafting] = useS2(false); // 임시저장 중
  const [draftId, setDraftId] = useS2(null);    // 이 프로젝트의 generation id (작업중→완료 승격에 사용)
  const [savedDone, setSavedDone] = useS2(false); // 완료 저장됨(뱃지)
  const autoDraftRef = React.useRef(false);       // 자동 임시저장 1회 가드
  const sourcesSavedRef = React.useRef(false);    // 원본/누끼 업로드 1회 가드
  const [previewUrl, setPreviewUrl] = useS2(null);

  // 선택 후보를 550/H1 캔버스에 래스터화 → Blob (다운로드/내 배너 저장 공용)
  const renderCandBlob = async (cand, mime) => {
    const cvW = (AP && AP.CANVAS && AP.CANVAS.w) || 550, cvH = (AP && AP.CANVAS && AP.CANVAS.h) || 550;
    const cv = document.createElement('canvas'); cv.width = cvW; cv.height = cvH;
    const ctx = cv.getContext('2d');
    ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, cvW, cvH);
    const rects = (cand.rects || []).slice().sort((a, b) => (a.z || 0) - (b.z || 0)); // z 오름차순(뒤→앞)
    for (const r of rects) {
      await new Promise((res) => { const im = new Image(); im.onload = () => { try { ctx.drawImage(im, r.x, r.y, r.w, r.h); } catch (e) {} res(); }; im.onerror = res; im.src = r.url; });
    }
    // 옵션 오버레이(로고/부가정보/컬러칩)를 같은 좌표계로 합성
    const ovs = apOverlays(d.schema550, (AP && AP.SAFE_RECT) || { x: 50, y: 40, w: 450, h: 470 });
    for (const o of ovs) {
      if (o.type === 'img') {
        await new Promise((res) => { const im = new Image(); im.onload = () => { try { ctx.drawImage(im, o.x, o.y, o.w, o.h); } catch (e) {} res(); }; im.onerror = res; im.src = o.url; });
      } else if (o.type === 'chip') {
        ctx.fillStyle = o.color; ctx.beginPath(); ctx.arc(o.x + o.w / 2, o.y + o.h / 2, o.w / 2, 0, Math.PI * 2); ctx.fill();
        ctx.lineWidth = 2; ctx.strokeStyle = '#fff'; ctx.stroke();
      } else {
        ctx.font = `800 ${o.size}px Pretendard, system-ui, sans-serif`;
        const tw = ctx.measureText(o.text).width, padX = o.size * 0.32, padY = o.size * 0.14;
        ctx.fillStyle = o.bg; ctx.fillRect(o.x, o.y, tw + padX * 2, o.size + padY * 2);
        ctx.fillStyle = o.color; ctx.textBaseline = 'top'; ctx.fillText(o.text, o.x + padX, o.y + padY);
      }
    }
    return await new Promise((res) => cv.toBlob(res, mime || 'image/png'));
  };

  const downloadCand = async (cand) => {
    if (!cand || dling) return;
    setDling(true);
    try {
      const blob = await renderCandBlob(cand, 'image/png');
      if (!blob) return;
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url; a.download = `bannerly-${(g.name || '550').replace(/\s+/g, '')}-${cand.strategy || 'cand'}.png`;
      document.body.appendChild(a); a.click(); a.remove();
      setTimeout(() => URL.revokeObjectURL(url), 1000);
      if (window.__ga4 && window.__ga4.trackDownload) {
        const cat = g.category === '앱푸시' ? 'push' : g.category === '상품배너 H1' ? 'h1' : '550';
        window.__ga4.trackDownload(cat, (cand && cand.strategy) || 'a', (cand && (cand.strategyLabel || cand.strategy)) || '', ga4Src);
      }
    } finally { setDling(false); }
  };

  // dataURL/objectURL/외부 URL → Blob (공용 urlToBlob 우선)
  const srcToBlob = async (src) => {
    if (window.BannerEditorPersist && window.BannerEditorPersist.urlToBlob) return window.BannerEditorPersist.urlToBlob(src);
    try { const r = await fetch(src); return await r.blob(); } catch (e) { return null; }
  };
  // 원본 + 누끼 이미지 blob 수집 (최초 1회만 업로드하기 위한 소스)
  const collectSources = async (cand) => {
    if (sourcesSavedRef.current) return []; // 이미 저장했으면 다시 안 올림
    const out = [];
    for (const s of imgs) { const b = await srcToBlob(s); if (b) out.push({ blob: b, subtype: 'upload' }); }
    const seen = {};
    for (const r of (cand && cand.rects) || []) {
      if (!r.url || seen[r.url]) continue; seen[r.url] = 1;
      const b = await srcToBlob(r.url); if (b) out.push({ blob: b, subtype: 'nukki' });
    }
    return out;
  };
  const projectMeta = (cand) => {
    const canvas = (AP && AP.CANVAS) || { w: 550, h: 550 };
    return {
      event: (d.schema550 && d.schema550.event) || g.name || '',
      category: g.category || '', type: cand ? (cand.strategyLabel || cand.strategy || '') : '',
      strategy: (cand && cand.strategy) || '', width: canvas.w, height: canvas.h,
      worker: window.__bannerlyUser || '',
    };
  };

  // 임시저장(작업중). 자동/버튼 공용. 원본·누끼는 최초 1회만 업로드.
  const saveDraft = async (cand, opts) => {
    if (!cand || drafting || !window.__myBanners) return;
    setDrafting(true);
    try {
      const preview = await renderCandBlob(cand, 'image/jpeg');
      const sources = await collectSources(cand);
      const r = await window.__myBanners.saveProject(Object.assign(projectMeta(cand), {
        status: 'draft', id: draftId, previewBlob: preview, sources,
      }));
      if (r && r.ok) {
        setDraftId(r.id);
        if (window.BannerEditorPersist && window.BannerEditorPersist.sourcesPersisted(r, sources.length)) sourcesSavedRef.current = true;
      }
      else if (opts && opts.explicit) { alert('임시저장 실패: ' + ((r && r.error) || '알 수 없는 오류')); }
    } finally { setDrafting(false); }
  };

  // 내 배너에 저장 = 완료(saved). 기존 작업중 항목이 있으면 그걸 완료로 승격.
  const saveCand = async (cand) => {
    if (!cand || saving || !window.__myBanners) return;
    setSaving(true);
    try {
      const blob = await renderCandBlob(cand, 'image/jpeg');
      const sources = await collectSources(cand);
      const r = await window.__myBanners.saveProject(Object.assign(projectMeta(cand), {
        status: 'saved', id: draftId, finalBlob: blob, sources,
      }));
      if (r && r.ok) {
        setDraftId(r.id);
        if (window.BannerEditorPersist && window.BannerEditorPersist.sourcesPersisted(r, sources.length)) sourcesSavedRef.current = true;
        setSavedOk(true); setSavedDone(true); setTimeout(() => setSavedOk(false), 2500);
        if (window.__ga4 && window.__ga4.trackDownload) {
          const cat = g.category === '앱푸시' ? 'push' : g.category === '상품배너 H1' ? 'h1' : '550';
          window.__ga4.trackDownload(cat, (cand && cand.strategy) || 'a', (cand && (cand.strategyLabel || cand.strategy)) || '', ga4Src);
        }
      } else { alert('내 배너 저장 실패: ' + ((r && r.error) || '알 수 없는 오류')); }
    } finally { setSaving(false); }
  };

  // 범용 폴백 결과도 화면에 노출된 다운로드·미리보기·저장 CTA가 실제로 동작하도록
  // 최소한의 캔버스 렌더러를 사용한다. 카테고리 전용 편집기는 위의 실제 엔진 경로를 쓴다.
  const renderFallbackBlob = async (variant, width, height) => {
    const w = Math.max(1, Number(width) || 1920), h = Math.max(1, Number(height) || 600);
    const cv = document.createElement('canvas'); cv.width = w; cv.height = h;
    const ctx = cv.getContext('2d');
    const colors = String((d.sty && d.sty.g) || STYLE_A.g).match(/#[0-9a-f]{3,8}/gi) || ['#1f1147', '#3b1d6e'];
    const gradient = ctx.createLinearGradient(0, 0, w, h);
    gradient.addColorStop(0, colors[0]); gradient.addColorStop(1, colors[1] || colors[0]);
    ctx.fillStyle = gradient; ctx.fillRect(0, 0, w, h);
    ctx.fillStyle = 'rgba(0,0,0,.22)'; ctx.fillRect(0, h * 0.45, w, h * 0.55);
    if (d.image) {
      await new Promise((resolve) => {
        const im = new Image(); im.crossOrigin = 'anonymous';
        im.onload = () => { try {
          const size = h * (variant === 'a2' ? 1.05 : 0.76), x = variant === 'a2' ? w - size * 0.62 : w - size - w * 0.06, y = (h - size) / 2;
          ctx.save(); ctx.beginPath(); ctx.arc(x + size / 2, y + size / 2, size / 2, 0, Math.PI * 2); ctx.clip();
          const scale = Math.max(size / im.naturalWidth, size / im.naturalHeight);
          const dw = im.naturalWidth * scale, dh = im.naturalHeight * scale;
          ctx.drawImage(im, x + (size - dw) / 2, y + (size - dh) / 2, dw, dh); ctx.restore();
        } catch (e) {} resolve(); };
        im.onerror = resolve; im.src = d.image;
      });
    }
    const c = d.content || {};
    const centered = variant === 'a2';
    ctx.fillStyle = '#fff'; ctx.textBaseline = 'top'; ctx.textAlign = centered ? 'center' : 'left';
    const tx = centered ? w / 2 : w * 0.08, max = w * (centered ? 0.84 : 0.55);
    ctx.font = `800 ${Math.max(18, Math.round(h * 0.115))}px Pretendard, sans-serif`;
    const head = String(c.head || ''); ctx.fillText(head.slice(0, 32), tx, h * 0.29, max);
    ctx.font = `600 ${Math.max(12, Math.round(h * 0.048))}px Pretendard, sans-serif`;
    if (c.sub) ctx.fillText(String(c.sub).slice(0, 48), tx, h * 0.49, max);
    if (c.cta) { const label = String(c.cta).slice(0, 24), ctaW = Math.max(120, ctx.measureText(label).width + h * 0.12); ctx.fillStyle = (d.sty && d.sty.accent) || '#FFD84D'; ctx.fillRect(centered ? tx - ctaW / 2 : tx, h * 0.68, ctaW, h * 0.12); ctx.fillStyle = '#1a1530'; ctx.font = `800 ${Math.max(11, Math.round(h * 0.04))}px Pretendard, sans-serif`; ctx.fillText(label, centered ? tx : tx + h * 0.06, h * 0.72); }
    return new Promise((resolve) => cv.toBlob(resolve, 'image/png'));
  };
  const downloadBlob = (blob, name) => {
    if (!blob) return;
    const url = URL.createObjectURL(blob), a = document.createElement('a');
    a.href = url; a.download = name; document.body.appendChild(a); a.click(); a.remove();
    setTimeout(() => URL.revokeObjectURL(url), 1000);
  };
  const previewFallback = async (variant) => {
    const blob = await renderFallbackBlob(variant, (g.sizes && g.sizes[0] && g.sizes[0].w) || 1920, (g.sizes && g.sizes[0] && g.sizes[0].h) || 600);
    if (!blob) return;
    setPreviewUrl((old) => { if (old) URL.revokeObjectURL(old); return URL.createObjectURL(blob); });
  };
  const closeFallbackPreview = () => setPreviewUrl((old) => { if (old) URL.revokeObjectURL(old); return null; });
  const downloadFallback = async (variant, size, name) => {
    if (dling) return; setDling(true);
    try { downloadBlob(await renderFallbackBlob(variant, size && size.w, size && size.h), name || `bannerly-${g.name || 'banner'}.png`); }
    finally { setDling(false); }
  };
  const saveFallback = async () => {
    if (saving || !window.__myBanners) return;
    setSaving(true);
    try {
      const size = (g.sizes && g.sizes[0]) || { w: 1920, h: 600 };
      const blob = await renderFallbackBlob('a1', size.w, size.h);
      const r = await window.__myBanners.saveProject({ event: g.name || '배너', category: g.category || '', type: '범용 결과', strategy: 'a1', width: size.w, height: size.h, status: 'saved', finalBlob: blob });
      if (r && r.ok) { setSavedOk(true); setSavedDone(true); setTimeout(() => setSavedOk(false), 2500); }
      else alert('내 배너 저장 실패: ' + ((r && r.error) || '알 수 없는 오류'));
    } finally { setSaving(false); }
  };
  const downloadAllFallback = async () => {
    if (dling) return; setDling(true);
    try {
      const variants = [{ id: 'a1', label: '추천안' }, { id: 'a2', label: '변형안' }];
      const sizes = g.sizes && g.sizes.length ? g.sizes : [{ w: 1920, h: 600, name: '기본' }];
      for (const variant of variants) for (const size of sizes) {
        const blob = await renderFallbackBlob(variant.id, size.w, size.h);
        downloadBlob(blob, `bannerly-${g.name || 'banner'}-${variant.id}-${size.name || size.w + 'x' + size.h}.png`);
        await new Promise((resolve) => setTimeout(resolve, 80));
      }
    } finally { setDling(false); }
  };

  // 결과가 준비되면 자동으로 작업중(draft) 저장 1회 (로그인 세션 있을 때만 동작)
  React.useEffect(() => {
    if (autoDraftRef.current) return;
    if (generating || !cands || !cands.length || !window.__myBanners) return;
    autoDraftRef.current = true;
    saveDraft(cands[sel]);
  }, [generating, cands]);

  React.useEffect(() => {
    if (!useEngine) { const t = setTimeout(() => setGenerating(false), 1500); return () => clearTimeout(t); }
    let cancelled = false;
    (async () => {
      try {
        // 카테고리 규격으로 엔진 캔버스 설정 (550=550×550, H1=776×388). 생성 전 필수.
        if (AP.configure && engineCat && engineCat.canvas) AP.configure({ w: engineCat.canvas.w, h: engineCat.canvas.h, safe: engineCat.canvas.safe });
        const items = [];
        for (const src of imgs) {
          let it = await AP.prepareItem(src, 'remove');
          // flood-fill 누끼가 실패(거의 전부 투명/전부 배경)하면 원본을 유지해 최소한 배치가 보이도록 폴백.
          // (진짜 배경제거 품질은 향후 세그멘테이션 API로 대체 — engine seam)
          if (!it || !it.meta || it.meta.removedRatio > 0.9) it = await AP.prepareItem(src, 'keep');
          items.push(it);
        }
        // 로고가 있으면 상단 영역을 예약해 제품이 로고와 겹치지 않게 (엔진 지원 scorer.logoReserveTop)
        const selOpt = d.schema550 || {};
        const hasLogo = (selOpt.logoImgs || []).filter(Boolean).slice(0, selOpt.logoCount || 0).length > 0;
        const scorer = Object.assign({}, AP.DEFAULT_SCORER, hasLogo ? { logoReserveTop: 60 } : {});
        let list = AP.generateCandidates(items, null, scorer) || [];
        if (AP.rankCandidates) list = AP.rankCandidates(list, scorer); // 엔진 자체 랭킹(≤14). 추가 dedup/cap 금지 → 다양성 보존
        if (!cancelled) { setCands(list); setGenerating(false); }
      } catch (e) { if (!cancelled) { setEngineErr(String((e && e.message) || e)); setGenerating(false); } }
    })();
    return () => { cancelled = true; };
  }, []);

  // ── 실제 엔진 결과 화면 ──
  if (useEngine) {
    const canvas = AP.CANVAS || { w: 550, h: 550 };
    const n = cands ? cands.length : 0;
    if (generating) {
      return (
        <div className="content"><div className="content-pad">
          <div className="empty-wrap"><div className="empty">
            <div className="spinner" style={{ width: 30, height: 30, marginBottom: 20 }} />
            <h2 className="empty-title">자동배치 후보를 계산하고 있어요</h2>
            <p className="empty-text">업로드 이미지의 배경을 제거하고 서로 다른 배열을 생성하는 중…</p>
          </div></div>
        </div></div>);
    }
    return (
      <div className="content"><div className="content-pad">
        <button className="btn btn-ghost btn-sm" style={{ marginBottom: 14, marginLeft: -8 }} onClick={onBack}>
          <S2Icon name="arrowLeft" size={15} /> 다시 편집
        </button>
        <div className="page-head" style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 24 }}>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <h1 className="page-title">자동배치 결과</h1>
              <span className="pill green"><span className="pill-dot" /> 후보 {n}개</span>
            </div>
            <p className="page-sub">{g.name} 규칙으로 실제 배치 엔진이 생성한 서로 다른 배열입니다. 원하는 안을 고르세요.</p>
          </div>
          <button className="btn btn-secondary" onClick={onBack}><S2Icon name="sliders" size={15} /> 미세조정</button>
        </div>

        {engineErr && <div className="constraint-msg">자동배치 중 오류가 발생했습니다: {engineErr}</div>}
        {!engineErr && n === 0 && <div className="constraint-msg">생성된 후보가 없습니다. 이미지를 확인해 주세요.</div>}

        {n > 0 &&
          <React.Fragment>
            <div className="section-title" style={{ justifyContent: 'space-between' }}>
              <span>자동배치 후보</span>
              <span style={{ color: 'var(--text-subtle)', fontWeight: 500 }}>서로 다른 배열 {n}개</span>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(240px,1fr))', gap: 18, marginBottom: 32 }}>
              {cands.map((c, i) => <AutoCandidateCard key={c.id != null ? c.id : i} cand={c} canvas={canvas} index={i} selected={sel === i} onSelect={() => setSel(i)} overlays={apOverlays(d.schema550, (AP && AP.SAFE_RECT) || { x: 50, y: 40, w: 450, h: 470 })} />)}
            </div>
            <div className="export-bar">
              <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>
                선택: <b style={{ color: 'var(--text-2)' }}>{cands[sel] ? (cands[sel].strategyLabel || cands[sel].strategy) : '-'}</b>
              </div>
              <div style={{ marginLeft: 'auto', display: 'flex', gap: 10 }}>
                <button className="btn btn-ghost" disabled={drafting || !cands || !cands[sel]} onClick={() => saveDraft(cands[sel], { explicit: true })} title="작업중 상태로 임시 저장">{drafting ? '임시저장 중…' : '임시저장'}</button>
                <button className="btn btn-secondary" disabled={saving || !cands || !cands[sel]} onClick={() => saveCand(cands[sel])}><S2Icon name="copy" size={15} /> {savedOk ? '내 배너에 저장됨 ✓' : saving ? '저장 중…' : (savedDone ? '완료로 저장됨 · 다시 저장' : '내 배너에 저장')}</button>
                <button className="btn btn-primary" disabled={dling || !cands || !cands[sel]} onClick={() => downloadCand(cands[sel])}><S2Icon name="download" size={16} /> {dling ? '내보내는 중…' : 'PNG 다운로드'}</button>
              </div>
            </div>
          </React.Fragment>}
      </div></div>);
  }

  // ── 앱푸시: 실제 720×380 템플릿 마감 변형 후보 N개 (금지된 1920×600 더미 대신) ──
  if (g.category === '앱푸시' && window.PushPreview && window.PUSH_VARIANTS) {
    if (generating) {
      return (
        <div className="content"><div className="content-pad">
          <div className="empty-wrap"><div className="empty">
            <div className="spinner" style={{ width: 30, height: 30, marginBottom: 20 }} />
            <h2 className="empty-title">앱푸시 변형안을 만들고 있어요</h2>
            <p className="empty-text">720×380 템플릿에 콘텐츠를 배치하고 마감 변형을 생성하는 중…</p>
          </div></div>
        </div></div>);
    }
    return <PushResult d={d} onBack={onBack} ga4Source={ga4Source} />;
  }

  // ── 기존 경로(H1/이미지 없음) — 미변경 ──
  if (generating) {
    return (
      <div className="content"><div className="content-pad">
        <div className="empty-wrap"><div className="empty">
          <div className="spinner" style={{ width: 30, height: 30, marginBottom: 20 }} />
          <h2 className="empty-title">배너를 생성하고 있어요</h2>
          <p className="empty-text">가이드 규칙에 맞춰 변형안과 사이즈별 출력을 만드는 중…</p>
        </div></div>
      </div></div>);

  }

  return (
    <div className="content"><div className="content-pad">
      <button className="btn btn-ghost btn-sm" style={{ marginBottom: 14, marginLeft: -8 }} onClick={onBack}>
        <S2Icon name="arrowLeft" size={15} /> 다시 편집
      </button>
      <div className="page-head" style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 24 }}>
        <div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <h1 className="page-title">생성 완료</h1>
            <span className="pill green"><span className="pill-dot" /> 2개 변형안 · 5개 규격</span>
          </div>
          <p className="page-sub">{g.name} 규칙으로 제작된 배너입니다. 마음에 드는 안을 내보내세요.</p>
        </div>
        <button className="btn btn-secondary" onClick={onBack}><S2Icon name="sliders" size={15} /> 미세조정</button>
      </div>

      {/* variants */}
      <div className="section-title">변형안</div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 18, marginBottom: 32 }}>
        {[
          { id: 'a1', label: '추천안', variant: 'a1', alt: false },
          { id: 'a2', label: '변형안', variant: 'a2', alt: true }].
          map((v) =>
          <div key={v.id} className={`variant-card ${v.alt ? '' : 'primary'} fade-up`}>
            <div className="variant-head">
              <div className="lab"><span className={`num ${v.alt ? 'alt' : ''}`}>{v.id.toUpperCase()[1]}</span> A{v.id[1]} · {v.label}</div>
              <div style={{ display: 'flex', gap: 6 }}>
                <button className="icon-btn" title="미리보기" onClick={() => previewFallback(v.variant)}><S2Icon name="eye" size={16} /></button>
                <button className="icon-btn" title="다운로드" disabled={dling} onClick={() => downloadFallback(v.variant, g.sizes && g.sizes[0], `bannerly-${g.name || 'banner'}-${v.id}.png`)}><S2Icon name="download" size={16} /></button>
              </div>
            </div>
            <div style={{ aspectRatio: '1920 / 600' }}>
              <FilledBanner content={d.content} image={d.image} variant={v.variant} sty={d.sty} />
            </div>
          </div>
          )}
      </div>

      {/* size outputs */}
      <div className="section-title" style={{ justifyContent: 'space-between' }}>
        <span>사이즈별 출력</span>
        <span style={{ color: 'var(--text-subtle)', fontWeight: 500 }}>가이드 규격에 맞춰 자동 리사이징</span>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(210px,1fr))', gap: 14 }}>
        {g.sizes.map((s, i) => {
            const ratio = s.w / s.h;
            const useVariant = ratio < 1.3 ? 'a2' : 'a1';
            return (
              <div key={s.name} className="size-out fade-up" style={{ animationDelay: `${i * 40}ms` }}>
              <div className="so-frame" style={{ aspectRatio: ratio > 2.4 ? '16/5' : ratio < 1.2 ? '1/1' : '16/9' }}>
                <div style={{ width: ratio < 1 ? 'auto' : '100%', height: ratio < 1 ? '100%' : 'auto', aspectRatio: `${s.w} / ${s.h}` }}>
                  <FilledBanner content={d.content} image={d.image} variant={useVariant} sty={d.sty} />
                </div>
              </div>
              <div className="so-meta">
                <div>
                  <div className="so-nm">{s.name}</div>
                  <div className="so-dim">{s.w} × {s.h}</div>
                </div>
                <button className="icon-btn" title={`${s.name} 다운로드`} disabled={dling} onClick={() => downloadFallback(useVariant, s, `bannerly-${g.name || 'banner'}-${s.name || i}.png`)}><S2Icon name="download" size={16} /></button>
              </div>
            </div>);

          })}
      </div>

      {/* export bar */}
      <div className="export-bar">
        <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>
          <b style={{ color: 'var(--text-2)' }}>10개 파일</b> · 2변형 × 5규격
        </div>
        <div style={{ marginLeft: 'auto', display: 'flex', gap: 10 }}>
          <button className="btn btn-secondary" disabled={saving} onClick={saveFallback}><S2Icon name="copy" size={15} /> {savedOk ? '내 배너에 저장됨 ✓' : saving ? '저장 중…' : (savedDone ? '완료로 저장됨 · 다시 저장' : '내 배너에 저장')}</button>
          <button className="btn btn-primary" disabled={dling} onClick={downloadAllFallback}><S2Icon name="download" size={16} /> {dling ? '내보내는 중…' : '전체 PNG 다운로드'}</button>
        </div>
      </div>
      {previewUrl &&
        <div role="dialog" aria-modal="true" aria-label="배너 미리보기" onClick={closeFallbackPreview} style={{ position: 'fixed', inset: 0, zIndex: 10000, background: 'rgba(20,20,26,.72)', display: 'grid', placeItems: 'center', padding: 24 }}>
          <div onClick={(e) => e.stopPropagation()} style={{ maxWidth: 'min(92vw, 1100px)', maxHeight: '86vh', background: '#fff', padding: 10, position: 'relative' }}>
            <img src={previewUrl} alt="배너 미리보기" style={{ display: 'block', maxWidth: 'calc(92vw - 44px)', maxHeight: '80vh', objectFit: 'contain' }} />
            <button type="button" title="닫기" onClick={closeFallbackPreview} style={{ position: 'absolute', top: 8, right: 8, width: 30, height: 30, border: 0, background: 'rgba(20,20,26,.72)', color: '#fff', cursor: 'pointer', fontSize: 18 }}>×</button>
          </div>
        </div>}
    </div></div>);

}

// ── 앱푸시 생성 결과: 실제 템플릿(PushPreview) 마감 변형 후보 + 선택 + PNG 다운로드 ──
function PushResult({ d, onBack, ga4Source }) {
  const ga4Src = ga4Source === 'edit' ? 'edit' : 'asst';
  const SCH = window.SCHEMA_PUSH;
  const push = (d && d.push) || { type: SCH.types[0].id, fields: {} };
  const t = SCH.types.find((x) => x.id === push.type) || SCH.types[0];
  const variants = t.fullUpload ? [{ id: 'v1', label: '완성본', scrim: 'none', align: 'left', original: true }] : window.PUSH_VARIANTS;
  const mainImg = d.image;
  const copy = push.copy || (d.content && d.content.head) || '';
  const logo = push.logo, fields = push.fields || {};
  const [sel, setSel] = useS2(0);
  const [dling, setDling] = useS2(false);
  const [saving, setSaving] = useS2(false);
  const [savedOk, setSavedOk] = useS2(false);
  const [drafting, setDrafting] = useS2(false);
  const [draftId, setDraftId] = useS2(null);
  const [savedDone, setSavedDone] = useS2(false);
  const autoDraftRef = React.useRef(false);
  const sourcesSavedRef = React.useRef(false);
  const download = async () => {
    if (dling) return; setDling(true);
    try {
      const blob = await window.rasterizePush({ t, img: mainImg, copy, logo, fields, variant: variants[sel] });
      if (!blob) return;
      const url = URL.createObjectURL(blob), a = document.createElement('a');
      a.href = url; a.download = `bannerly-앱푸시-${t.id}-${variants[sel].id}.png`;
      document.body.appendChild(a); a.click(); a.remove();
      setTimeout(() => URL.revokeObjectURL(url), 1000);
      if (window.__ga4 && window.__ga4.trackDownload) window.__ga4.trackDownload('push', t.id || 'a', t.label || '', ga4Src);
    } finally { setDling(false); }
  };
  const _pushMeta = () => ({
    event: copy || t.label || '앱푸시', category: '앱푸시',
    type: t.label || t.id || '', strategy: variants[sel].id || '',
    width: 720, height: 380, worker: window.__bannerlyUser || '',
  });
  const _pushSources = async () => {
    if (sourcesSavedRef.current || !mainImg) return [];
    try { const b = await (await fetch(mainImg)).blob(); return b ? [{ blob: b, subtype: 'upload' }] : []; }
    catch (e) { return []; }
  };
  const saveDraft = async (opts) => {
    if (drafting || !window.__myBanners) return; setDrafting(true);
    try {
      const preview = await window.rasterizePush({ t, img: mainImg, copy, logo, fields, variant: variants[sel] });
      const sources = await _pushSources();
      const r = await window.__myBanners.saveProject(Object.assign(_pushMeta(), { status: 'draft', id: draftId, previewBlob: preview, sources }));
      if (r && r.ok) {
        setDraftId(r.id);
        if (window.BannerEditorPersist && window.BannerEditorPersist.sourcesPersisted(r, sources.length)) sourcesSavedRef.current = true;
      }
      else if (opts && opts.explicit) { alert('임시저장 실패: ' + ((r && r.error) || '알 수 없는 오류')); }
    } finally { setDrafting(false); }
  };
  const saveMine = async () => {
    if (saving || !window.__myBanners) return; setSaving(true);
    try {
      const blob = await window.rasterizePush({ t, img: mainImg, copy, logo, fields, variant: variants[sel] });
      const sources = await _pushSources();
      const r = await window.__myBanners.saveProject(Object.assign(_pushMeta(), { status: 'saved', id: draftId, finalBlob: blob, sources }));
      if (r && r.ok) {
        setDraftId(r.id);
        if (window.BannerEditorPersist && window.BannerEditorPersist.sourcesPersisted(r, sources.length)) sourcesSavedRef.current = true;
        setSavedOk(true); setSavedDone(true); setTimeout(() => setSavedOk(false), 2500);
        if (window.__ga4 && window.__ga4.trackDownload) window.__ga4.trackDownload('push', t.id || 'a', t.label || '', ga4Src);
      }
      else { alert('내 배너 저장 실패: ' + ((r && r.error) || '알 수 없는 오류')); }
    } finally { setSaving(false); }
  };
  React.useEffect(() => {
    if (autoDraftRef.current || !window.__myBanners) return;
    autoDraftRef.current = true;
    saveDraft();
  }, []);
  return (
    <div className="content"><div className="content-pad">
      <button className="btn btn-ghost btn-sm" style={{ marginBottom: 14, marginLeft: -8 }} onClick={onBack}>
        <S2Icon name="arrowLeft" size={15} /> 다시 편집
      </button>
      <div className="page-head" style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 24 }}>
        <div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <h1 className="page-title">앱푸시 생성 결과</h1>
            <span className="pill green"><span className="pill-dot" /> 후보 {variants.length}개</span>
          </div>
          <p className="page-sub">{t.label} · 720×380 · 마감 변형입니다. 원하는 안을 고르세요.</p>
        </div>
        <button className="btn btn-secondary" onClick={onBack}><S2Icon name="sliders" size={15} /> 미세조정</button>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(300px,1fr))', gap: 18, marginBottom: 32 }}>
        {variants.map((v, i) =>
          <button key={v.id} onClick={() => setSel(i)} style={{ textAlign: 'left', border: sel === i ? '2px solid var(--accent)' : '1px solid var(--border)', borderRadius: 12, padding: 8, background: '#fff', cursor: 'pointer' }}>
            <PushPreview t={t} img={mainImg} copy={copy} logo={logo} finalImg={push.finalImg || mainImg} fields={fields} variant={v} />
            <div style={{ fontSize: 12, fontWeight: 700, marginTop: 8, display: 'flex', alignItems: 'center', gap: 6, color: sel === i ? 'var(--accent-text)' : 'var(--text-2)' }}>
              {v.original ? '★ 원안' : `변형 ${String.fromCharCode(64 + i)} · ${v.label}`}
              {v.original && <span className="pill green" style={{ fontSize: 10 }}>추천</span>}
            </div>
          </button>)}
      </div>
      <div className="export-bar">
        <div style={{ fontSize: 13, color: 'var(--text-muted)' }}>선택: <b style={{ color: 'var(--text-2)' }}>{variants[sel].label}</b></div>
        <div style={{ marginLeft: 'auto', display: 'flex', gap: 10 }}>
          <button className="btn btn-ghost" disabled={drafting} onClick={() => saveDraft({ explicit: true })} title="작업중 상태로 임시 저장">{drafting ? '임시저장 중…' : '임시저장'}</button>
          <button className="btn btn-secondary" disabled={saving} onClick={saveMine}><S2Icon name="copy" size={15} /> {savedOk ? '내 배너에 저장됨 ✓' : saving ? '저장 중…' : (savedDone ? '완료로 저장됨 · 다시 저장' : '내 배너에 저장')}</button>
          <button className="btn btn-primary" disabled={dling} onClick={download}><S2Icon name="download" size={16} /> {dling ? '내보내는 중…' : 'PNG 다운로드'}</button>
        </div>
      </div>
    </div></div>);
}

Object.assign(window, { CreateBanner, CreateHead, BannerResult, PushResult, FilledBanner, STYLE_A });
