// Demo mode: banner, guided tour, journey map, auto-play
const ROLE_KEYS = [['manager','Mark · Manager','Mark'],['finance','Laura · Finance','Laura'],['admin','Emily · Admin','Emily'],['client:c1','Rachel · Client','Rachel']];

const TOURS = {
  client: [
    { view:'home', target:'client-stats', title:'Your status at a glance', body:'Open orders, containers in motion and open invoices. This is the page clients used to call about.' },
    { view:'home', target:'client-orders', title:'Every order, one row', body:'Status, requested date, linked container and payment state. Amounts shown are what you pay; SofloLG margin is never exposed.' },
    { view:'home', target:'client-containers', title:'Where your container is', body:'ETA and the date of the last update. Click one to read the shipping notes as they were posted.' },
    { view:'home', target:'client-inbox', title:'Updates come to you', body:'Status changes and container notes land in the inbox, so there is nothing to chase by phone.' },
  ],
  manager: [
    { view:'home', target:'needs-action', title:'Nothing gets forgotten', body:'Confirmed orders not yet purchased, stale or late containers, and overdue orders stay here until handled.' },
    { view:'live', target:'live-map', title:'Live map', body:'Every container on its real route, day by day. Press play to run the season; click a ship to trace its orders.' },
    { view:'home', target:'new-order', title:'Create an order', body:'Client, supplier, line items with supplier cost and selling price. Margin is calculated as you type.' },
    { view:'order', params:{ id:'SO-1068' }, target:'split-card', title:'The split is locked on confirm', body:'Client total, supplier amount and margin are frozen when the order is confirmed. Mark paid files the split for Finance.' },
    { view:'container', params:{ id:'MSKU4471023' }, target:'post-update', title:'Post container updates', body:'Change status and add a note. Linked orders and the client portal update instantly; risk flags clear.' },
    { view:'analytics', target:'an-stats', title:'Analytics', body:'Margin by month, pipeline by stage, container on-time rate and delays.' },
  ],
  finance: [
    { view:'billing', target:'bill-stats', title:'Nothing slips', body:'Outstanding, overdue, collected and owed to suppliers — every invoice and payment in one ledger.' },
    { view:'billing', target:'aging', title:'Aging buckets', body:'Open balances by how late they are. Click a bucket to list those invoices.' },
    { view:'billing', target:'inv-table', title:'Invoice → payments', body:'Open an invoice to record full or partial payments with method and reference. Paying in full files the supplier payable automatically.' },
    { view:'finance', target:'fin-stats', title:'Money in, money out', body:'What is owed to suppliers from paid orders, margin retained, and what clients still owe.' },
    { view:'finance', target:'export-csv', title:'Pay-supplier list in one click', body:'CSV of every paid order with supplier amount and margin, totalled per supplier.' },
    { view:'finance', target:'fin-table', title:'Full split history', body:'Every locked split is retained, including overrides by an admin.' },
  ],
  admin: [
    { view:'analytics', target:'an-margin', title:'Business view', body:'Admin sees everything a manager sees, plus the controls below.' },
    { view:'team', target:'invite', title:'Team & roles', body:'Invite teammates, change roles, deactivate accounts. Clients get portal access from the directory.' },
    { view:'order', params:{ id:'SO-1058' }, target:'admin-controls', title:'Override with a paper trail', body:'Edit a locked split, cancel or delete an order. Each action requires a reason and is written to the audit log.' },
    { view:'audit', target:'audit-table', title:'Audit log', body:'Every status change, payment, note, override and team change — who, when, what.' },
    { view:'settings', target:'settings-stale', title:'Tune the risk rules', body:'How many days without an update before a container is flagged. Changes apply to the dashboard immediately.' },
  ],
};

