import React, {createContext, useContext, useEffect, useRef, useState, lazy, Suspense} from 'react';
import {createRoot} from 'react-dom/client';
import {ArrowRight, Download, LockKeyhole, ShieldCheck} from 'lucide-react';
import Home from './home';
import {Header, Footer, BookSummary} from './shared';
import './styles.css';

type Session = {csrf:string;user:{id:string;email:string;role:string}|null;order:any;entitled:boolean;unlocked:boolean;checkout:{ready:boolean;mode:string;publicKey:string};supportEmail:string};
const SessionContext = createContext<{data:Session|null;reload:()=>Promise<void>;api:(path:string,body?:any)=>Promise<any>}>({data:null,reload:async()=>{},api:async()=>{}});
const useSession = () => useContext(SessionContext);
const NmiPayments = lazy(()=>import('@nmipayments/nmi-pay-react').then(m=>({default:m.NmiPayments})));
function Provider({children}:{children:React.ReactNode}) {
  const [data,setData]=useState<Session|null>(null),[failure,setFailure]=useState('');
  async function reload(){const r=await fetch('/api/session',{cache:'no-store'});const next=await r.json();if(!r.ok)throw new Error(next.error||'Unable to connect.');setData(next);setFailure('');}
  useEffect(()=>{reload().catch(e=>setFailure(e.message));},[]);
  async function api(path:string,body:any={}){const r=await fetch(path,{method:'POST',headers:{'Content-Type':'application/json','X-CSRF-Token':data?.csrf||''},body:JSON.stringify(body)});const result=await r.json();if(!r.ok)throw new Error(result.error||'Unable to complete the request.');return result;}
  return <SessionContext.Provider value={{data,reload,api}}>{failure&&<div className="connection-error" role="alert">{failure} <button onClick={()=>reload().catch(e=>setFailure(e.message))}>Retry connection</button></div>}{children}</SessionContext.Provider>;
}
function Page({title,eyebrow='CASINO GAMES HANDBOOK',children}:{title:string;eyebrow?:string;children:React.ReactNode}){return <><Header/><main id="main" className="section-wrap app-page"><p className="eyebrow">{eyebrow}</p><h1>{title}</h1>{children}</main><Footer/></>;}
function Notice({children,error=false}:{children:React.ReactNode;error?:boolean}){return children?<div className={`notice${error?' error':''}`} role={error?'alert':'status'}>{children}</div>:null;}
function Support(){const {data}=useSession();return data?.supportEmail?<a className="text-link" href={`mailto:${data.supportEmail}`}>Contact support</a>:<p className="fine-print">Account recovery is handled by the store owner. Use the contact information from your purchase correspondence.</p>;}
function AccountLinks(){const {data,api}=useSession();return data?.user?<div className="account-bar"><span>Signed in as {data.user.email}</span><div>{data.user.role==='admin'&&<a href="/admin">Store management</a>}<button className="text-button" onClick={async()=>{await api('/api/logout');location.assign('/login');}}>Sign out</button></div></div>:null;}
function SignInPrompt(){return <div className="panel"><LockKeyhole className="panel-icon" size={28}/><h2>Your reader account</h2><p>Use your email and a unique password to keep your purchase and downloads together.</p><div className="member-actions"><a className="button gold" href="/register">Create an account <ArrowRight size={18}/></a><a className="button outline" href="/login">Sign in</a></div></div>;}
function AccountForm({register=false}:{register?:boolean}){
  const {data,api}=useSession();const[message,setMessage]=useState(''),[busy,setBusy]=useState(false);
  async function submit(e:React.FormEvent<HTMLFormElement>){e.preventDefault();const fields=Object.fromEntries(new FormData(e.currentTarget));if(register&&fields.password!==fields.confirm){setMessage('Passwords do not match.');return;}setBusy(true);setMessage('');try{await api(register?'/api/register':'/api/login',{...fields,accepted:fields.accepted==='on'});location.assign(register?'/checkout':'/members');}catch(e){setMessage((e as Error).message);}finally{setBusy(false);}}
  return <Page title={register?'Create your reader account.':'Welcome back.'}><div className="narrow-panel panel">{data?.user?<><h2>You’re already signed in.</h2><AccountLinks/><a className="button gold" href="/members">Open members area</a></>:<><h2>{register?'Your ebook starts here':'Sign in to your members area'}</h2><p>{register?'One account. One digital handbook. Choose a password you can use to confirm your protected downloads.':'Enter the email and password you used when purchasing.'}</p><Notice error>{message}</Notice><form onSubmit={submit}><label className="form-field">Email address<input name="email" type="email" autoComplete="email" required maxLength={254}/></label><label className="form-field">Password<input name="password" type="password" autoComplete={register?'new-password':'current-password'} required minLength={register?12:1} maxLength={128}/>{register&&<small>Use 12 to 128 characters and a unique password.</small>}</label>{register&&<><label className="form-field">Confirm password<input name="confirm" type="password" autoComplete="new-password" required minLength={12} maxLength={128}/></label><label className="form-check"><input type="checkbox" name="accepted" required/><span>I agree to the <a href="/terms">purchase terms</a> and <a href="/privacy">privacy information</a>.</span></label></>}<button className="button gold" disabled={busy||!data}>{busy?'Please wait…':register?'Create account':'Sign in'} <ArrowRight size={18}/></button></form><p className="switch-account">{register?<>Already a member? <a href="/login">Sign in</a></>:<>New here? <a href="/register">Create an account</a></>}</p>{!register&&<details className="help-details"><summary>Forgot your password?</summary><p>Contact the store for a secure, one-use reset link. Password recovery emails are not sent automatically.</p><Support/></details>}</>}</div></Page>;
}
function Checkout(){
  const {data,api}=useSession();const[step,setStep]=useState(1),[details,setDetails]=useState<any>(null),[message,setMessage]=useState(''),[busy,setBusy]=useState(false);const requestKey=useRef(''),inflight=useRef(false);
  function next(e:React.FormEvent<HTMLFormElement>){e.preventDefault();setDetails({...Object.fromEntries(new FormData(e.currentTarget)),accepted:true});requestKey.current=crypto.randomUUID();setMessage('');setStep(2);}
  async function pay(event:{token:string}):Promise<true|string>{if(inflight.current)return 'A payment is already processing.';inflight.current=true;setBusy(true);setMessage('');try{const result=await api('/api/checkout',{...details,paymentToken:event.token,requestKey:requestKey.current});if(['approved','test_approved','review','processing'].includes(result.status)){setDetails(null);location.assign('/members');return true;}requestKey.current=crypto.randomUUID();throw new Error('Your payment was not approved. No ebook access was granted. Please check your card details or use another card.');}catch(e){const message=(e as Error).message;setMessage(message);return message;}finally{inflight.current=false;setBusy(false);}}
  const active=data?.order&&['approved','processing','review'].includes(data.order.status);
  return <Page title="Make the handbook yours." eyebrow="SECURE CHECKOUT"><AccountLinks/><div className="checkout-grid"><div>{!data?<div className="panel"><p>Loading your account…</p></div>:!data.user?<SignInPrompt/>:active?<div className="panel"><h2>{data.entitled?'Your handbook is already yours.':'Your order is being verified.'}</h2><p>{data.entitled?'Open your members area to download the ebook.':'Please do not pay again while your order is processing or under review.'}</p><a className="button gold" href="/members">Open members area</a></div>:<div className="panel"><h2>{step===1?'Your billing details':'Secure payment'}</h2><p>{step===1?'Your purchase will be linked to your signed-in account.':'Enter your card in the secure NMI fields below. The total is $39.95 USD.'}</p>{!data.checkout.ready&&<Notice>Checkout is not available yet. You can <a href="/assets/Casino-Games-Sample.pdf">read the free sample</a> while purchasing is being prepared.</Notice>}{data.checkout.ready&&data.checkout.mode==='sandbox'&&<Notice>Sandbox checkout: use NMI test cards only. Test approvals do not unlock the complete ebook.</Notice>}<Notice error>{message}</Notice>{step===1?<form onSubmit={next}><fieldset disabled={!data.checkout.ready} className="plain-fieldset"><div className="form-grid"><Field name="firstName" label="First name" autoComplete="billing given-name"/><Field name="lastName" label="Last name" autoComplete="billing family-name"/></div><label className="form-field">Account email<input value={data.user.email} type="email" readOnly/></label><Field name="address" label="Billing street address" autoComplete="billing street-address"/><div className="form-grid"><Field name="city" label="City" autoComplete="billing address-level2"/><Field name="region" label="State or region" autoComplete="billing address-level1"/></div><div className="form-grid"><Field name="zip" label="ZIP or postal code" autoComplete="billing postal-code"/><label className="form-field">Country<select name="country" autoComplete="billing country" defaultValue="US">{[['US','United States'],['CA','Canada'],['GB','United Kingdom'],['AU','Australia'],['NZ','New Zealand'],['IE','Ireland']].map(([v,l])=><option key={v} value={v}>{l}</option>)}</select></label></div><label className="form-check"><input name="accepted" type="checkbox" required/><span>I understand this is a digital PDF and agree to the <a href="/terms" target="_blank" rel="noopener">purchase terms</a> and <a href="/privacy" target="_blank" rel="noopener">privacy information</a>.</span></label><button className="button gold">Continue to payment <ArrowRight size={18}/></button></fieldset></form>:<><div className="payment-box"><Suspense fallback={<p>Loading secure payment fields…</p>}><NmiPayments tokenizationKey={data.checkout.publicKey} paymentMethods={['card']} layout="multiLine" payButtonText="Pay $39.95 USD" onPay={pay}/></Suspense></div><button className="text-button" disabled={busy} onClick={()=>{setStep(1);setDetails(null);}}>Edit billing details</button></>}<p className="fine-print payment-note"><ShieldCheck size={15}/>NMI collects card details. Access unlocks after payment approval.</p></div>}</div><BookSummary/></div></Page>;
}
function Field({name,label,autoComplete}:{name:string;label:string;autoComplete?:string}){return <label className="form-field">{label}<input name={name} autoComplete={autoComplete} required maxLength={150}/></label>;}
function PasswordChange(){const{api}=useSession();const[message,setMessage]=useState(''),[busy,setBusy]=useState(false);async function submit(e:React.FormEvent<HTMLFormElement>){e.preventDefault();const fields=Object.fromEntries(new FormData(e.currentTarget));if(fields.password!==fields.confirm){setMessage('New passwords do not match.');return;}setBusy(true);try{await api('/api/password',fields);location.reload();}catch(e){setMessage((e as Error).message);setBusy(false);}}return <details className="help-details"><summary>Change your account password</summary><Notice error>{message}</Notice><form onSubmit={submit}><label className="form-field">Current password<input name="currentPassword" type="password" autoComplete="current-password" required maxLength={128}/></label><label className="form-field">New password<input name="password" type="password" autoComplete="new-password" minLength={12} maxLength={128} required/></label><label className="form-field">Confirm new password<input name="confirm" type="password" autoComplete="new-password" minLength={12} maxLength={128} required/></label><button className="button outline" disabled={busy}>Save new password</button><p className="fine-print">Changing your password signs out your other sessions and locks existing downloads.</p></form></details>;}
function Members(){
  const {data,api,reload}=useSession();const[message,setMessage]=useState(''),[busy,setBusy]=useState(false);
  async function unlock(e:React.FormEvent<HTMLFormElement>){e.preventDefault();setBusy(true);setMessage('');const form=e.currentTarget;try{await api('/api/unlock',Object.fromEntries(new FormData(form)));form.reset();await reload();}catch(e){setMessage((e as Error).message);}finally{setBusy(false);}}
  async function download(){setBusy(true);setMessage('');try{const r=await fetch('/api/download');if(!r.ok){const e=await r.json();throw new Error(e.error);}const b=await r.blob();const u=URL.createObjectURL(b),a=document.createElement('a');a.href=u;a.download='Casino-Games-Handbook.pdf';a.click();setTimeout(()=>URL.revokeObjectURL(u),60000);}catch(e){setMessage((e as Error).message);await reload();}finally{setBusy(false);}}
  const statuses:any={processing:'Your payment is processing or awaiting verification. Please do not pay again.',review:'Your payment needs verification by the store. Please do not pay again.',declined:'Your last payment was declined. You can return to checkout to try another card.',test_approved:'Your NMI sandbox test was approved. Test orders do not unlock the full ebook.',revoked:'Download access for this order has been removed. Contact the store if you need help.'};
  return <Page title="Your next chapter is here." eyebrow="MEMBERS AREA"><AccountLinks/>{!data?<div className="panel">Loading your account…</div>:!data.user?<SignInPrompt/>:<div className="checkout-grid"><div><div className="panel"><LockKeyhole size={28} className="panel-icon"/><h2>{data.entitled?'Casino Games Handbook':'Your protected library'}</h2><Notice error>{message}</Notice>{data.order&&<p className="fine-print order-reference">Order reference: {data.order.id}</p>}{!data.entitled?<><Notice>{statuses[data.order?.status]||'Complete an approved purchase to add the ebook to your account.'}</Notice>{!['processing','review'].includes(data.order?.status)&&<a className="button gold" href="/checkout">Go to checkout <ArrowRight size={18}/></a>}<div className="support-line"><Support/></div></>:data.unlocked?<><p>Your purchase is unlocked for 15 minutes. Download and save your complete PDF for offline reading.</p><div className="member-actions"><button className="button gold" onClick={download} disabled={busy}><Download size={18}/>{busy?'Preparing…':'Download the ebook'}</button><button className="text-button" onClick={async()=>{await api('/api/lock');await reload();}}>Lock downloads</button></div></>:<><p>Your payment is approved. Confirm your account password to unlock the download.</p><form onSubmit={unlock}><label className="form-field">Account password<input name="password" type="password" autoComplete="current-password" required maxLength={128}/></label><button className="button gold" disabled={busy}><LockKeyhole size={18}/>Unlock my ebook</button></form></>}</div><div className="panel"><PasswordChange/></div></div><BookSummary/></div>}</Page>;
}
function Reset(){const {data,api}=useSession();const[raw]=useState(()=>location.hash.slice(1));const[message,setMessage]=useState(''),[busy,setBusy]=useState(false),[done,setDone]=useState(false);useEffect(()=>{history.replaceState(null,'','/reset');},[]);async function submit(e:React.FormEvent<HTMLFormElement>){e.preventDefault();const fields=Object.fromEntries(new FormData(e.currentTarget));if(fields.password!==fields.confirm){setMessage('Passwords do not match.');return;}setBusy(true);try{await api('/api/recover',{token:raw,password:fields.password});setDone(true);}catch(e){setMessage((e as Error).message);}finally{setBusy(false);}}return <Page title="A fresh start."><div className="narrow-panel panel"><h2>Reset your account password</h2>{done?<><p>Your password has been updated. Sign in again to access your purchase.</p><a className="button gold" href="/login">Sign in</a></>:!raw?<><p>Open the complete reset link supplied by the store. Reset links expire after one hour.</p><Support/></>:<><Notice error>{message}</Notice><form onSubmit={submit}><label className="form-field">New password<input type="password" name="password" minLength={12} maxLength={128} autoComplete="new-password" required/></label><label className="form-field">Confirm password<input type="password" name="confirm" minLength={12} maxLength={128} autoComplete="new-password" required/></label><button className="button gold" disabled={!data||busy}>Reset password</button></form></>}</div></Page>;}
function Admin(){
  const {data,api}=useSession();const[orders,setOrders]=useState<any[]>([]),[gateway,setGateway]=useState<any>(null),[before,setBefore]=useState<number|null>(null),[message,setMessage]=useState(''),[busy,setBusy]=useState('');
  async function load(older=false){const r=await fetch('/api/admin/orders'+(older&&before?`?before=${before}`:''));const d=await r.json();if(!r.ok)throw new Error(d.error);setOrders(older?[...orders,...d.orders]:d.orders);setGateway(d.gateway);setBefore(d.nextBefore);}
  useEffect(()=>{if(data?.user?.role==='admin')load().catch(e=>setMessage(e.message));},[data?.user?.id]);
  async function verify(e:React.FormEvent<HTMLFormElement>,orderId:string){e.preventDefault();setBusy(orderId);setMessage('');try{const fields=Object.fromEntries(new FormData(e.currentTarget));await api('/api/admin/verify',{orderId,...fields});await load();}catch(e){setMessage((e as Error).message);}finally{setBusy('');}}
  async function revoke(id:string){if(!confirm('Remove future ebook download access? This does not issue a financial refund.'))return;setBusy(id);try{await api('/api/admin/revoke',{orderId:id});await load();}catch(e){setMessage((e as Error).message);}finally{setBusy('');}}
  return <Page title="Store management." eyebrow="OWNER ACCESS"><AccountLinks/>{!data?<p>Loading…</p>:data.user?.role!=='admin'?<div className="panel"><h2>Administrator sign-in required</h2><p>Use the administrator account created during server setup.</p><a className="button gold" href="/login">Sign in</a></div>:<><Notice error>{message}</Notice><div className="panel"><h2>NMI connection</h2>{gateway&&<p>Payments: <strong>{gateway.enabled?'enabled':'disabled'}</strong> · Mode: <strong>{gateway.mode}</strong> · Private key: {gateway.hasPrivateKey?'configured':'missing'} · Tokenization key: {gateway.hasPublicKey?'configured':'missing'}</p>}<p>Set merchant keys securely in the server’s .env file and restart the service. Start with sandbox keys and NMI_MODE=sandbox. Test approvals do not release the full ebook. Use the included installation guide before switching to live payments.</p><p>For an uncertain payment, find its order reference in the NMI merchant portal, enter that transaction ID below, and verify it. Refunded or voided transactions can be reverified to remove access. Financial refunds are performed in NMI.</p></div><div className="orders-heading"><h2>Orders</h2><button className="button outline" onClick={()=>load().catch(e=>setMessage(e.message))}>Refresh</button></div>{orders.length===0?<div className="panel"><p>No orders yet.</p></div>:orders.map(order=><article className="panel admin-order" key={order.id}><div className="order-title"><strong>{order.email}</strong><span className="status-pill">{order.status.replaceAll('_',' ')}</span></div><p className="order-reference">{order.id}</p><p>${(order.amount_cents/100).toFixed(2)} {order.currency} · {order.gateway_mode} · {new Date(order.created_at).toLocaleString()}</p><form className="verify-form" onSubmit={e=>verify(e,order.id)}><label className="form-field">NMI transaction ID<input name="transactionId" defaultValue={order.transaction_id||''} maxLength={128} required/></label><button className="button outline" disabled={!!busy}>{busy===order.id?'Working…':'Verify with NMI'}</button></form>{order.status==='approved'&&<button className="text-button" disabled={!!busy} onClick={()=>revoke(order.id)}>Revoke future downloads</button>}</article>)}{before&&<button className="button outline" onClick={()=>load(true).catch(e=>setMessage(e.message))}>Load older orders</button>}</>}</Page>;
}
function Legal({privacy=false}:{privacy?:boolean}){return <Page title={privacy?'Your privacy.':'Purchase & use.'}><div className="legal-copy panel">{privacy?<><h2>Information used by this store</h2><p>The store saves your account email, a salted password hash, order reference, NMI transaction ID, payment status, amount, and purchase dates. It uses essential cookies for sign-in, request security, and time-limited download access. IP addresses are used temporarily for rate limiting.</p><h2>Payments and card details</h2><p>Card details are entered in NMI’s secure payment component. This server receives a payment token and forwards it with your billing details to NMI. It does not store card numbers or security codes. NMI and the merchant’s payment providers process payment information.</p><h2>Downloads and your choices</h2><p>Your account and payment status control ebook access. You can sign out, change your password, and contact the store about your account or privacy requests. Essential session cookies expire within 12 hours; unlocked download access lasts 15 minutes. No marketing emails, advertising trackers, or analytics are configured in this package.</p><h2>Contact</h2><Support/></>:<><h2>Your digital purchase</h2><p>Casino Games Handbook is a 68-page PDF ebook. The limited-time price is $39.95 USD, reduced from $49.95. For a limited time, save $10. This is a one-time purchase, with no subscription and no physical shipment.</p><h2>Payment and delivery</h2><p>NMI processes payment. Access is granted only after an approved payment has been verified by the server. Sign in using the email and password you created, then confirm your password in the members area to download the ebook. Save the PDF for offline use. Declined, pending, review, and sandbox test orders do not grant full ebook access.</p><h2>Personal use</h2><p>Your purchase is for personal reading. Do not resell the PDF, share your account credentials, or distribute the ebook without permission from the rights holder.</p><h2>Educational content</h2><p>The handbook explains casino rules and common betting systems. Game rules and payouts vary by venue and jurisdiction. No profit or winning outcome is promised. Betting systems cannot remove a fixed house edge.</p><h2>Purchase questions</h2><p>Contact the store about billing, access, or refund requests. Nothing on this page limits rights that apply to your purchase under applicable law.</p><Support/></>}</div></Page>;}
class ErrorBoundary extends React.Component<{children:React.ReactNode},{failed:boolean}>{state={failed:false};static getDerivedStateFromError(){return{failed:true};}render(){return this.state.failed?<Page title="Please try again."><div className="panel"><p>This page could not finish loading. Reload the page, or contact the store if the problem continues.</p><button className="button gold" onClick={()=>location.reload()}>Reload</button></div></Page>:this.props.children;}}
const routes:Record<string,React.ReactNode>={'/':<Home/>,'/checkout':<Checkout/>,'/members':<Members/>,'/login':<AccountForm/>,'/register':<AccountForm register/>,'/reset':<Reset/>,'/admin':<Admin/>,'/terms':<Legal/>,'/privacy':<Legal privacy/>};
createRoot(document.getElementById('root')!).render(<ErrorBoundary><Provider>{routes[location.pathname]||<Page title="Page not found."><a href="/">Return to the handbook</a></Page>}</Provider></ErrorBoundary>);
