/* global React, DATA, Panel, mdToHtml, splitCharts, ChartFromSpec, fmtEUR, fmtN, fmtPct, fmtSignPct */
const BigDelta = ({ label, value, pct, sub, neg }) => {
const color = (neg || String(value).startsWith('-')) ? 'var(--neg)' : 'var(--ink)';
return React.createElement('div', { className: 'kpi' },
React.createElement('div', { className: 'kpi-label' }, label),
React.createElement('div', { className: 'kpi-value', style: { color } }, value),
React.createElement('div', { className: 'kpi-sub' },
pct != null ? React.createElement('span', { className: 'mono ' + (pct >= 0 ? 'text-pos' : 'text-neg') }, fmtSignPct(pct)) : null,
sub ? React.createElement('span', null, sub) : null));
};
const Scenario = () => {
const [q, setQ] = useState('');
const [reply, setReply] = useState('');
const [result, setResult] = useState(null);
const [loading, setLoading] = useState(false);
const [err, setErr] = useState(null);
const examples = [
'What happens to Q3 revenue on LCA-ATH if we drop one daily frequency and Aegean adds two?',
'Simulate a 7% fare cut across the Greece market for the next 60 days.',
'If we add one daily LCA-TLV for the summer, what is the revenue and load-factor impact?',
'A competitor adds two daily frequencies on LCA-DXB this quarter, what do we lose?',
];
const run = async (text) => {
if (!text.trim() || loading) return;
setLoading(true); setErr(null); setReply(''); setResult(null);
try {
const base = (window.API_BASE_URL || '');
const res = await fetch(base + '/api/scenario', { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ messages: [{ role: 'user', content: text }] }) });
if (!res.ok) throw new Error('HTTP ' + res.status);
const data = await res.json();
setReply(data.reply || ''); setResult(data.result || null);
} catch (e) { setErr(e.message); } finally { setLoading(false); }
};
const { text, charts } = splitCharts(reply || '');
const d = result && result.delta, b = result && result.baseline, s = result && result.scenario;
// KPI strip
const kpiStrip = (result && !result.error) ? React.createElement('div', { className: 'grid grid-4 gap-2', style: { marginBottom: 18 } },
React.createElement(BigDelta, { label: 'Δ Revenue', value: fmtEUR(d.revenue_eur), pct: d.revenue_pct, sub: result.scope_label }),
React.createElement(BigDelta, { label: 'Δ Passengers', value: fmtN(d.pax), sub: result.horizon.days + ' days' }),
React.createElement(BigDelta, { label: 'Δ Load factor', value: fmtSignPct(d.load_factor_pts) + ' pts', sub: (b ? fmtPct(b.load_factor) : '') + ' to ' + (s ? fmtPct(s.load_factor) : '') }),
React.createElement(BigDelta, { label: 'Spilled pax', value: fmtN(s ? s.spilled_pax : 0), sub: 'beyond capacity', neg: true })) : null;
// by-O&D table
const odTable = (result && result.by_od && result.by_od.length) ? React.createElement(Panel, { title: 'Impact by O&D', sub: 'Δ revenue (€)', flush: true },
React.createElement('div', { style: { maxHeight: 460, overflowY: 'auto' } },
React.createElement('table', { className: 'tbl tbl-zebra' },
React.createElement('thead', null, React.createElement('tr', null,
['O&D', 'Δ Rev', 'Δ Pax', 'LF'].map((h, i) => React.createElement('th', { key: i, className: i ? 'num' : '' }, h)))),
React.createElement('tbody', null,
result.by_od.map((r, i) => React.createElement('tr', { key: i },
React.createElement('td', { style: { fontWeight: 600 } }, r.od),
React.createElement('td', { className: 'num mono ' + (r.d_revenue >= 0 ? 'text-pos' : 'text-neg') }, fmtEUR(r.d_revenue)),
React.createElement('td', { className: 'num mono' }, fmtN(r.d_pax)),
React.createElement('td', { className: 'num mono text-muted' }, r.base_lf + ' to ' + r.scn_lf)))))) ) : null;
const readout = React.createElement(Panel, { title: 'Analyst read-out', sub: 'Anthropic Claude over the OR simulator' },
React.createElement('div', { className: 'article-col', style: { maxWidth: 'none', fontSize: 18.5, lineHeight: 1.6 }, dangerouslySetInnerHTML: { __html: mdToHtml(text) } }),
charts.map((c, i) => React.createElement(ChartFromSpec, { key: i, spec: c })));
let body;
if (loading) body = React.createElement('div', { style: { padding: 28, color: 'var(--text-muted)', fontStyle: 'italic', textAlign: 'center' } }, '· · · parsing the question and running the network simulation');
else if (err) body = React.createElement('div', { className: 'text-neg', style: { padding: 16 } }, 'Scenario failed: ' + err);
else if (result || reply) body = React.createElement('div', { style: { marginTop: 20 } }, kpiStrip,
React.createElement('div', { className: 'grid gap-3', style: { gridTemplateColumns: odTable ? '1.4fr 1fr' : '1fr' } }, readout, odTable));
else body = React.createElement('div', { style: { padding: 40, textAlign: 'center', color: 'var(--text-faint)', fontFamily: 'var(--serif)', fontSize: 17, fontStyle: 'italic' } },
'Type a what-if above, or pick an example, to run a quantified scenario.');
return React.createElement('div', { className: 'page' },
React.createElement('div', { className: 'page-head' },
React.createElement('div', { className: 'eyebrow', style: { marginBottom: 8 } }, 'Scenario Simulation · C3'),
React.createElement('h1', { className: 'headline', style: { fontSize: 46 } }, 'Ask a ', React.createElement('em', null, 'what-if'), ' in plain English.'),
React.createElement('div', { className: 'subhead' }, 'The copilot translates your question into simulation parameters; a deterministic network model (capacity, spill-recapture, price elasticity, competitor share) returns the quantified answer in seconds.')),
React.createElement(Panel, null,
React.createElement('div', { className: 'row gap-2', style: { marginBottom: 10 } },
React.createElement('input', { className: 'input', style: { flex: 1, height: 38, fontSize: 13.5 }, placeholder: 'e.g. What happens to Q3 revenue on LCA-ATH if we drop one daily and Aegean adds two?',
value: q, onChange: e => setQ(e.target.value), onKeyDown: e => e.key === 'Enter' && run(q), disabled: loading }),
React.createElement('button', { className: 'btn btn-accent', style: { height: 38 }, onClick: () => run(q), disabled: loading }, loading ? 'Simulating…' : 'Run scenario')),
React.createElement('div', { className: 'filterbar' },
examples.map((x, i) => React.createElement('button', { key: i, className: 'filter-chip', onClick: () => { setQ(x); run(x); } }, x.length > 52 ? x.slice(0, 50) + '…' : x)))),
body);
};
window.Scenario = Scenario;