const JOURNEYS = [
  { role:'client:c1', label:'Client', who:'Rachel, Marlin Bay Builders', tint:'sky', steps:[['Sign in','Email + password, read-only', 'home'],['See all orders','Status, container, payment','home'],['Open an order','Items, amounts, timeline','order',{ id:'SO-1058' }],['Track the container','ETA, notes as posted','container',{ id:'TGHU8820916' }],['Check invoices','Balance, due dates, payments','invoices'],['Read updates','Inbox replaces phone calls','inbox']] },
  { role:'manager', label:'Manager', who:'Mark, operations', tint:'mint', steps:[['Check needs action','Unpurchased, stale, overdue','home'],['Watch the live map','Ships, statuses, payments','live'],['Create order','Cost vs price, margin live','order-new'],['Confirm → split locked','Client / supplier / margin','order',{ id:'SO-1068' }],['Mark paid by client','Split filed for Finance','order',{ id:'SO-1059' }],['Update container','Status + note, risk clears','container',{ id:'MSKU4471023' }]] },
  { role:'finance', label:'Finance', who:'Laura, accounts', tint:'yellow', steps:[['Review billing','Outstanding, overdue, aging','billing'],['Record a payment','Full or partial, with reference','billing'],['Pay suppliers','Payables from paid invoices','billing',{ tab:'ap' }],['Client balances','Who owes what, how late','billing',{ tab:'stmt' }],['Review splits','Paid vs awaiting','finance'],['Export supplier payments','CSV per supplier','finance'],['Margin by client','Who earns what','finance']] },
  { role:'admin', label:'Admin', who:'Emily, owner', tint:'lavender', steps:[['Analytics','Margin trend, on-time rate','analytics'],['Manage team','Invite, roles, deactivate','team'],['Clients & suppliers','Portal logins','directory'],['Override a split','Reason required, audited','order',{ id:'SO-1058' }],['Audit log','Full trail','audit'],['Settings & export','Thresholds, full data','settings']] },
];

const Spotlight = ({ target, children, bottom }) => {
  const [r, setR] = useState(null);
  useEffect(() => { let scrolled = false; const m = () => { const el = target && document.querySelector(`[data-tour="${target}"]`); if (el) { const b = el.getBoundingClientRect(); if (!scrolled && (b.top < 70 || b.bottom > innerHeight - 160)) { window.scrollTo(0, Math.max(0, window.scrollY + b.top - 130)); scrolled = true; return; } setR({ x: b.left - 8, y: b.top - 8, w: b.width + 16, h: Math.min(b.height, innerHeight - 220) + 16 }); } else setR(null); }; m(); const id = setInterval(m, 250); return () => clearInterval(id); }, [target]);
  const below = r && r.y + r.h + 240 < innerHeight;
  return <>
    <div className="spot" style={r ? { left: r.x, top: r.y, width: r.w, height: r.h } : { left: '50%', top: '50%', width: 0, height: 0 }}></div>
    {bottom ? <div className="tour-tip tour-bottom">{children}</div> : <div className="tour-tip" style={r ? { left: Math.min(Math.max(16, r.x), innerWidth - 376), top: below ? r.y + r.h + 12 : Math.max(16, r.y - 12), transform: below ? 'none' : 'translateY(-100%)' } : { left: '50%', top: '50%', transform: 'translate(-50%,-50%)' }}>{children}</div>}
  </>;
};

const Tour = ({ role, go, onClose }) => {
  const key = role.startsWith('client') ? 'client' : role; const steps = TOURS[key]; const [i, setI] = useState(0); const s = steps[i];
  useEffect(() => { go(role, s.view, s.params || {}); }, [i]);
  return <Spotlight target={s.target}>
    <span className="kicker">{t('Guided tour')} · {i + 1}/{steps.length}</span><h4>{s.title}</h4><p>{s.body}</p>
    <div className="tour-a"><Btn sm onClick={onClose}>{t('Exit demo') === 'Exit demo' ? 'Close' : 'Cerrar'}</Btn><span className="grow"></span>{i > 0 && <Btn sm onClick={() => setI(i - 1)}>Back</Btn>}{i < steps.length - 1 ? <Btn sm v="primary" onClick={() => setI(i + 1)}>Next</Btn> : <Btn sm v="primary" onClick={onClose}>Done</Btn>}</div>
  </Spotlight>;
};

