/* =========================================================
   Tappt — Pre-generated profile builder (CEO only)
   Builds a real, claimable profile for an influencer using the
   EXACT same surfaces as the live app: OwnProfile (live preview),
   EditProfile (full inline editor) and DesignPanel (themes,
   wallpaper, link/icon animations, card style, fonts). Operates on
   an ISOLATED draft (never the CEO's own account), then on Generate
   uploads any picked images to Storage and saves a pregen row.
   The influencer claims it via app.tappt.io/login?claimprofile=<token>.
   ========================================================= */
const { useState: pgUse, useRef: pgRef } = React;

function pgReadImg(file, cb) {
  if (!file) return;
  const r = new FileReader();
  r.onload = () => cb(r.result);
  r.readAsDataURL(file);
}

/* parse an aspect string like "16 / 9" → number; default 1 */
function pgAspect(a) {
  if (!a) return 1;
  if (typeof a === 'number') return a;
  const m = String(a).split('/').map((s) => parseFloat(s.trim()));
  return (m.length === 2 && m[1]) ? m[0] / m[1] : 1;
}

/* Drag-to-reposition + zoom cropper — shows the EXACT frame an image fills, bakes the
   visible crop to a data URL. Exported for reuse in the dashboard editor. */
function PgCropper({ src, aspect, round, onCancel, onDone }) {
  const ar = pgAspect(aspect);
  const imgRef = pgRef(null);
  const [nat, setNat] = pgUse(null);
  const [zoom, setZoom] = pgUse(1);
  const [pos, setPos] = pgUse({ x: 0, y: 0 });
  const drag = pgRef(null);
  const FRAME_W = 300;
  const FRAME_H = Math.round(FRAME_W / ar);
  const baseScale = nat ? Math.max(FRAME_W / nat.w, FRAME_H / nat.h) : 1;
  const dispW = nat ? nat.w * baseScale * zoom : 0;
  const dispH = nat ? nat.h * baseScale * zoom : 0;
  const clamp = (p) => ({ x: Math.min(0, Math.max(FRAME_W - dispW, p.x)), y: Math.min(0, Math.max(FRAME_H - dispH, p.y)) });
  React.useEffect(() => { if (nat) setPos((p) => clamp(p)); /* eslint-disable-next-line */ }, [zoom, nat]);
  const onImgLoad = (e) => {
    const w = e.target.naturalWidth, h = e.target.naturalHeight;
    setNat({ w: w, h: h });
    const bs = Math.max(FRAME_W / w, FRAME_H / h);
    setPos({ x: (FRAME_W - w * bs) / 2, y: (FRAME_H - h * bs) / 2 });
  };
  const start = (cx, cy) => { drag.current = { cx: cx, cy: cy, x: pos.x, y: pos.y }; };
  const move = (cx, cy) => { if (!drag.current) return; setPos(clamp({ x: drag.current.x + (cx - drag.current.cx), y: drag.current.y + (cy - drag.current.cy) })); };
  const end = () => { drag.current = null; };
  const bake = () => {
    if (!nat) { onCancel(); return; }
    try {
      // render at the ACTUAL source resolution available for the cropped region (no quality loss),
      // capped at 1600px wide. Previously a fixed 660px canvas downscaled good photos.
      const srcPerDisp = 1 / (baseScale * zoom);
      let outW = Math.round(FRAME_W * srcPerDisp);
      outW = Math.min(1600, Math.max(FRAME_W * 2, outW));
      const scale = outW / FRAME_W;
      const canvas = document.createElement('canvas');
      canvas.width = Math.round(outW); canvas.height = Math.round(FRAME_H * scale);
      const ctx = canvas.getContext('2d');
      ctx.imageSmoothingEnabled = true; ctx.imageSmoothingQuality = 'high';
      ctx.drawImage(imgRef.current, pos.x * scale, pos.y * scale, dispW * scale, dispH * scale);
      onDone(canvas.toDataURL('image/jpeg', 0.92));
    } catch (e) {
      // cross-origin image without CORS would taint the canvas — fall back to the original
      // so the button still works (keeps the existing image rather than failing silently)
      onDone(src);
    }
  };
  return (
    <div className="pg-crop-bg" onClick={onCancel}>
      <div className="pg-crop-card" onClick={(e) => e.stopPropagation()}>
        <div className="pg-crop-title">Position image</div>
        <p className="pg-crop-sub">Drag to move · slide to zoom. This is the exact crop shown on the profile.</p>
        <div
          className={'pg-crop-frame' + (round ? ' is-round' : '')}
          style={{ width: FRAME_W, height: FRAME_H }}
          onMouseDown={(e) => { e.preventDefault(); start(e.clientX, e.clientY); }}
          onMouseMove={(e) => move(e.clientX, e.clientY)}
          onMouseUp={end} onMouseLeave={end}
          onTouchStart={(e) => { const t = e.touches[0]; start(t.clientX, t.clientY); }}
          onTouchMove={(e) => { const t = e.touches[0]; move(t.clientX, t.clientY); }}
          onTouchEnd={end}
        >
          <img ref={imgRef} src={src} alt="" onLoad={onImgLoad} crossOrigin="anonymous" draggable={false}
            style={{ position: 'absolute', left: pos.x, top: pos.y, width: dispW || 'auto', height: dispH || 'auto', maxWidth: 'none', userSelect: 'none', pointerEvents: 'none' }} />
        </div>
        <input className="pg-crop-zoom" type="range" min="1" max="3" step="0.01" value={zoom} onChange={(e) => setZoom(parseFloat(e.target.value))} />
        <div className="pg-crop-acts">
          <button className="pg-crop-cancel" onClick={onCancel}>Cancel</button>
          <button className="pg-crop-save" onClick={bake}>Use photo</button>
        </div>
      </div>
    </div>
  );
}
window.PgCropper = PgCropper;

