// Main app shell for the World Cup 2026 Prediction Game poster generator.
// Single template (TplWC26). User edits app URL, headline, subheadline,
// body text and uploads a logo. Exports A3 poster and A5 flyer in PNG + PDF.

const { useState, useEffect, useMemo, useRef } = React;

// A4/A3/A5 are all the same aspect ratio (1:√2). Design native = 1837×2603.
// We render at design native into the on-screen canvas, then re-render for
// export at higher resolutions to get crisp PNG/PDF output.
//
//   A3 portrait @ 300 dpi → 3508 × 4961 px
//   A5 portrait @ 300 dpi → 1748 × 2480 px
const SIZES = {
  preview: { width: 1837, label: 'Design native' },
  A3:      { width: 3508, mm: [297, 420], label: 'A3 poster' },
  A5:      { width: 1748, mm: [148, 210], label: 'A5 flyer'  },
};

const STORAGE_KEY = 'wc26.params.v1';

// Default headline differs by variant — v2 stacks "Prediction" and "Game"
// as separate lines beside the phone, while v1 keeps them on one line.
const V1_DEFAULT_HEAD = 'World Cup 2026\nPrediction Game';
const V2_DEFAULT_HEAD = 'World Cup 2026\nPrediction\nGame';

const DEFAULT_P = {
  variant:     'v1',     // 'v1' = centered double-phone, 'v2' = split single-phone
  language:    'en',     // 'en' or 'de' — controls the FIFA disclaimer
  appUrl:      'https://app.flip.com',
  headline:    V1_DEFAULT_HEAD,
  subheadline: 'On your\nEmployee App!',
  bodyText:    "If you don't have it already, scan the QR to download the app and start playing!",
  logoUrl:     '',
};

function loadParams() {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) return DEFAULT_P;
    return { ...DEFAULT_P, ...JSON.parse(raw) };
  } catch (e) {
    return DEFAULT_P;
  }
}