const JourneyMap = ({ go, startTour }) => <div className="page">
  <PageHead title="Journey map" kicker="Demo mode"><span className="mute small">Each card opens the live screen as that user.</span></PageHead>
  <div className="jm">{JOURNEYS.map(j => <section key={j.role} className={`jm-col tint-${j.tint}`}>
    <header><span className="kicker">{j.label}</span><h4>{j.who}</h4><Btn sm v="dark" onClick={() => startTour(j.role)}>{t('Guided tour')}</Btn></header>
    <ol>{j.steps.map(([ti, d, v, p], k) => <li key={k} onClick={() => go(j.role, v, p || {})}><span className="jm-n">{k + 1}</span><span className="jm-t"><b>{ti}</b><span>{d}</span></span>{I.right}</li>)}</ol>
  </section>)}</div>
</div>;

const buildScript = () => [
  { role:'manager', view:'home', target:'needs-action', cap:'Mark opens the dashboard. "Needs action" lists confirmed orders not yet purchased and containers that are stale or late.' },
  { role:'manager', view:'live', target:'live-map', cap:'The live map: every container on its real route, statuses and payments landing day by day. Click any ship to trace its orders.' },
  { role:'manager', cap:'He creates a new order for Marlin Bay: 900 m² of porcelain tile at $10.50 supplier cost, $16.00 selling price.', run:(c) => { c.mem.oid = c.act.saveOrder({ clientId:'c1', supplierId:'s1', priority:'Normal', requestedDate:new Date(TODAY.getTime() + 86400000 * 40).toISOString().slice(0, 10), containerId:null, items:[{ desc:'Porcelain tile 60×60 polished white', qty:900, unit:'m²', cost:10.5, price:16 }] }, false); c.go('manager', 'order', { id:c.mem.oid }); }, target:'split-card' },
  { role:'manager', cap:'Confirming locks the split: client pays $14,400 → $9,450 to Foshan Tile Works, $4,950 margin. Mandatory fields were validated first.', run:(c) => c.act.setStatus(c.mem.oid, 'Confirmed'), target:'split-card' },
  { role:'manager', cap:'The client pays. One click records it against the invoice and files the split for Finance.', run:(c) => c.act.markPaid(c.mem.oid), target:'split-card' },
  { role:'finance', view:'billing', target:'bill-stats', cap:'Laura opens Billing: outstanding, overdue with the oldest invoice age, collected in 30 days, and what is owed to suppliers. No invoice or payment can go missing.' },
  { role:'finance', view:'billing', target:'aging', cap:'Aging shows who is how late. A partial payment on SO-1059 stays open until the balance is cleared.' },
  { role:'finance', view:'finance', target:'export-csv', cap:'Laura in Finance sees what is owed to each supplier from paid orders and exports the supplier payment list as CSV.' },
  { role:'manager', view:'container', params:{ id:'TGHU8820916' }, target:'post-update', cap:'A container hits a customs hold at Port Everglades. Mark posts the status and a note.', run:(c) => setTimeout(() => c.act.updateContainer('TGHU8820916', 'Customs Hold', 'CBP exam requested at Port Everglades. Broker expects 5–7 days.'), 1500) },
  { role:'client:c1', view:'inbox', target:'client-inbox-list', cap:'Rachel at Marlin Bay sees the same note in her inbox a second later — no phone call needed.' },
  { role:'client:c1', view:'order', params:{ id:'SO-1058' }, target:'client-payment', cap:'Her order page shows status, items, what she owes and the container. Margin is never shown to clients.' },
  { role:'admin', view:'order', params:{ id:'SO-1058' }, target:'admin-controls', cap:'Emily (Admin) corrects a locked split: the supplier invoice came in at $5,700 instead of $6,015. A reason is required.', run:(c) => setTimeout(() => c.act.editSplit('SO-1058', 5700, 'Supplier invoice lower than quoted'), 1500) },
  { role:'admin', view:'audit', target:'audit-table', cap:'The override is in the audit log with the previous value, the new value and the reason — alongside every status change and payment.' },
  { role:'admin', view:'team', target:'team-table', cap:'She invites a new Finance teammate. Roles decide what each person can see and do.', run:(c) => setTimeout(() => c.act.inviteUser({ name:'Sophie Lane', email:'sophie@soflolg.com', role:'finance' }), 1200) },
  { role:'admin', view:'analytics', target:'an-margin', cap:'Analytics: margin by month and pipeline value by stage over the last 90 days.' },
  { role:'admin', view:'analytics', target:'an-delays', cap:'Container on-time rate and the worst delays — the calls that used to come in, visible before the phone rings.' },
  { role:'manager', view:'home', target:'needs-action', cap:'That is the loop: order → locked split → payment → container → client, with every change audited. Demo complete.' },
];