/* a fresh, branded, isolated draft — pro:true unlocks all design features in the editor;
   it is stripped before saving so the influencer doesn't inherit free Pro. */
function pgBlankDraft() {
  const av = (window.AVATAR_COLORS && window.AVATAR_COLORS[0]) || 'linear-gradient(135deg,#6B8299,#3a4f63)';
  return {
    pro: true, accountType: 'creator',
    name: '', handle: '', bio: '',
    avatar: null, avatarColor: av, showAvatar: false,
    cover: null, coverKind: 'image', covers: [], align: 'centered',
    sections: (window.DEFAULT_SECTIONS || []).map((s) => Object.assign({}, s, {
      on: (s.id === 'featured' || s.id === 'moments' || s.id === 'bio' || s.id === 'gallery') ? true : s.on,
    })),
    links: [], socials: [], socialData: {}, actions: [], actionData: {}, products: [], gallery: [],
    saveContact: false, profileTheme: 'default', buttonStyle: 'solid', buttonRadius: 'md',
    wallpaper: '', cardEffect: 'none', profileAnim: 'none', linkAnim: 'none', iconAnim: 'none',
    headlineFont: 'display', avatarRing: false, verified: false,
    moments: [{ id: 'pgm-' + Date.now(), cap: "Hey I'm on Tappt ✨", ts: Date.now(), taps: 0, comments: [] }],
  };
}

/* deep-walk a value and upload any data: URLs to Storage, returning public URLs */
async function pgUploadDeep(val) {
  if (typeof val === 'string') {
    if (val.indexOf('data:') === 0) { try { const u = await window.TapptDB.uploadMedia(val); return u || val; } catch (e) { return val; } }
    return val;
  }
  if (Array.isArray(val)) { const out = []; for (let i = 0; i < val.length; i++) out.push(await pgUploadDeep(val[i])); return out; }
  if (val && typeof val === 'object') { const out = {}; for (const k in val) out[k] = await pgUploadDeep(val[k]); return out; }
  return val;
}

const PG_FIELDS = ['name', 'handle', 'bio', 'avatar', 'avatarColor', 'showAvatar', 'cover', 'coverKind', 'covers', 'align', 'sections', 'links', 'socials', 'socialData', 'saveContact', 'actions', 'actionData', 'products', 'gallery', 'gallerySize', 'merchStyle', 'merchRotate', 'profileAnim', 'profileTheme', 'buttonStyle', 'buttonRadius', 'wallpaper', 'cardEffect', 'avatarRing', 'headlineFont', 'verified', 'spotlight', 'drop', 'role', 'company', 'accountType', 'linkAnim', 'iconAnim'];

