(() => {
  const {useState,useEffect}=React;
  const names={fixed:'Fixed costs',investments:'Investments',savings:'Savings',guiltFree:'Guilt-free spending'};
  const money=n=>typeof n==='number'?n.toLocaleString('en-US',{style:'currency',currency:'USD'}):'Not yet available';
  const api=(method,path,body)=>window.NGM.api(method,'/rich-life'+path,body);
  function useSnapshot(){
    const [data,setData]=useState(null),[error,setError]=useState('');
    const load=async()=>{setError('');try{setData(await api('GET','/snapshot'));}catch(e){setError(e.message);}};
    useEffect(()=>{load();},[]);return {data,error,load};
  }
  function Loading({error}){return <p role={error?'alert':'status'}>{error||'Gathering your financial picture…'}</p>;}
  function Warnings({data}){return data.warnings.length?<details className="rl-note"><summary>{data.reliable?'Calculation notes':'Your estimate needs review'}</summary>{data.warnings.map(w=><p key={w}>{w}</p>)}</details>:null;}
  function Tile({label,value,children}){return <section className="rl-tile"><span className="rl-label">{label}</span><strong>{value}</strong>{children&&<p>{children}</p>}</section>;}
  const oldDashboard=window.Dashboard;
  function Today({onNavigate,onOpenBill}){
    const {data:d,error,load}=useSnapshot();
    if(!d)return <Loading error={error}/>;
    return <div className="rich-life ngm-controls"><header className="rl-header"><div><span className="rl-eyebrow">Your Rich Life</span><h1>Today</h1><p>Your priorities, your spending room, your next decision.</p></div><button onClick={load}>Refresh view</button></header>
      <section className="rl-hero"><span>{!d.plan?'Start with your spending plan':d.reliable?'Comfortable spending room':'Estimated spending room'}</span><h2>{money(d.comfortable)}</h2><p>{!d.plan?'Choose the accounts and priorities that make this number meaningful.':`Limited by your monthly allowance and the cash needed through ${d.horizon}.`}</p><button onClick={()=>onNavigate('plan')}>{d.plan?'Review spending plan':'Set up my plan'}</button>{d.shortfall>0&&<p role="alert">Your plan has a {money(d.shortfall)} shortfall to resolve.</p>}</section>
      <Warnings data={d}/><div className="rl-grid"><Tile label="Monthly allowance remaining" value={d.plan?money(d.monthlyRemaining):'Set your plan'}>After reviewed spending and unclassified expenses.</Tile><Tile label="Cash after commitments" value={d.plan?money(d.cashHeadroom):'Select cash accounts'}>Bills, buffer, and goal reservations are protected.</Tile><Tile label="Bills in the next 30 days" value={money(d.totalBills)}>{d.bills.length} open records, including overdue bills.</Tile></div>
      <div className="rl-columns"><section className="rl-panel"><h2>Coming up</h2>{d.bills.length?d.bills.slice(0,6).map(b=><button className="rl-row" key={b.instanceId||b.id} onClick={()=>onOpenBill?onOpenBill(b.id):onNavigate('bills')}><span>{b.biller}<small>{b.overdue?'Overdue · ':''}{b.dueDate}</small></span><strong>{money(b.amount)}</strong></button>):<p>No dated open bills found. Check that all your obligations are included.</p>}<button onClick={()=>onNavigate('bills')}>Review bills</button></section><section className="rl-panel"><h2>What needs your attention</h2>{!d.plan&&<p>Approve your first four-bucket plan.</p>}{d.unclassifiedCount>0&&<p>{d.unclassifiedCount} expenses need a bucket review.</p>}{d.reconciliation.legacyGoalsNeedReview&&<p>Historical goal totals need reconciliation before they can be called funded.</p>}<button onClick={()=>onNavigate('goals')}>Review goals</button> <button onClick={()=>onNavigate('aicost')}>Ask an advisor</button></section></div>
      {d.plan?.richLife&&<section className="rl-panel"><h2>What this money is for</h2><p>{d.plan.richLife}</p></section>}<details className="rl-panel"><summary>How this is calculated</summary><p>{d.explanation}</p><p>View calculated {new Date(d.asOf).toLocaleString()}. Bank data is checked daily at 9:05 a.m. Eastern; each bank has its own update schedule.</p>{d.accounts.filter(a=>a.selected).map(a=><p key={a.id}>{a.name}: {money(a.available)} · {a.balanceAsOf?new Date(a.balanceAsOf).toLocaleString():'Refresh date unavailable'}</p>)}<button onClick={()=>onNavigate('calendar')}>Cash forecast</button> <button onClick={()=>onNavigate('spend')}>Transactions</button></details>
    </div>;
  }
  function SpendingPlan(){
    const {data:d,error,load}=useSnapshot(),[draft,setDraft]=useState(null),[preview,setPreview]=useState(null),[busy,setBusy]=useState(false),[message,setMessage]=useState('');
    useEffect(()=>{if(d){const p=d.plan;setDraft({version:p?.version||0,incomeCents:Math.round((p?.income??d.suggestedIncome??0)*100),bufferCents:Math.round((p?.buffer||0)*100),percentages:p?.percentages||{fixed:60,investments:10,savings:10,guiltFree:20},accountIds:p?.accountIds||d.accounts.filter(a=>a.kind==='checking').map(a=>a.id),reservations:p?.reservations||{},categoryBuckets:p?.categoryBuckets||{},richLife:p?.richLife||''});setPreview(null);}},[d]);
    const change=patch=>{setDraft({...draft,...patch});setPreview(null);setMessage('');};
    const submit=async confirmed=>{setBusy(true);setMessage('');try{const r=await api('POST','/plan',{...draft,confirmed,approvalToken:confirmed?preview.approvalToken:undefined});if(confirmed){setMessage('Plan approved. No money was moved.');await load();}else setPreview(r);}catch(e){setMessage(e.message);setPreview(null);}finally{setBusy(false);}};
    if(!d||!draft)return <Loading error={error}/>;
    const view=preview?.preview||d;
    return <div className="rich-life ngm-controls"><header className="rl-header"><div><span className="rl-eyebrow">Make room for what matters</span><h1>Spending Plan</h1><p>Preview your changes, then approve the exact plan. These are virtual reservations; no transfers are made.</p></div></header>
      <section className="rl-panel"><label>What does a Rich Life mean to you?<textarea placeholder="More time with family, travel, peace of mind…" value={draft.richLife} onChange={e=>change({richLife:e.target.value})}/></label><div className="rl-grid"><label>Monthly take-home income ($)<input type="number" min="0" step="0.01" value={draft.incomeCents/100} onChange={e=>change({incomeCents:Math.round(Number(e.target.value)*100)})}/></label><label>Cash buffer ($)<input type="number" min="0" step="0.01" value={draft.bufferCents/100} onChange={e=>change({bufferCents:Math.round(Number(e.target.value)*100)})}/></label></div><p>Use take-home income after payroll deductions. Expected income guides the monthly plan; it does not increase bank cash.</p></section>
      <section className="rl-panel"><h2>Your four buckets</h2><div className="rl-grid rl-four">{Object.keys(names).map(k=><label key={k}>{names[k]} (%)<input type="number" min="0" max="100" value={draft.percentages[k]} onChange={e=>change({percentages:{...draft.percentages,[k]:Number(e.target.value)}})}/><small>{money(draft.incomeCents/100*draft.percentages[k]/100)} planned monthly</small></label>)}</div><p>Total: {Object.values(draft.percentages).reduce((s,n)=>s+n,0)}%. The example split is a starting point; choose what fits your household.</p></section>
      <section className="rl-panel"><h2>Cash included in this plan</h2><p>Leave emergency and protected savings accounts unchecked unless their money is explicitly reserved below.</p>{d.accounts.map(a=><label className="rl-check" key={a.id}><input type="checkbox" checked={draft.accountIds.includes(a.id)} onChange={e=>change({accountIds:e.target.checked?[...draft.accountIds,a.id]:draft.accountIds.filter(id=>id!==a.id)})}/>{a.name} · {money(a.available)}<small>{a.kind}</small></label>)}</section>
      <section className="rl-panel"><h2>Protect money for goals</h2><p>Reserve cash already in the selected accounts. Moving it to another account is a separate action.</p>{d.goals.map(g=><label className="rl-row" key={g.id}><span>{g.name}</span><input aria-label={`${g.name} reservation`} type="number" min="0" step="0.01" value={(draft.reservations[g.id]||0)/100} onChange={e=>change({reservations:{...draft.reservations,[g.id]:Math.round(Number(e.target.value)*100)}})}/></label>)}</section>
      <details className="rl-panel"><summary>Assign spending categories to buckets</summary><p>Unmapped expenses reduce the provisional guilt-free allowance until reviewed.</p>{d.categories.map(c=><label className="rl-row" key={c.id}>{c.name}<select value={draft.categoryBuckets[c.id]||''} onChange={e=>{const map={...draft.categoryBuckets};if(e.target.value)map[c.id]=e.target.value;else delete map[c.id];change({categoryBuckets:map});}}><option value="">Needs review</option>{Object.entries(names).map(([k,v])=><option key={k} value={k}>{v}</option>)}</select></label>)}</details>
      <button disabled={busy} onClick={()=>submit(false)}>Preview this plan</button>{preview&&<section className="rl-panel" aria-live="polite"><h2>Review before approving</h2><div className="rl-grid"><Tile label="Estimated spending room" value={money(view.comfortable)}/><Tile label="Monthly allowance remaining" value={money(view.monthlyRemaining)}/><Tile label="Cash headroom" value={money(view.cashHeadroom)}/></div><Warnings data={view}/>{view.shortfall>0&&<p role="alert">This plan has a {money(view.shortfall)} shortfall. Reservations are not fully backed.</p>}<button disabled={busy} onClick={()=>submit(true)}>Approve this plan</button><p>Approval updates your plan and reservations only. No bill payment, investment, or bank transfer is authorized.</p></section>}<p role="status">{busy?'Working…':message}</p>
    </div>;
  }
  function NewGoal({onSaved}){
    const [name,setName]=useState(''),[target,setTarget]=useState(''),[message,setMessage]=useState(''),[busy,setBusy]=useState(false);
    const create=async()=>{setBusy(true);try{if(!name.trim()||!(Number(target)>0))throw new Error('Enter a name and a positive target.');await window.NGM.api('POST','/goals',{name:name.trim(),targetCents:Math.round(Number(target)*100),currentCents:0,monthlyTargetCents:0,fundedThisMonthCents:0});setName('');setTarget('');setMessage('Goal created. No money reserved or transferred.');await onSaved();}catch(e){setMessage(e.message);}finally{setBusy(false);}};
    return <details className="rl-panel"><summary>Add a goal</summary><label>Goal name<input value={name} onChange={e=>setName(e.target.value)}/></label><label>Target ($)<input type="number" min="0.01" step="0.01" value={target} onChange={e=>setTarget(e.target.value)}/></label><button disabled={busy} onClick={create}>Create goal</button><p role="status">{message}</p></details>;
  }
  function Goals(){
    const {data:d,error,load}=useSnapshot();const [extra,setExtra]=useState({});
    if(!d)return <Loading error={error}/>;
    return <div className="rich-life ngm-controls"><h1>Goals</h1><NewGoal onSaved={load}/><p>See the difference between a target, reserved cash, and a completed transfer.</p><Warnings data={d}/><div className="rl-grid">{d.goals.map(g=>{const contribution=Number(extra[g.id]??g.monthlyTarget??0),remaining=Math.max(0,g.target-g.reserved);return <section className="rl-panel" key={g.id}><h2>{g.name}</h2><p>Target: <strong>{money(g.target)}</strong></p><p>Approved reservation: <strong>{money(g.reserved)}</strong></p><p>{g.backingStatus==='cash_available'?'Selected accounts currently cover the household reservations.':'Cash backing needs review.'}</p><p>Confirmed transfers: not yet reconciled.</p><label>Explore a monthly contribution ($)<input type="number" min="0" step="0.01" value={contribution} onChange={e=>setExtra({...extra,[g.id]:e.target.value})}/></label><p>{remaining===0?'Your reservation meets this target.':contribution>0?`About ${Math.ceil(remaining/contribution)} months to reserve the remaining target, assuming consistent contributions.`:'Enter a contribution to explore a target date.'}</p><small>Scenario only. Approve reservation changes in Spending Plan.</small>{g.legacyRecorded!==0&&<details><summary>Historical record needs review</summary><p>{money(g.legacyRecorded)} was previously recorded. It is not counted as bank-verified savings.</p></details>}</section>;})}</div>{!d.goals.length&&<p>No goals recorded yet.</p>}</div>;
  }
  window.Dashboard=props=>window.NGM?.live()?<Today {...props}/>:React.createElement(oldDashboard,props);
  window.SpendingPlanPage=SpendingPlan;
  window.GoalsPage=Goals;
  window.RichLifeDocumentReview=function({id,onDone}){
    const [doc,setDoc]=useState(null),[fields,setFields]=useState({}),[busy,setBusy]=useState(false),[error,setError]=useState('');
    const load=async()=>{try{const r=await api('GET',`/documents/${id}`);setDoc(r);setFields({biller:r.fields.biller||r.suggestedFields.biller||'',amount:r.fields.amount??r.suggestedFields.amount??'',dueDate:r.fields.dueDate||r.suggestedFields.dueDate||'',referenceNumber:r.fields.referenceNumber||r.suggestedFields.referenceNumber||''});}catch(e){setError(e.message);}};
    useEffect(()=>{load();},[id]);
    const extract=async()=>{setBusy(true);setError('');try{await api('POST',`/documents/${id}/extract`,{});await load();}catch(e){setError(e.message);}finally{setBusy(false);}};
    const approve=async()=>{setBusy(true);setError('');try{await api('POST',`/documents/${id}/review`,{confirmed:true,reviewVersion:doc.reviewVersion,fields:{...fields,amountCents:fields.amount===''?null:Math.round(Number(fields.amount)*100)}});await load();onDone?.();}catch(e){setError(e.message);}finally{setBusy(false);}};
    const createBill=async()=>{setBusy(true);setError('');try{await api('POST',`/documents/${id}/bill`,{confirmed:true,reviewVersion:doc.reviewVersion});await load();setError('Bill added for payment review. No payment was made.');}catch(e){setError(e.message);}finally{setBusy(false);}};
    if(!doc)return <Loading error={error}/>;
    return <section className="rich-life ngm-controls rl-panel"><h2>Review document details</h2><p>{doc.extractionStatus==='processing'?'Reading this document. Check progress in a moment.':doc.extractionStatus==='complete'?'Suggested details are ready to check against the original.':'Extract details automatically or enter them below.'}</p><button disabled={busy||doc.extractionStatus==='complete'} onClick={extract}>{doc.extractionStatus==='processing'?'Check extraction progress':'Extract details'}</button>{doc.extractionError&&<p role="alert">{doc.extractionError}</p>}<div className="rl-grid"><label>Biller<input value={fields.biller} onChange={e=>setFields({...fields,biller:e.target.value})}/></label><label>Amount ($)<input type="number" min="0" step="0.01" value={fields.amount} onChange={e=>setFields({...fields,amount:e.target.value})}/></label><label>Due date<input type="date" value={fields.dueDate} onChange={e=>setFields({...fields,dueDate:e.target.value})}/></label><label>Reference<input value={fields.referenceNumber} onChange={e=>setFields({...fields,referenceNumber:e.target.value})}/></label></div><button disabled={busy} onClick={approve}>Confirm document details</button> {!doc.needsReview&&!doc.linkedBillId&&<button disabled={busy} onClick={createBill}>Add reviewed details as a bill</button>}{doc.linkedBillId&&<p>This document is linked to a bill.</p>}<p>{doc.reviewedAt?`Reviewed ${new Date(doc.reviewedAt).toLocaleString()}. `:''}This does not create or pay a bill.</p><details><summary>Extracted text and page references</summary>{doc.pages.length?doc.pages.map(p=><section key={p.page}><h3>Page {p.page}</h3><p style={{whiteSpace:'pre-wrap'}}>{p.text}</p></section>):<p style={{whiteSpace:'pre-wrap'}}>{doc.text||'No text extracted yet.'}</p>}</details><p role="status">{busy?'Working…':error}</p></section>;
  };
})();