function App() {
  const [params, setParams] = useState(loadParams);
  const [busy, setBusy] = useState(null); // e.g. 'A3-png', 'A5-pdf'

  const update = (patch) => setParams(p => ({ ...p, ...patch }));

  // Switching variant: also swap the headline default if the user hasn't
  // customized it, so the layout matches what the variant expects.
  function setVariant(nextVariant) {
    setParams(p => {
      const currentDefault = p.variant === 'v2' ? V2_DEFAULT_HEAD : V1_DEFAULT_HEAD;
      const nextDefault    = nextVariant === 'v2' ? V2_DEFAULT_HEAD : V1_DEFAULT_HEAD;
      const headline = (p.headline === currentDefault) ? nextDefault : p.headline;
      return { ...p, variant: nextVariant, headline };
    });
  }

  // Persist params to localStorage on every change
  useEffect(() => {
    try { localStorage.setItem(STORAGE_KEY, JSON.stringify(params)); }
    catch (e) { /* localStorage quota / private mode — ignore */ }
  }, [params]);

  // ── Preview-stage scaling ────────────────────────────────────
  // We render the poster at native 1837 px wide inside a 'canvas' div, then
  // CSS-scale it to fit the visible stage. This keeps export resolution
  // independent of the user's screen size.
  const stageRef = useRef(null);
  const [stageScale, setStageScale] = useState(0.3);
  useEffect(() => {
    if (!stageRef.current) return;
    function recompute() {
      const el = stageRef.current;
      if (!el) return;
      const rect = el.getBoundingClientRect();
      // Padding so the canvas doesn't touch the stage edges.
      const padX = 48, padY = 48;
      const targetW = 1837, targetH = 2603;
      const sX = (rect.width  - padX) / targetW;
      const sY = (rect.height - padY) / targetH;
      setStageScale(Math.max(0.05, Math.min(sX, sY)));
    }
    recompute();
    // ResizeObserver picks up panel resize, font load, etc — more
    // reliable than window 'resize' alone.
    const ro = new ResizeObserver(recompute);
    ro.observe(stageRef.current);
    window.addEventListener('resize', recompute);
    return () => {
      ro.disconnect();
      window.removeEventListener('resize', recompute);
    };
  }, []);

  // ── Logo upload (FileReader → data URL → state) ─────────────
  const onLogoUpload = (e) => {
    const f = e.target.files?.[0];
    if (!f) return;
    const r = new FileReader();
    r.onload = () => update({ logoUrl: r.result });
    r.readAsDataURL(f);
  };

  // ── Export helpers ──────────────────────────────────────────
  // Render the template offscreen at the requested export width, then use
  // html-to-image to rasterize. For PDF, embed the resulting PNG into a
  // jsPDF document of the matching A-size at 300dpi.
  async function exportAt(sizeKey, format) {
    const cfg = SIZES[sizeKey];
    if (!cfg) return;
    setBusy(`${sizeKey}-${format}`);

    // Build offscreen container
    const off = document.createElement('div');
    off.style.position = 'fixed';
    off.style.left = '-99999px';
    off.style.top = '0';
    off.style.width = `${cfg.width}px`;
    off.style.background = 'transparent';
    document.body.appendChild(off);

    // Render the template into the offscreen container via ReactDOM
    const root = ReactDOM.createRoot(off);
    root.render(<TplWC26 p={params} width={cfg.width}/>);
    // Give React + fonts a tick to settle.
    await new Promise(r => setTimeout(r, 250));

    try {
      const node = off.firstElementChild;
      const dataUrl = await htmlToImage.toPng(node, {
        cacheBust: true,
        pixelRatio: 1, // we already render at full px; no need to upscale
        backgroundColor: '#000000',
      });

      if (format === 'png') {
        triggerDownload(dataUrl, fileNameFor(sizeKey, 'png'));
      } else if (format === 'pdf') {
        const { jsPDF } = window.jspdf;
        const [mmW, mmH] = cfg.mm;
        const doc = new jsPDF({
          orientation: 'portrait',
          unit: 'mm',
          format: [mmW, mmH],
          compress: true,
        });
        doc.addImage(dataUrl, 'PNG', 0, 0, mmW, mmH, undefined, 'FAST');
        doc.save(fileNameFor(sizeKey, 'pdf'));
      }
    } catch (err) {
      console.error('Export failed:', err);
      alert('Export failed. Open the browser console for details.');
    } finally {
      // Clean up offscreen container
      try { root.unmount(); } catch (e) { /* */ }
      try { document.body.removeChild(off); } catch (e) { /* */ }
      setBusy(null);
    }
  }

  function fileNameFor(sizeKey, ext) {
    return `wc26-${params.variant || 'v1'}-${sizeKey.toLowerCase()}.${ext}`;
  }

  function triggerDownload(dataUrl, filename) {
    const a = document.createElement('a');
    a.href = dataUrl;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  }

  // ── Render ──────────────────────────────────────────────────
  return (
    <div className="app">
      <header className="topbar">
        <div className="brand">
          <FlipWordmark height={22}/>
          <span style={{color: 'var(--ink-3)', fontWeight: 400, marginLeft: 10}}>
            World Cup 2026 · Prediction Game · Poster Generator
          </span>
        </div>
      </header>

      <div className="layout">
        {/* ── Left: input panel ────────────────────────────── */}
        <aside className="panel">
          <div>
            <h2>Layout</h2>
          </div>

          <div className="field">
            <div style={{display: 'flex', gap: 6}}>
              <button
                className={'btn' + (params.variant === 'v1' ? ' primary' : '')}
                style={{flex: 1}}
                onClick={() => setVariant('v1')}>
                Centered
              </button>
              <button
                className={'btn' + (params.variant === 'v2' ? ' primary' : '')}
                style={{flex: 1}}
                onClick={() => setVariant('v2')}>
                Split
              </button>
            </div>
            <div className="hint">Centered: stacked headline, two phones. Split: "World Cup 2026" on top, "Prediction Game" beside a single tilted phone.</div>
          </div>

          <div>
            <h2>Content</h2>
          </div>

          <div className="field">
            <label className="lbl">App URL <span style={{color: 'var(--ink-4)'}}>(QR code)</span></label>
            <input type="url"
                   value={params.appUrl}
                   placeholder="https://app.flip.com/wc26"
                   onChange={e => update({ appUrl: e.target.value })}/>
            <div className="hint">The QR code in the bottom-left will encode this URL.</div>
          </div>

          <div className="field">
            <label className="lbl">Headline</label>
            <textarea value={params.headline}
                      onChange={e => update({ headline: e.target.value })}/>
            <div className="hint">Use a line break to split across two lines.</div>
          </div>

          <div className="field">
            <label className="lbl">Subheadline</label>
            <input type="text" value={params.subheadline}
                   onChange={e => update({ subheadline: e.target.value })}/>
          </div>

          <div className="field">
            <label className="lbl">Body text</label>
            <textarea value={params.bodyText}
                      onChange={e => update({ bodyText: e.target.value })}/>
          </div>

          <div>
            <h2>Disclaimer language</h2>
          </div>

          <div className="field">
            <div style={{display: 'flex', gap: 6}}>
              <button
                className={'btn' + (params.language === 'en' ? ' primary' : '')}
                style={{flex: 1}}
                onClick={() => update({ language: 'en' })}>
                English
              </button>
              <button
                className={'btn' + (params.language === 'de' ? ' primary' : '')}
                style={{flex: 1}}
                onClick={() => update({ language: 'de' })}>
                Deutsch
              </button>
            </div>
            <div className="hint">Switches the FIFA disclaimer at the bottom of the poster between English and German. Applies to both layouts.</div>
          </div>

          <div>
            <h2>Branding</h2>
          </div>

          <div className="field">
            <label className="lbl">Logo override <span style={{color: 'var(--ink-3)'}}>(PNG / SVG)</span></label>
            <div className="file-row">
              {params.logoUrl && (
                <img className="thumb" src={params.logoUrl} alt="logo preview"/>
              )}
              <input type="file" accept="image/png,image/svg+xml,image/jpeg"
                     onChange={onLogoUpload}/>
              {params.logoUrl && (
                <button className="btn" onClick={() => update({ logoUrl: '' })}>
                  Clear
                </button>
              )}
            </div>
            <div className="hint">Replaces the Flip swirl in the bottom-right card. Leave empty for the default Flip mark.</div>
          </div>

          <div>
            <h2>Download</h2>
          </div>

          <div className="export-grid">
            <div className="group">
              <div className="ttl">A3 · Poster</div>
              <button className="btn primary"
                      disabled={busy !== null}
                      onClick={() => exportAt('A3', 'png')}>
                {busy === 'A3-png' ? 'Rendering…' : 'PNG'}
              </button>
              <button className="btn"
                      disabled={busy !== null}
                      onClick={() => exportAt('A3', 'pdf')}>
                {busy === 'A3-pdf' ? 'Rendering…' : 'PDF'}
              </button>
            </div>
            <div className="group">
              <div className="ttl">A5 · Flyer</div>
              <button className="btn primary"
                      disabled={busy !== null}
                      onClick={() => exportAt('A5', 'png')}>
                {busy === 'A5-png' ? 'Rendering…' : 'PNG'}
              </button>
              <button className="btn"
                      disabled={busy !== null}
                      onClick={() => exportAt('A5', 'pdf')}>
                {busy === 'A5-pdf' ? 'Rendering…' : 'PDF'}
              </button>
            </div>
          </div>
          <div className="hint">PNG renders at 300dpi. PDF embeds the same image at the exact paper size.</div>

          <div style={{marginTop: 'auto', paddingTop: 12,
                       borderTop: '1px solid var(--line)', fontSize: 11,
                       color: 'var(--ink-4)', lineHeight: 1.5}}>
            All edits stay in your browser (localStorage). Nothing is sent to a
            server. Refresh the page anytime — your inputs persist.
          </div>
        </aside>

        {/* ── Right: live preview ──────────────────────────── */}
        <main className="stage" ref={stageRef}>
          <div className="canvas-wrap" style={{
            transform: `scale(${stageScale})`,
          }}>
            <TplWC26 p={params} width={1837}/>
          </div>
        </main>
      </div>
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);
