/* Analytics dashboards, Segments and A/B tests. */
function AnalyticsPage() {
  const [r, setR] = useState({ from: new Date(Date.now() - 27 * 864e5).toISOString().slice(0, 10), to: new Date().toISOString().slice(0, 10), source: '', device: '' });
  const [d, setD] = useState(null); const [busy, setBusy] = useState(false); const toast = useToast(); const { user } = useDraft();
  const load = async () => { setBusy(true); const x = await api(`/analytics/overview?from=${r.from}&to=${r.to}${r.source ? '&source=' + r.source : ''}${r.device ? '&device=' + r.device : ''}`); setBusy(false); if (x.data) setD(x.data); else toast(x.error, 'bad'); };
  useEffect(() => { load(); }, [r.from, r.to, r.source, r.device]);
  const rollup = async () => { setBusy(true); const x = await api('/analytics/rollup', { method: 'POST', timeout: 120000 }); setBusy(false); toast(x.error || `Rolled up: ${x.data.rollups.map(z => z.day + ' ' + z.rows).join(', ')}; orders joined ${x.data.orders.joined}`); load(); };
  const cols = (label) => [{ k: 'key', l: label }, { k: 'views', l: 'Views', num: true, f: x => fmt(x.views) }, { k: 'clicks', l: 'Clicks', num: true, f: x => fmt(x.clicks) }, { k: 'ctr', l: 'CTR', num: true, f: x => pct(x.ctr) }, { k: 'adds', l: 'Add to cart', num: true, f: x => fmt(x.adds) }, { k: 'orders', l: 'Orders', num: true, f: x => fmt(x.orders) }, { k: 'revenue', l: 'Revenue', num: true, f: x => x.revenue ? money(x.revenue) : '—' }];
  return <div>
    <div className="topbar"><h1>Analytics</h1><span className="muted">Our own events, no Google grants needed. Rolled up hourly for today and nightly for history.</span>
      <div className="right row wrap"><input type="date" value={r.from} onChange={e => setR({ ...r, from: e.target.value })} style={{ width: 150 }} /><input type="date" value={r.to} onChange={e => setR({ ...r, to: e.target.value })} style={{ width: 150 }} />
        <select value={r.source} onChange={e => setR({ ...r, source: e.target.value })} style={{ width: 140 }}><option value="">every source</option>{['email', 'paid_search', 'social', 'search', 'referral', 'direct'].map(s => <option key={s}>{s}</option>)}</select>
        <select value={r.device} onChange={e => setR({ ...r, device: e.target.value })} style={{ width: 120 }}><option value="">every device</option><option value="mobile">mobile</option><option value="desktop">desktop</option></select>
        {user?.can_publish && <button className="btn" onClick={rollup} disabled={busy}>Roll up now</button>}</div></div>
    {!d ? <div className="card muted">Loading…</div> : <>
      <div className="kpi"><div className="card"><div className="v">{fmt(d.totals.views)}</div><div className="l">Home page views</div></div><div className="card"><div className="v">{fmt(d.totals.clicks)}</div><div className="l">Clicks</div></div><div className="card"><div className="v">{d.totals.views ? pct(d.totals.clicks / d.totals.views) : '—'}</div><div className="l">Click-through</div></div><div className="card"><div className="v">{fmt(d.totals.adds)}</div><div className="l">Add to cart</div></div><div className="card"><div className="v">{fmt(d.totals.orders)}</div><div className="l">Attributed orders</div></div><div className="card"><div className="v">{money(d.totals.revenue)}</div><div className="l">Attributed revenue</div></div></div>
      <div className="card" style={{ marginTop: 12 }}><div className="row"><h2>Views by day</h2><span className="muted small right">Today so far (raw, not yet rolled up): {Object.entries(d.today.counts || {}).map(([k, v]) => `${k.replace('home_', '')} ${v}`).join(' · ') || 'nothing yet'}</span></div><Bars series={d.daily} /></div>
      <div className="grid2" style={{ marginTop: 12 }}>
        <div className="card"><h2>Rails</h2><Table cols={[...cols('Rail'), { k: 'pos', l: 'Avg position', num: true, f: x => x.avg_position != null ? x.avg_position.toFixed(1) : '—' }]} rows={d.rails} /></div>
        <div className="card"><h2>Hero variants</h2><Table cols={cols('Variant')} rows={d.hero} /></div>
        <div className="card"><h2>Seasons</h2><Table cols={cols('Season')} rows={d.seasons} /></div>
        <div className="card"><h2>Promo blocks</h2><Table cols={cols('Promo')} rows={d.promos} /></div>
        <div className="card"><h2>Related placements</h2><Table cols={cols('Placement')} rows={d.placements} /></div>
        <div className="card"><h2>Related by rule</h2><span className="muted small">Does hand-picked beat the data?</span><Table cols={cols('Placement : rule')} rows={d.rules} /></div>
        <div className="card"><h2>Search terms on the home page</h2><Table cols={[{ k: 'key', l: 'Term' }, { k: 'views', l: 'Searches', num: true, f: x => fmt(x.views) }]} rows={d.search} /></div>
        <div className="card"><h2>Zero-result searches</h2><span className="muted small">Merchandising leads: what people wanted that we did not have.</span><Table cols={[{ k: 'key', l: 'Term' }, { k: 'views', l: 'Searches', num: true, f: x => fmt(x.views) }]} rows={d.zero_results} /></div>
        <div className="card"><h2>Experiments</h2><Table cols={cols('Experiment : variant')} rows={d.experiments} /></div>
        <div className="card"><h2>Sources and devices</h2><Table cols={[{ k: 'source', l: 'Source', f: x => x.source || 'unknown' }, { k: 'device', l: 'Device', f: x => x.device || 'unknown' }, { k: 'views', l: 'Views', num: true, f: x => fmt(x.views) }]} rows={d.sources} /></div>
      </div></>}
  </div>;
}