const AutoPlay = ({ go, act, speed, setSpeed, onClose }) => {
  const script = useMemo(buildScript, []); const [i, setI] = useState(0); const [playing, setPlaying] = useState(true); const ctx = useRef({ mem: {} });
  ctx.current.go = go; ctx.current.act = act;
  useEffect(() => { const s = script[i]; const c = ctx.current; if (s.view) go(s.role, s.view, s.params || {}); else if (!s.run) go(s.role, 'home'); if (s.run) setTimeout(() => s.run(c), s.view ? 600 : 300); }, [i]);
  useEffect(() => { if (!playing) return; const id = setTimeout(() => { if (i < script.length - 1) setI(i + 1); else setPlaying(false); }, speed * 1000); return () => clearTimeout(id); }, [i, playing, speed]);
  const s = script[i];
  return <Spotlight target={s.target} bottom>
    <div className="ap-top"><span className="kicker">{t('Auto-play')} · {i + 1}/{script.length}</span><div className="ap-prog"><i style={{ width: ((i + 1) / script.length * 100) + '%' }}></i></div></div>
    <p className="ap-cap">{s.cap}</p>
    <div className="tour-a"><Btn sm v="dark" icon={playing ? I.pause : I.play} onClick={() => setPlaying(!playing)}>{playing ? 'Pause' : 'Play'}</Btn><Btn sm disabled={i === 0} onClick={() => { setI(i - 1); }}>Back</Btn><Btn sm disabled={i >= script.length - 1} onClick={() => setI(i + 1)}>Next</Btn><label className="ap-speed"><span className="mute">{speed}s</span><input type="range" min="2" max="8" value={speed} onChange={e => setSpeed(+e.target.value)}></input></label><span className="grow"></span><Btn sm onClick={onClose}>Stop</Btn></div>
  </Spotlight>;
};

const DemoBanner = ({ roleKey, go, onTour, onMap, onPlay, onExit, lang, setLang }) => <div className="demo-bar">
  <span className="demo-tag">{I.sparkle}{t('Demo mode')}</span>
  <div className="demo-roles">{ROLE_KEYS.map(([k, l, s]) => <button key={k} className={roleKey === k ? 'on' : ''} onClick={() => go(k, 'home')}><span className="lg">{l}</span><span className="sm">{s}</span></button>)}</div>
  <div className="demo-acts"><Btn sm v="on-dark" icon={I.map} onClick={onMap}>Journey map</Btn><Btn sm v="on-dark" onClick={onTour}>Guided tour</Btn><Btn sm v="primary" icon={I.play} onClick={onPlay}>Auto-play</Btn>
    <div className="seg seg-dark">{['en','es'].map(l => <button key={l} className={lang === l ? 'on' : ''} onClick={() => setLang(l)}>{l.toUpperCase()}</button>)}</div>
    <button className="demo-x" onClick={onExit} title={t('Exit demo')}>{I.x}</button></div>
</div>;

Object.assign(window, { Tour, JourneyMap, AutoPlay, DemoBanner, ROLE_KEYS, JOURNEYS });
