/* Plans kit, shared by the Plans page (plans.html) and the course pages (/courses/cat · ipmat · cuet):
   the plans on sale (GET /api/payments/plans) as pricing cards with Buy now → the plan picker (components/sb-gate.js,
   Razorpay checkout; a student who isn't logged in logs in first and comes back with ?buy=<plan id>), the free trial
   per course (settings.trialAreas / trialDays), what's free, how it works, and FAQs.
   Inside the Android app nothing is sold (Google Play rules): no prices or buy buttons (components/sb-app.js). */
const PK_COURSES=[
{key:'cat',label:'CAT',page:'/courses/cat'},
{key:'ipmat',label:'IPMAT · JIPMAT · IIM B (B.Sc.)',short:'IPMAT',page:'/courses/ipmat'},
{key:'cuet',label:'CUET (UG)',short:'CUET',page:'/courses/cuet'},
{key:'varc',label:'VARC & more'}];
function pkInr(n){return '₹'+Number(n||0).toLocaleString('en-IN');}
function pkCourses(p,areas){const c={};(p.areas||[]).forEach(k=>{const a=(areas||[]).find(x=>x.key===k);const ck=a&&a.course||(/^cuet-subj:/.test(k)?'cuet':'');if(ck)c[ck]=1;});if(p.pick)c.cuet=1;return c;}
/* the longest free trial among a course's rights (0 = no trial) */
function pkTrialDays(course,areas){
const s=(window.SBAuth&&window.SBAuth.settings&&window.SBAuth.settings())||{},ta=s.trialAreas||{},def=Number(s.trialDays||0);
const keys=(areas||[]).filter(a=>a.course===course&&!a.subject&&!a.free).map(a=>a.key);
if(!keys.length)return def;
return Math.max(0,...keys.map(k=>ta[k]===undefined||ta[k]===null||ta[k]===''?def:Number(ta[k])||0));
}
function usePlans(){
const [d,setD]=React.useState(null);
React.useEffect(()=>{let on=true;fetch('/api/payments/plans',{credentials:'same-origin'}).then(r=>r.ok?r.json():{plans:[],areas:[]}).then(x=>{if(on)setD(x);}).catch(()=>{if(on)setD({plans:[],areas:[]});});return()=>{on=false;};},[]);
return d;
}
/* Buy now: logged in → the plan picker for this plan; otherwise log in first (one-time code) and come back */
function pkBuy(p){
const u=window.SBAuth&&window.SBAuth.currentUser();
if(!u){const here=location.pathname.replace(/^\//,'')+(location.search?location.search.replace(/([?&])buy=\d+&?/,'$1').replace(/[?&]$/,''):'');
location.href='login.html?next='+encodeURIComponent(here+(here.indexOf('?')>=0?'&':'?')+'buy='+p.id);return;}
if(window.SBGate)window.SBGate.showPaywall(u,{force:true,planId:p.id,title:'Get '+p.name,text:'Pay securely with Razorpay — UPI, cards, netbanking or wallets. Access starts the moment your payment is confirmed.'});
}
/* back from login with ?buy=<id>: open that plan's checkout */
function usePendingBuy(plans){
React.useEffect(()=>{if(!plans)return;const m=/[?&]buy=(\d+)/.exec(location.search);if(!m)return;const p=plans.find(x=>String(x.id)===m[1]);
if(!p)return;(window.SBAuth?window.SBAuth.ready:Promise.resolve()).then(()=>{if(window.SBAuth&&window.SBAuth.currentUser()){try{history.replaceState(null,'',location.pathname+location.search.replace(/([?&])buy=\d+&?/,'$1').replace(/[?&]$/,'')+location.hash);}catch(e){}pkBuy(p);}});},[plans]);
}
const PK_CSS=`
.pk-wrap{max-width:1180px;margin:0 auto;padding:0 32px}
.pk-sec{padding:56px 0}.pk-sec.alt{background:var(--gray-50,#f6f7fb)}
.pk-kick{display:inline-block;font:800 11.5px/1 var(--font-body);letter-spacing:.08em;text-transform:uppercase;color:var(--brand-accent,#e02b2b);margin:0 0 8px}
.pk-h2{font:800 32px/1.15 var(--font-display);color:var(--text-heading);margin:0 0 10px;letter-spacing:-.01em}
.pk-lede{font:400 16px/1.6 var(--font-body);color:var(--text-body);max-width:680px;margin:0 0 28px}
.pk-plans{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:18px;align-items:stretch}
.pk-plan{position:relative;display:flex;flex-direction:column;background:var(--white);border:1.5px solid var(--border-default);border-radius:22px;padding:24px;box-shadow:0 10px 30px rgba(11,16,51,.06)}
.pk-plan.hl{border-color:var(--brand-primary,#1d2fa0);box-shadow:0 22px 50px rgba(29,47,160,.18)}
.pk-pop{position:absolute;top:-12px;left:24px;background:var(--brand-accent,#e02b2b);color:#fff;font:800 11px/1 var(--font-body);letter-spacing:.06em;border-radius:999px;padding:6px 12px}
.pk-plan h3{font:800 20px/1.25 var(--font-display);color:var(--text-heading);margin:4px 0 6px}
.pk-plan .d{font:400 14px/1.55 var(--font-body);color:var(--text-body);margin:0 0 14px}
.pk-price{display:flex;align-items:baseline;gap:6px;margin:0 0 4px}.pk-price b{font:800 34px/1 var(--font-display);color:var(--text-heading)}.pk-price span{font:600 14px/1 var(--font-body);color:var(--text-muted)}
.pk-pm{font:600 12.5px/1.4 var(--font-body);color:var(--teal-700,#0b6b62);margin:0 0 14px;min-height:18px}
.pk-opts{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 16px}
.pk-opts button{border:1.5px solid var(--border-default);background:var(--white);border-radius:999px;padding:7px 12px;font:700 12.5px/1 var(--font-body);color:var(--text-body);cursor:pointer}
.pk-opts button.on{border-color:var(--brand-primary,#1d2fa0);background:var(--navy-100,#e5e9fb);color:var(--brand-primary,#1d2fa0)}
.pk-inc{list-style:none;margin:0 0 20px;padding:0;display:grid;gap:8px}.pk-inc li{display:flex;gap:8px;font:400 14px/1.45 var(--font-body);color:var(--text-body)}.pk-inc li:before{content:"✓";color:var(--teal-700,#0b6b62);font-weight:800}
.pk-buy{margin-top:auto;display:flex;justify-content:center;align-items:center;gap:8px;border:none;border-radius:999px;padding:14px 20px;font:700 15px/1 var(--font-body);cursor:pointer;background:#1d2fa0;color:#fff;box-shadow:0 10px 22px rgba(29,47,160,.28);transition:background .15s,transform .12s}
.pk-buy:hover{background:#141f6e}.pk-buy:active{transform:scale(.98)}html.sb-dark .pk-buy{background:#5570ff}
.pk-plan:not(.hl) .pk-buy{background:var(--white);color:var(--brand-primary,#1d2fa0);border:1.5px solid var(--brand-primary,#1d2fa0);box-shadow:none}
.pk-secure{font:500 12px/1.4 var(--font-body);color:var(--text-muted);text-align:center;margin:10px 0 0}
.pk-free{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:12px}
.pk-free a{display:flex;gap:12px;align-items:flex-start;padding:16px;border-radius:16px;background:var(--white);border:1px solid var(--border-default);text-decoration:none;color:var(--text-heading);transition:border-color .15s,transform .12s}
.pk-free a:hover{border-color:var(--brand-primary,#1d2fa0);transform:translateY(-2px)}
.pk-free i{flex:none;width:42px;height:42px;border-radius:13px;display:grid;place-items:center;font-style:normal;font-size:20px;background:var(--navy-100,#e5e9fb)}
.pk-free b{display:block;font:700 14.5px/1.3 var(--font-body)}.pk-free small{display:block;font:400 12.5px/1.45 var(--font-body);color:var(--text-muted);margin-top:3px}
.pk-tag{display:inline-block;margin-top:6px;font:800 10.5px/1 var(--font-body);letter-spacing:.06em;text-transform:uppercase;color:var(--teal-700,#0b6b62);background:var(--teal-50,#e6f5f3);border-radius:999px;padding:4px 8px}
.pk-steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;counter-reset:s}
.pk-steps div{background:var(--white);border:1px solid var(--border-default);border-radius:18px;padding:20px}
.pk-steps b{display:flex;align-items:center;gap:10px;font:800 16px/1.3 var(--font-display);color:var(--text-heading)}.pk-steps b:before{counter-increment:s;content:counter(s);flex:none;width:30px;height:30px;border-radius:50%;background:var(--brand-accent,#e02b2b);color:#fff;display:grid;place-items:center;font-size:14px}
.pk-steps p{font:400 14px/1.55 var(--font-body);color:var(--text-body);margin:8px 0 0}
.pk-faq{display:grid;gap:10px;max-width:860px}
.pk-faq details{background:var(--white);border:1px solid var(--border-default);border-radius:14px;padding:0 18px}
.pk-faq summary{cursor:pointer;padding:16px 0;font:700 15px/1.4 var(--font-body);color:var(--text-heading);list-style:none}.pk-faq summary::-webkit-details-marker{display:none}
.pk-faq summary:after{content:"+";float:right;color:var(--text-muted);font-size:18px}.pk-faq details[open] summary:after{content:"–"}
.pk-faq p{font:400 14.5px/1.6 var(--font-body);color:var(--text-body);margin:0 0 16px}
.pk-trial{display:flex;gap:16px;align-items:center;justify-content:space-between;flex-wrap:wrap;background:var(--navy-900,#131c66);color:#fff;border-radius:22px;padding:26px 28px}
.pk-trial h3{font:800 22px/1.25 var(--font-display);margin:0 0 6px;color:#fff}.pk-trial p{margin:0;color:rgba(255,255,255,.82);font:400 15px/1.5 var(--font-body)}
.pk-trial a{display:inline-flex;align-items:center;gap:8px;background:var(--brand-accent,#e02b2b);color:#fff;border-radius:999px;padding:14px 22px;font:800 15px/1 var(--font-body);text-decoration:none;white-space:nowrap}
#plans,#compare{scroll-margin-top:84px}
.pk-cmp{overflow-x:auto;border:1px solid var(--border-default);border-radius:18px;background:var(--white);margin-top:26px}
.pk-cmp table{width:100%;border-collapse:collapse;min-width:560px;font:400 14px/1.4 var(--font-body)}
.pk-cmp th,.pk-cmp td{padding:12px 14px;border-bottom:1px solid var(--border-default);text-align:center;vertical-align:middle}
.pk-cmp th:first-child,.pk-cmp td:first-child{text-align:left;position:sticky;left:0;background:var(--white);min-width:200px}
.pk-cmp thead th{font:800 14.5px/1.3 var(--font-display);color:var(--text-heading);background:var(--gray-50,#f6f7fb)}.pk-cmp thead th:first-child{background:var(--gray-50,#f6f7fb)}
.pk-cmp thead th small{display:block;font:800 10.5px/1 var(--font-body);letter-spacing:.06em;color:var(--brand-accent,#e02b2b);margin-top:4px}
.pk-cmp tr.g td{background:var(--gray-50,#f6f7fb);font:800 11.5px/1 var(--font-body);letter-spacing:.06em;text-transform:uppercase;color:var(--text-muted);text-align:left}
.pk-cmp .y{color:var(--teal-700,#0b6b62);font-weight:800;font-size:16px}.pk-cmp .n{color:var(--gray-400,#a0a6b8)}
.pk-cmp td b{font:800 15px/1 var(--font-display);color:var(--text-heading)}.pk-cmp td small{display:block;color:var(--text-muted);font-size:11.5px;margin-top:3px}
.pk-cmp button{border:none;border-radius:999px;padding:10px 16px;font:700 13px/1 var(--font-body);cursor:pointer;background:#1d2fa0;color:#fff}
.pk-none{background:var(--white);border:1px dashed var(--border-default);border-radius:18px;padding:22px;color:var(--text-muted);font:500 14.5px/1.5 var(--font-body)}
@media(max-width:640px){.pk-wrap{padding:0 16px}.pk-sec{padding:40px 0}.pk-h2{font-size:25px}.pk-plan{padding:20px}.pk-trial{padding:22px}.pk-trial a{width:100%;justify-content:center}}`;
function PkStyle(){return <style>{PK_CSS}</style>;}
/* jump to a section of this page (links here use <base href="/">, so a plain "#id" would leave the page) */
function pkGo(id){return e=>{e.preventDefault();const el=document.getElementById(id);if(el)el.scrollIntoView({behavior:'smooth',block:'start'});};}
/* Plans of one course side by side: what each unlocks, and every duration's price, with Buy now */
function PlanCompare({data,course}){
if(window.SB_APP||!data)return null;
const list=(data.plans||[]).filter(p=>!course||pkCourses(p,data.areas)[course]);
if(list.length<1)return null;
const areas=data.areas||[];
const label=k=>{const a=areas.find(x=>x.key===k);return a?a.label.replace(/^CUET · /,'').replace(/ \(free with login\)$/,''):k;};
const groups=(course?[course]:['cat','ipmat','cuet','varc']).concat(course?['other']:[]);
const rowsOf=g=>{if(g==='other'){const ks=new Set();list.forEach(p=>(p.areas||[]).forEach(k=>{const a=areas.find(x=>x.key===k);const c=a&&a.course||(/^cuet-subj:/.test(k)?'cuet':'');if(c&&c!==course&&!(a&&a.free))ks.add(c);}));return [...ks].map(c=>({c,label:(PK_COURSES.find(x=>x.key===c)||{}).short||(PK_COURSES.find(x=>x.key===c)||{}).label||c}));}
const fixed=areas.filter(a=>a.course===g&&!a.subject&&!a.free).map(a=>a.key);
const subs=areas.filter(a=>a.course===g&&a.subject&&list.some(p=>(p.areas||[]).indexOf(a.key)>=0)).map(a=>a.key);
return fixed.concat(subs).map(k=>({k,label:label(k)}));};
const has=(p,r)=>r.c?(p.areas||[]).some(k=>{const a=areas.find(x=>x.key===k);return (a&&a.course||(/^cuet-subj:/.test(k)?'cuet':''))===r.c;}):(p.areas||[]).indexOf(r.k)>=0;
const days=[...new Set([].concat(...list.map(p=>p.options.map(o=>o.days))))].sort((a,b)=>a-b);
const dl=d=>{const o=list.map(p=>p.options.find(x=>x.days===d)).find(Boolean);return o?o.label:d+' days';};
const G={cat:'CAT',ipmat:'IPMAT · JIPMAT · IIM B (B.Sc.)',cuet:'CUET (UG)',varc:'VARC & more',other:'Also included'};
return (<div className="pk-cmp" id="compare"><table><thead><tr><th>Compare plans</th>{list.map(p=><th key={p.id}>{p.name}{p.highlight?<small>MOST POPULAR</small>:null}</th>)}</tr></thead>
<tbody>{groups.map(g=>{const rows=rowsOf(g);const pick=(g==='cuet')&&list.some(p=>p.pick);if(!rows.length&&!pick)return null;
return <React.Fragment key={g}><tr className="g"><td colSpan={list.length+1}>{G[g]}</td></tr>
{rows.map(r=><tr key={r.k||r.c}><td>{r.label}</td>{list.map(p=><td key={p.id}>{has(p,r)?<span className="y" aria-label="included">✓</span>:<span className="n" aria-label="not included">—</span>}</td>)}</tr>)}
{pick?<tr><td>Subjects you choose</td>{list.map(p=><td key={p.id}>{p.pick?'Any '+p.pick.count:<span className="n">—</span>}</td>)}</tr>:null}
</React.Fragment>;})}
<tr className="g"><td colSpan={list.length+1}>Previous-year papers</td></tr>
<tr><td>Every PYQ paper (timed) and solution</td>{list.map(p=><td key={p.id}><span className="y">✓</span><small>free for all</small></td>)}</tr>
<tr className="g"><td colSpan={list.length+1}>Price</td></tr>
{days.map(d=><tr key={d}><td>{dl(d)}</td>{list.map(p=>{const o=p.options.find(x=>x.days===d);return <td key={p.id}>{o?<span><b>{pkInr(o.priceINR)}</b>{d>30?<small>≈ {pkInr(Math.round(o.priceINR*30/d))}/mo</small>:null}</span>:<span className="n">—</span>}</td>;})}</tr>)}
<tr><td></td>{list.map(p=><td key={p.id}><button type="button" onClick={()=>pkBuy(p)}>Buy now</button></td>)}</tr>
</tbody></table></div>);
}
/* the rights a plan unlocks, in plain words */
function pkIncludes(p,areas,subjects){
const out=(p.areas||[]).map(k=>{const a=(areas||[]).find(x=>x.key===k);return a?a.label.replace(/ \(free with login\)$/,''):k;}).filter(l=>!/PYQs/.test(l));
if(p.pick)out.push('Any '+p.pick.count+' '+({domain:'CUET domain subjects',language:'CUET language subjects',general:'General Test subjects',any:'CUET subjects'}[p.pick.group]||'subjects')+' — you choose');
out.push('Score, percentile and question-wise analysis after every test');
return out;
}
function PlanCard({p,areas}){
const [opt,setOpt]=React.useState(0);const o=p.options[opt]||p.options[0];
const pm=o&&o.days>30?'≈ '+pkInr(Math.round(o.priceINR*30/o.days))+' / month':'';
return (<div className={'pk-plan'+(p.highlight?' hl':'')}>
{p.highlight?<span className="pk-pop">MOST POPULAR</span>:null}
<h3>{p.name}</h3>{p.description?<p className="d">{p.description}</p>:null}
<div className="pk-price"><b>{pkInr(o.priceINR)}</b><span>/ {o.label}</span></div>
<div className="pk-pm">{pm}</div>
{p.options.length>1?<div className="pk-opts" role="group" aria-label="Duration">{p.options.map((x,i)=><button key={x.days} type="button" className={i===opt?'on':''} aria-pressed={i===opt} onClick={()=>setOpt(i)}>{x.label}</button>)}</div>:null}
<ul className="pk-inc">{pkIncludes(p,areas).map(t=><li key={t}>{t}</li>)}</ul>
<button className="pk-buy" type="button" onClick={()=>pkBuy(p)}>Buy now →</button>
<p className="pk-secure">🔒 Secure checkout by Razorpay · UPI, cards, netbanking</p>
</div>);
}
/* course: 'cat' | 'ipmat' | 'cuet' | 'varc' | null (all) */
function PlanCards({data,course}){
if(window.SB_APP)return <div className="pk-none">Plans can’t be bought inside the app. If you already have a plan, log in with the same email or mobile number you used for it.</div>;
if(!data)return <div className="pk-none">Loading plans…</div>;
const list=(data.plans||[]).filter(p=>!course||pkCourses(p,data.areas)[course]);
if(!list.length)return <div className="pk-none">New plans for this course are coming soon. Start with the free trial and the free resources below.</div>;
return <div className="pk-plans">{list.map(p=><PlanCard key={p.id} p={p} areas={data.areas}/>)}</div>;
}
function FreeGrid({items}){
return <div className="pk-free">{items.map(([ic,t,d,href,tag])=><a key={href+t} href={href}><i aria-hidden="true">{ic}</i><span><b>{t}</b><small>{d}</small>{tag?<span className="pk-tag">{tag}</span>:null}</span></a>)}</div>;
}
function TrialBand({days,course}){
const me=window.SBAuth&&window.SBAuth.currentUser();
if(!days)return null;
return (<div className="pk-trial"><div><h3>{days} days free — no card needed</h3><p>{'Try '+(course?course+' ':'')+'tests on the real exam screen before you pay anything. Log in with a one-time code and start in under a minute.'}</p></div>
<a href={me?'dashboard.html#practice':'login.html?next=dashboard.html'}>{me?'Go to my practice →':'Start my free trial →'}</a></div>);
}
function Steps({days}){
return (<div className="pk-steps">
<div><b>Log in in seconds</b><p>Your mobile number or email and a one-time code — no password to remember.</p></div>
<div><b>{days?'Use your '+days+'-day free trial':'Start with the free resources'}</b><p>{days?'Take real mocks and topic tests, see your score, percentile and the topics to fix.':'Every previous-year paper, daily RC reads and guides — free.'}</p></div>
<div><b>Pick a plan when you’re ready</b><p>Pay securely with Razorpay. Access starts the moment your payment is confirmed.</p></div>
</div>);
}
function Faq({items}){return <div className="pk-faq">{items.map(([q,a])=><details key={q}><summary>{q}</summary><p>{a}</p></details>)}</div>;}
const PK_FAQ_COMMON=[
['Are previous-year papers really free?','Yes. Every previous-year paper is free to take as a timed test once you log in, and every question’s answer and solution is free to read — no plan needed.'],
['Do I need a card for the free trial?','No. Log in with your mobile number or email and a one-time code; the trial starts right away.'],
['How do I pay for a plan?','Securely through Razorpay — UPI, debit and credit cards, netbanking and wallets. Your plan is active as soon as the payment is confirmed.'],
['Can I use it on my phone?','Yes — on any browser, and on the Scorebuddy Android app with the same login.'],
['What if I need help?','Message us on WhatsApp or write to info.scorebuddy@gmail.com — we reply quickly.']];
Object.assign(window,{pkGo,PlanCompare,PK_COURSES,pkInr,pkTrialDays,usePlans,usePendingBuy,PkStyle,PlanCards,FreeGrid,TrialBand,Steps,Faq,PK_FAQ_COMMON});