/* ------------------------------------------------------------------ Segments + A/B tests */
function TargetingPage() {
  const toast = useToast(); const { segments, reloadSegments, user, refreshLive } = useDraft();
  const [exps, setExps] = useState([]); const [segForm, setSegForm] = useState(null); const [expForm, setExpForm] = useState(null); const [ending, setEnding] = useState(null);
  const loadExps = async () => { const r = await api('/experiments'); setExps(r.data || []); };
  useEffect(() => { loadExps(); }, []);
  const saveSeg = async (s) => { const r = await api('/segments', { method: 'POST', body: s }); if (r.error) return toast(r.error, 'bad'); toast('Segment saved'); setSegForm(null); reloadSegments(); refreshLive && refreshLive(); };
  const delSeg = async (s) => { if (!confirm(`Delete segment “${s.name}”? Sections targeting it show to everyone.`)) return; await api(`/segments/${s.id}`, { method: 'DELETE' }); reloadSegments(); };
  const saveExp = async (e) => { const r = await api('/experiments', { method: 'POST', body: e }); if (r.error) return toast(r.error, 'bad'); toast('Experiment saved'); setExpForm(null); loadExps(); };
  const start = async (e) => { const r = await api(`/experiments/${e.id}/start`, { method: 'POST' }); if (r.error) return toast(r.error, 'bad'); toast(`${e.name} is live`); loadExps(); refreshLive && refreshLive(); };
  const end = async (e, winner, promote) => { const r = await api(`/experiments/${e.id}/end`, { method: 'POST', body: { winner, promote } }); if (r.error) return toast(r.error, 'bad'); toast(promote && r.data.promoted_version ? `Ended. Winner published as v${r.data.promoted_version}` : 'Ended'); setEnding(null); loadExps(); refreshLive && refreshLive(); };
  return <div>
    <div className="topbar"><h1>Segments & tests</h1><span className="muted">Segments are evaluated in the browser from the arrival context. Tests assign once per session; never more than three live.</span></div>
    <div className="card"><div className="row" style={{ marginBottom: 10 }}><h2>Segments</h2><button className="btn primary right" onClick={() => setSegForm({ key: '', name: '', definition: { all: [] } })}>+ Segment</button></div>
      <Table cols={[{ k: 'name', l: 'Name', f: s => <div><b>{s.name}</b> <span className="mono muted">{s.key}</span></div> }, { k: 'def', l: 'Conditions (all must match)', f: s => (s.definition.all || []).map((c, i) => <span key={i} className="pill" style={{ marginRight: 4 }}>{c.field} {c.op} {String(c.value)}</span>) }, { k: 'a', l: '', f: s => <div className="row"><button className="btn sm" onClick={() => setSegForm(s)}>Edit</button><button className="btn sm danger" onClick={() => delSeg(s)}>Delete</button></div> }]} rows={segments || []} empty="No segments yet. Try: source = email and returning = true." /></div>
    <div className="card"><div className="row" style={{ marginBottom: 10 }}><h2>A/B tests</h2><span className="muted small">{exps.filter(e => e.status === 'live').length} of 3 live</span><button className="btn primary right" onClick={() => setExpForm({ key: '', name: '', target: 'hero', variants: [{ key: 'a', name: 'Control', weight: 1, patch: {} }, { key: 'b', name: 'Variant B', weight: 1, patch: {} }] })}>+ Experiment</button></div>
      <Table cols={[{ k: 'status', l: 'Status', f: e => <Pill kind={e.status === 'live' ? 'good' : e.status === 'ended' ? '' : 'warn'}>{e.status}</Pill> }, { k: 'name', l: 'Experiment', f: e => <div><b>{e.name}</b> <span className="mono muted">{e.key}</span><div className="muted small">{e.target} · {e.variants.map(v => `${v.key} (${v.weight})`).join(' / ')}{e.winner ? ` · winner ${e.winner}` : ''}</div></div> }, { k: 'a', l: '', f: e => <div className="row">{e.status === 'draft' && <button className="btn sm" onClick={() => setExpForm(e)}>Edit</button>}{e.status === 'draft' && user?.can_publish && <button className="btn sm primary" onClick={() => start(e)}>Start</button>}{e.status === 'live' && user?.can_publish && <button className="btn sm gold" onClick={() => setEnding(e)}>End…</button>}{e.status !== 'live' && user?.can_publish && <button className="btn sm danger" onClick={async () => { if (confirm('Delete this experiment?')) { await api(`/experiments/${e.id}`, { method: 'DELETE' }); loadExps(); } }}>Delete</button>}</div> }]} rows={exps} empty="No experiments yet." /></div>
    {segForm && <SegmentForm init={segForm} onSave={saveSeg} onClose={() => setSegForm(null)} />}
    {expForm && <ExperimentForm init={expForm} onSave={saveExp} onClose={() => setExpForm(null)} />}
    {ending && <EndExperiment e={ending} onEnd={end} onClose={() => setEnding(null)} />}
  </div>;
}
function SegmentForm({ init, onSave, onClose }) {
  const [s, set] = useState(init); const conds = s.definition.all || [];
  const setC = (i, p) => set({ ...s, definition: { all: conds.map((c, k) => k === i ? { ...c, ...p } : c) } });
  const fieldOf = (k) => SEGMENT_FIELDS.find(f => f.key === k) || SEGMENT_FIELDS[0];
  return <Modal title="Segment" onClose={onClose} footer={<><button className="btn" onClick={onClose}>Cancel</button><button className="btn primary" disabled={!s.name} onClick={() => onSave({ ...s, key: s.key || slug(s.name) })}>Save</button></>}>
    <div className="stack"><div className="grid2"><Field label="Name"><Text value={s.name} onChange={v => set({ ...s, name: v, key: s.id ? s.key : slug(v) })} /></Field><Field label="Key"><Text value={s.key} onChange={v => set({ ...s, key: slug(v) })} disabled={!!s.id} /></Field></div>
      {conds.map((c, i) => { const f = fieldOf(c.field); return <div className="row" key={i}><select value={c.field} onChange={e => setC(i, { field: e.target.value, value: fieldOf(e.target.value).type === 'bool' ? true : '' })} style={{ width: 240 }}>{SEGMENT_FIELDS.map(x => <option key={x.key} value={x.key}>{x.label}</option>)}</select>
        {f.type === 'bool' ? <select value={String(c.value)} onChange={e => setC(i, { op: 'eq', value: e.target.value === 'true' })}><option value="true">is true</option><option value="false">is false</option></select>
          : f.type === 'enum' ? <select value={c.value} onChange={e => setC(i, { op: 'eq', value: e.target.value })}><option value="">choose…</option>{f.options.map(o => <option key={o}>{o}</option>)}</select>
            : f.type === 'lane' ? <div className="row"><select value={c.lane || 'sports'} onChange={e => setC(i, { lane: e.target.value })}>{LANES.map(l => <option key={l}>{l}</option>)}</select><span className="small">viewed at least</span><input type="number" value={c.value || 1} onChange={e => setC(i, { op: 'gte', value: Number(e.target.value) })} style={{ width: 70 }} /></div>
              : f.type === 'range' ? <div className="row"><input type="number" placeholder="from" value={c.min ?? ''} onChange={e => setC(i, { op: 'between', min: Number(e.target.value) })} style={{ width: 80 }} /><input type="number" placeholder="to" value={c.max ?? ''} onChange={e => setC(i, { max: Number(e.target.value) })} style={{ width: 80 }} /></div>
                : <input type="text" value={c.value || ''} onChange={e => setC(i, { op: 'eq', value: e.target.value })} />}
        <button className="btn sm" onClick={() => set({ ...s, definition: { all: conds.filter((x, k) => k !== i) } })}>Remove</button></div>; })}
      <div><button className="btn sm" onClick={() => set({ ...s, definition: { all: [...conds, { field: 'source', op: 'eq', value: 'email' }] } })}>+ Condition</button></div></div>
  </Modal>;
}
function ExperimentForm({ init, onSave, onClose }) {
  const [e, set] = useState(init); const setV = (i, p) => set({ ...e, variants: e.variants.map((v, k) => k === i ? { ...v, ...p } : v) });
  const HELP = { hero: 'Patch example: {"hero":{"default":{"kicker":"Straight from the vault"}}}', sections: 'Patch example: {"sections_patch":[{"id":"trending","weight":90},{"id":"books","enabled":false}]}', promo: 'Patch example: {"sections_patch":[{"id":"promo_x","promo":{"headline":"…","asset_id":3}}]}', relations: 'Patch example: {"related":{"placements":{"home_similar":{"rules":["bought_together","signer_graph","searchspring"]}}}}' };
  return <Modal title="Experiment" wide onClose={onClose} footer={<><button className="btn" onClick={onClose}>Cancel</button><button className="btn primary" disabled={!e.name || e.variants.length < 2} onClick={() => onSave({ ...e, key: e.key || slug(e.name) })}>Save</button></>}>
    <div className="stack"><div className="grid3"><Field label="Name"><Text value={e.name} onChange={v => set({ ...e, name: v, key: e.id ? e.key : slug(v) })} /></Field><Field label="Key"><Text value={e.key} onChange={v => set({ ...e, key: slug(v) })} disabled={!!e.id} /></Field><Field label="What is tested"><select value={e.target} onChange={ev => set({ ...e, target: ev.target.value })}><option value="hero">Hero line</option><option value="sections">Section order / on-off</option><option value="promo">Promo image or copy</option><option value="relations">Relationship rule set</option></select></Field></div>
      <div className="notice info small">{HELP[e.target]}. The control's patch stays empty. Ending with “promote” merges the winner's patch into the live config as a new version.</div>
      {e.variants.map((v, i) => <div className="card tight" key={i}><div className="grid3"><Field label="Variant key"><Text value={v.key} onChange={x => setV(i, { key: slug(x) })} /></Field><Field label="Name"><Text value={v.name} onChange={x => setV(i, { name: x })} /></Field><Field label="Weight (split)"><input type="number" min="1" value={v.weight} onChange={x => setV(i, { weight: Number(x.target.value) })} /></Field></div><Field label="Patch (JSON)"><textarea className="mono" value={typeof v.patch === 'string' ? v.patch : JSON.stringify(v.patch || {}, null, 1)} onChange={x => { try { setV(i, { patch: JSON.parse(x.target.value) }); } catch (err) { setV(i, { patch: x.target.value }); } }} /></Field>{typeof v.patch === 'string' && <span className="pill bad">Invalid JSON</span>}{e.variants.length > 2 && <button className="btn sm" onClick={() => set({ ...e, variants: e.variants.filter((x, k) => k !== i) })}>Remove variant</button>}</div>)}
      <div><button className="btn sm" onClick={() => set({ ...e, variants: [...e.variants, { key: String.fromCharCode(97 + e.variants.length), name: 'Variant ' + String.fromCharCode(65 + e.variants.length), weight: 1, patch: {} }] })}>+ Variant</button></div></div>
  </Modal>;
}
function EndExperiment({ e, onEnd, onClose }) {
  const [winner, setWinner] = useState(e.variants[0].key); const [promote, setPromote] = useState(true); const [d, setD] = useState(null);
  useEffect(() => { api(`/analytics/overview?from=${(e.started_at || '2020-01-01').slice(0, 10)}`).then(r => r.data && setD(r.data.experiments.filter(x => x.key.startsWith(e.key + ':')))); }, []);
  const readout = () => {
    if (!d || d.length < 2) return 'Not enough data yet.';
    const s = d.map(x => ({ k: x.key.split(':')[1], n: x.views, c: x.clicks, p: x.views ? x.clicks / x.views : 0 })).sort((a, b) => b.p - a.p);
    const [a, b] = s; const pooled = (a.c + b.c) / Math.max(1, a.n + b.n); const se = Math.sqrt(pooled * (1 - pooled) * (1 / Math.max(1, a.n) + 1 / Math.max(1, b.n))); const z = se ? (a.p - b.p) / se : 0;
    return `${a.k} leads at ${pct(a.p)} vs ${pct(b.p)} (${fmt(a.n)} vs ${fmt(b.n)} views). ${Math.abs(z) >= 1.96 ? 'The difference is likely real.' : Math.abs(z) >= 1.3 ? 'Leaning real, but keep it running.' : 'Too close to call yet.'}`;
  };
  return <Modal title={`End “${e.name}”`} onClose={onClose} footer={<><button className="btn" onClick={onClose}>Cancel</button><button className="btn primary" onClick={() => onEnd(e, winner, promote)}>End experiment</button></>}>
    <div className="stack"><div className="notice info">{readout()}</div>{d && <Table cols={[{ k: 'key', l: 'Variant' }, { k: 'views', l: 'Views', num: true }, { k: 'clicks', l: 'Clicks', num: true }, { k: 'ctr', l: 'CTR', num: true, f: x => pct(x.ctr) }, { k: 'adds', l: 'Adds', num: true }, { k: 'revenue', l: 'Revenue', num: true, f: x => x.revenue ? money(x.revenue) : '—' }]} rows={d} />}
      <Field label="Winner"><select value={winner} onChange={ev => setWinner(ev.target.value)}>{e.variants.map(v => <option key={v.key} value={v.key}>{v.name || v.key}</option>)}</select></Field><Toggle on={promote} onChange={setPromote} label="Publish the winner into the live config as a new version" /></div>
  </Modal>;
}