function PregenGenerator({ onClose, toast, editToken }) {
  const MI2 = window.MI;
  // when editing an existing profile, draft starts null until the row loads (EditProfile
  // reads its user once on mount, so the data MUST be present before it renders)
  const [draft, setDraft] = pgUse(editToken ? null : pgBlankDraft());
  const [editing, setEditing] = pgUse(true);     // open straight into the editor
  const [designOpen, setDesignOpen] = pgUse(false);
  const [designDraft, setDesignDraft] = pgUse(null);
  const [busy, setBusy] = pgUse(false);
  const [result, setResult] = pgUse(null);

  React.useEffect(() => {
    if (!editToken) return;
    let alive = true;
    (async () => {
      let pg = null;
      try { pg = await window.TapptDB.loadPregen(editToken); } catch (e) {}
      if (!alive) return;
      if (pg) {
        setDraft(Object.assign({}, pgBlankDraft(), pg.data || {}, { name: pg.name || '', handle: pg.handle || '', bio: pg.bio || '', pro: true }));
      } else { setDraft(pgBlankDraft()); toast && toast('Could not load that profile'); }
    })();
    return () => { alive = false; };
  }, [editToken]);

  const Edit = window.EditProfile;
  const Own = window.OwnProfile;
  const Design = window.DesignPanel;

  if (editToken && !draft) {
    return (
      <div className="ceo-overlay pg-overlay"><div className="ceo-top"><b>Loading profile…</b><button className="ceo-close" onClick={onClose}>✕</button></div>
        <div className="ceo-body" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}><div className="oauth-splash-spin" /></div></div>
    );
  }

  const openDesign = () => {
    setDesignDraft({
      profileTheme: draft.profileTheme || 'default', linkAnim: draft.linkAnim || 'none', iconAnim: draft.iconAnim || 'none',
      headlineFont: draft.headlineFont || 'display', avatarRing: draft.avatarRing || false,
      buttonStyle: draft.buttonStyle || 'solid', buttonRadius: draft.buttonRadius || 'md',
      wallpaper: draft.wallpaper || '', cardEffect: draft.cardEffect || 'none', profileAnim: draft.profileAnim || 'none',
    });
    setDesignOpen(true);
  };

  const cleanHandle = (draft.handle || '').trim().toLowerCase().replace(/^@+/, '').replace(/[^a-z0-9_.]/g, '');

  async function generate() {
    if (!cleanHandle) { toast && toast('Set a username in the editor first'); setEditing(true); return; }
    if (!window.TapptDB || !window.TapptDB.available()) { toast && toast('Need to be online'); return; }
    setBusy(true);
    try {
      const clean = {};
      PG_FIELDS.forEach((f) => { if (draft[f] !== undefined) clean[f] = draft[f]; });
      clean.handle = cleanHandle;
      // use whatever moment(s) were composed in the preview; fall back to a friendly default
      clean.moments = (draft.moments && draft.moments.length) ? draft.moments : [{ id: 'pgm-' + Date.now(), cap: "Hey I'm on Tappt ✨", ts: Date.now(), taps: 0, comments: [] }];
      const uploaded = await pgUploadDeep(clean);
      const token = editToken || (cleanHandle + '-' + Math.random().toString(36).slice(2, 7));
      const ok = await window.TapptDB.savePregen(token, { handle: cleanHandle, name: (draft.name || '').trim(), bio: (draft.bio || '').trim(), data: uploaded });
      if (!ok) { toast && toast('Save failed — check connection'); setBusy(false); return; }
      setResult({ token: token, claimLink: 'https://app.tappt.io/login?claimprofile=' + token, previewLink: 'https://tappt.io/p/' + token });
      toast && toast('Profile generated ✨');
    } catch (e) { toast && toast('Error: ' + (e.message || 'failed')); }
    setBusy(false);
  }

  const copy = (t) => { try { navigator.clipboard.writeText(t); toast && toast('Copied'); } catch (e) {} };

  if (result) {
    return (
      <div className="ceo-overlay pg-overlay">
        <div className="ceo-top"><div className="ceo-brand">{MI2.gift ? MI2.gift({ width: 16, height: 16 }) : '🎁'} <b>Profile ready</b></div><button className="ceo-close" onClick={onClose}>{MI2.close ? MI2.close({ width: 18, height: 18 }) : '✕'}</button></div>
        <div className="ceo-body pg-done">
          <div className="pg-done-ic">{MI2.check ? MI2.check({ width: 30, height: 30 }) : '✓'}</div>
          <h3>@{cleanHandle}'s profile is live</h3>
          <p className="ceo-p">Send the claim link in your DM. When they sign up through it, this whole profile becomes theirs — they just confirm their handle &amp; they're done.</p>
          <div className="pg-link-row"><div className="pg-link-lbl">Claim link (DM this)</div><button className="pg-link-copy" onClick={() => copy(result.claimLink)}>{result.claimLink} · Copy</button></div>
          <div className="pg-link-row"><div className="pg-link-lbl">Preview (screenshot / show them)</div><button className="pg-link-copy" onClick={() => copy(result.previewLink)}>{result.previewLink} · Copy</button></div>
          <div className="pg-done-actions">
            <a className="ceo-btn pg-preview-btn" href={result.previewLink} target="_blank" rel="noopener">Open preview</a>
            <button className="ceo-btn-ghost" onClick={() => { setResult(null); setDraft(pgBlankDraft()); setEditing(true); }}>Build another</button>
          </div>
        </div>
      </div>
    );
  }

  if (!Edit || !Own || !Design) {
    return (
      <div className="ceo-overlay pg-overlay"><div className="ceo-top"><b>Profile generator</b><button className="ceo-close" onClick={onClose}>✕</button></div>
        <div className="ceo-body"><p className="ceo-p">Editor components still loading — close and reopen.</p></div></div>
    );
  }

  return (
    <div className="ceo-overlay pg-overlay pg-fulledit">
      <div className="ceo-top pg-top">
        <button className="ceo-close" onClick={onClose}>{MI2.close ? MI2.close({ width: 18, height: 18 }) : '✕'}</button>
        <div className="pg-top-mid">Build profile{cleanHandle ? ' · @' + cleanHandle : ''}</div>
        <button className="pg-gen-btn" disabled={busy} onClick={generate}>{busy ? 'Generating…' : 'Generate'}</button>
      </div>
      <div className="appframe pg-appframe" data-tab={editing ? 'edit' : 'profile'}>
        {!editing && (
          <Own
            user={(designOpen && designDraft) ? Object.assign({}, draft, designDraft) : draft}
            onEdit={() => setEditing(true)} onDesign={openDesign}
            onShare={() => {}} onMenu={() => {}} onMoments={() => {}} onPersona={() => {}}
            onEditMoment={(id, patch) => setDraft((d) => Object.assign({}, d, { moments: (d.moments || []).map((m) => m.id === id ? Object.assign({}, m, patch) : m) }))}
            onDeleteMoment={(id) => setDraft((d) => Object.assign({}, d, { moments: (d.moments || []).filter((m) => m.id !== id) }))}
            onSetComments={(id, arr) => setDraft((d) => Object.assign({}, d, { moments: (d.moments || []).map((m) => m.id === id ? Object.assign({}, m, { comments: arr }) : m) }))}
            onPostMoment={(m) => setDraft((d) => Object.assign({}, d, { moments: [m, ...(d.moments || [])] }))}
            onLead={() => {}} onTip={() => {}} toast={toast}
          />
        )}
        {editing && (
          <Edit user={draft} openPro={() => {}} toast={toast}
            onCancel={() => setEditing(false)}
            onSave={(d) => { setDraft(Object.assign({}, draft, d)); setEditing(false); }} />
        )}
        {designOpen && designDraft && (
          <Design draft={designDraft} isPro={true}
            onChange={(patch) => setDesignDraft((d) => Object.assign({}, d, patch))}
            onPro={() => {}}
            onApply={() => { setDraft((dr) => Object.assign({}, dr, designDraft)); setDesignOpen(false); }}
            onCancel={() => setDesignOpen(false)} />
        )}
      </div>
      {!editing && !designOpen && (
        <div className="pg-hint">Tap the profile to edit · use the design button for themes &amp; wallpaper · then hit Generate</div>
      )}
    </div>
  );
}

window.PregenGenerator = PregenGenerator;
