/* ============================================================
   NeuroRoute — Portal core: Dashboard, Usage, Billing, Provider Keys
   All data fetched from live APIs — no demo data.
   ============================================================ */
const D = window.DATA;

/* ---- human-readable model name (handles "auto" / "none" / unknown ids) ---- */
function modelName(id){
  if(!id || id==='none') return 'Unresolved';
  if(id==='auto') return 'Auto-routed (cached)';
  const m=D.modelById(id); return m ? m.name : id;
}

/* ---- model name + provider cell ---- */
function ModelCell({id}){
  if(!id || id==='none') return <span style={{color:'var(--tx-3)',fontStyle:'italic'}}>Unresolved</span>;
  if(id==='auto') return <span style={{color:'var(--tx-2)'}}>Auto-routed (cached)</span>;
  const m=D.modelById(id); if(!m) return <span>{id}</span>;
  return <span className="row" style={{gap:9}}><ProviderLogo id={m.provider} size={26}/><span style={{fontWeight:600,color:'var(--tx-0)'}}>{m.name}</span></span>;
}

/* =====================  DASHBOARD  ===================== */
function DashboardPage(){
  const [loading, setLoading] = React.useState(true);
  const [ov, setOv] = React.useState(null);
  const [timeline, setTimeline] = React.useState([]);
  const [decisions, setDecisions] = React.useState([]);
  const [modelStats, setModelStats] = React.useState([]);
  const [healthData, setHealthData] = React.useState({});
  const [ent, setEnt] = React.useState(null);

  React.useEffect(()=>{
    Promise.all([
      NR_API.dashboardOverview(),
      NR_API.dashboardUsage(30),
      NR_API.dashboardRouting(8),
      NR_API.dashboardModels(),
      NR_API.health(),
      NR_API.entitlements(),
    ]).then(([o,u,r,m,h,e])=>{
      setOv(o);
      setTimeline(u && u.timeline ? u.timeline : []);
      setDecisions(r && r.decisions ? r.decisions : []);
      setModelStats(m && m.models ? m.models : []);
      setHealthData(h || {});
      setEnt(e || null);
      setLoading(false);
    }).catch(()=>setLoading(false));
  },[]);

  if(loading) return <LoadingPage/>;

  const hasData = ov && ov.total_requests > 0;

  /* Derive chart data */
  const savingsPct = ov && ov.total_spend > 0 ? Math.round((ov.total_saved / (ov.total_saved + ov.total_spend)) * 100) : 0;
  const baseline = ov ? ov.total_saved + ov.total_spend : 0;
  const labels = timeline.map(d=>{ const dt=new Date(d.date); return (dt.getMonth()+1)+'/'+dt.getDate(); });
  const actuals = timeline.map(d=>d.cost);
  const baselines = timeline.map(d=>gpt4oBaseline(d.input_tokens, d.output_tokens));
  const sparkSav = timeline.slice(-14).map((d,i)=>{ const idx=timeline.length-14+i; return (baselines[idx]||0) - d.cost; });

  /* Model distribution from real stats */
  const totalModelReqs = modelStats.reduce((s,m)=>s+m.request_count, 0);
  const dist = modelStats.slice(0,10).map(m=>({
    label: modelName(m.model),
    value: totalModelReqs>0 ? Math.round(m.request_count/totalModelReqs*100) : 0,
    model: m.model, reqs: m.request_count,
  }));

  return (
    <div className="grid" style={{gap:18}}>
      <PageHead desc="Live overview of your routing, savings, and provider health.">
        <button className="btn btn-primary btn-sm" onClick={()=>go('playground')}><Icon name="playground" size={15}/>Open Playground</button>
      </PageHead>

      {!hasData ? <>
        <EmptyState icon="dashboard" title="Welcome to NeuroRoute"
          desc="Your intelligent routing dashboard will show savings and performance data once you start sending requests through the API."
          actions={[
            {label:'Create API Key', onClick:()=>go('apikeys')},
            {label:'Open Playground', onClick:()=>go('playground'), primary:true},
          ]}/>
        <HealthSidebar healthData={healthData}/>
      </> : <>
        {/* savings hero banner */}
        <div className="card" style={{position:'relative',overflow:'hidden',padding:'26px 28px'}}>
          <div style={{position:'absolute',inset:0,background:'radial-gradient(120% 160% at 0% 0%, rgba(16,185,129,.16), transparent 50%), radial-gradient(120% 160% at 100% 0%, rgba(226,79,214,.12), transparent 55%)'}}/>
          <div className="spread" style={{position:'relative',flexWrap:'wrap',gap:20}}>
            <div>
              <div className="eyebrow" style={{marginBottom:8}}>SAVINGS THIS MONTH</div>
              <div className="row" style={{gap:14,alignItems:'baseline'}}>
                <span className="display" style={{fontSize:46,lineHeight:1}}>{fmtUSD(ov.total_saved,2)}</span>
                {savingsPct>0 && <Badge color="green" dot>{savingsPct}% saved</Badge>}
              </div>
              <div className="faint" style={{marginTop:8,fontSize:13.5}}>vs {fmtUSD(baseline,2)} Claude Fable 5 baseline · {fmtNum(ov.total_requests)} requests</div>
            </div>
            <div style={{display:'flex',flexDirection:'column',alignItems:'flex-end',gap:8}}>
              {ent && ent.tier && (function(){
                var t = ent.tier;
                var col = t==='enterprise'?'purple':t==='premium'?'blue':t==='standard'?'cyan':'gray';
                return <div className="row" style={{gap:6,marginBottom:4}}>
                  <span className="faint" style={{fontSize:11.5}}>Your plan</span>
                  <Badge color={col} style={{textTransform:'capitalize'}}>{t}</Badge>
                  {t!=='enterprise' && <button className="btn btn-ghost btn-sm" style={{fontSize:11,padding:'2px 8px'}} onClick={()=>go('billing')}>Upgrade</button>}
                </div>;
              })()}
              {timeline.length>=14 && <div style={{textAlign:'right'}}>
                <Spark data={sparkSav} color={COL.green} w={220} h={56}/>
                <div className="faint mono" style={{fontSize:11,marginTop:4}}>last 14 days</div>
              </div>}
            </div>
          </div>
        </div>

        {/* metric cards */}
        <div className="metric-grid">
          <Metric icon="dollar"    color="green"   value={fmtUSD(ov.total_saved,2)} label="Total saved"/>
          <Metric icon="zap"       color="blue"    value={fmtNum(ov.total_requests)} label="Requests served"/>
          <Metric icon="billing"   color="magenta" value={fmtUSD(ov.total_spend,2)}  label="Actual spend"/>
          <Metric icon="estimator" color="cyan"    value={'$'+(ov.avg_cost_per_request||0).toFixed(4)} label="Avg cost / request"/>
        </div>

        {/* charts row */}
        {timeline.length>0 && <div className="grid" style={{gridTemplateColumns:'1.7fr 1fr'}}>
          <SectionCard title="Cost: NeuroRoute vs Claude Fable 5 baseline" sub="Daily spend over the last 30 days"
            action={<div className="row" style={{gap:14,fontSize:12}}>
              <span className="row" style={{gap:6}}><span style={{width:18,height:2,background:COL.blue,display:'inline-block'}}/>NeuroRoute</span>
              <span className="row" style={{gap:6}}><span style={{width:18,height:0,borderTop:'2px dashed '+COL.red,display:'inline-block'}}/>Claude Fable 5</span>
            </div>}>
            <LineDual labels={labels} a={actuals} b={baselines} height={268}/>
          </SectionCard>
          {dist.length>0 && <SectionCard title="Model distribution" sub="Share of traffic by model">
            <Donut items={dist} centerLabel={dist.length} centerSub="models" height={210}/>
            <div className="grid" style={{gap:7,marginTop:12}}>
              {dist.slice(0,5).map((d,i)=>{
                const c=[COL.cyan,COL.blue,COL.magenta,COL.green,COL.purple][i];
                return <div key={d.model||i} className="spread" style={{fontSize:12.5}}>
                  <span className="row" style={{gap:8}}><span style={{width:9,height:9,borderRadius:3,background:c}}/>{d.label}</span>
                  <span className="mono faint">{d.value}%</span></div>;
              })}
            </div>
          </SectionCard>}
        </div>}

        {/* recent decisions + health */}
        <div className="grid" style={{gridTemplateColumns:'1.7fr 1fr'}}>
          <SectionCard title="Recent routing decisions" pad={false}
            action={<button className="btn btn-soft btn-sm" onClick={()=>go('explorer')}>Open explorer<Icon name="arrowright" size={14}/></button>}>
            {decisions.length===0 ?
              <div style={{padding:40,textAlign:'center'}} className="faint">No routing decisions yet.</div> :
              <div className="scroll-x">
                <table className="table">
                  <thead><tr><th>Time</th><th>Model</th><th>Task</th><th style={{textAlign:'right'}}>Cost</th><th style={{textAlign:'right'}}>Saved</th><th style={{textAlign:'right'}}>Latency</th><th>Strategy</th></tr></thead>
                  <tbody>
                    {decisions.map(r=>{
                      const saved = gpt4oBaseline(r.input_tokens, r.output_tokens) - r.provider_cost;
                      const task = D.TASKS.find(t=>t.id===r.task_type) || {label:r.task_type||'general', color:'gray'};
                      return (
                        <tr key={r.request_id}>
                          <td className="faint" style={{whiteSpace:'nowrap'}}>{timeAgo(r.created_at)}</td>
                          <td><ModelCell id={r.model}/></td>
                          <td><TaskBadge task={task}/></td>
                          <td className="num" style={{textAlign:'right'}}>${r.provider_cost.toFixed(4)}</td>
                          <td className="num" style={{textAlign:'right',color:saved>0?'var(--green)':'var(--tx-2)'}}>{saved>0?'+':''}${saved.toFixed(4)}</td>
                          <td className="num" style={{textAlign:'right'}}>{r.routing_latency_ms}ms</td>
                          <td><Badge color="gray">{r.routing_strategy}</Badge></td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            }
          </SectionCard>
          <HealthSidebar healthData={healthData}/>
        </div>
      </>}
    </div>
  );
}

/* =====================  USAGE ANALYTICS  ===================== */
function costTierFor(modelId){
  var m = D.modelById(modelId);
  // 'unknown' (not 'free') when we have no pricing for this model. A missing
  // price is not a zero price: labelling an unpriced model "Free" put a green
  // badge next to its real, non-zero cost in the very same table row.
  if(!m || m.unknown || m.hasPricing === false) return 'unknown';
  var maxRate = Math.max(m.in||0, m.out||0) / 1000;
  if(maxRate === 0)    return 'free';
  if(maxRate < 0.005)  return 'near-zero';
  if(maxRate < 0.025)  return 'standard';
  return 'premium';
}
var COST_TIER_COLOR = {free:'green', 'near-zero':'cyan', standard:'blue', premium:'magenta', unknown:'gray'};

function UsagePage(){
  const [loading, setLoading] = React.useState(true);
  const [timeline, setTimeline] = React.useState([]);
  const [modelStats, setModelStats] = React.useState([]);
  const [compression, setCompression] = React.useState(null);
  const [range, setRange] = React.useState('30d');
  const [tab, setTab] = React.useState('overview');

  React.useEffect(()=>{
    const days = range==='7d'?7 : range==='15d'?15 : range==='90d'?90 : 30;
    setLoading(true);
    Promise.all([
      NR_API.dashboardUsage(days),
      NR_API.dashboardModels(),
      NR_API.dashboardCompression(),
    ]).then(([u,m,c])=>{
      setTimeline(u && u.timeline ? u.timeline : []);
      setModelStats(m && m.models ? m.models : []);
      setCompression(c || null);
      setLoading(false);
    }).catch(()=>setLoading(false));
  },[range]);

  if(loading) return <LoadingPage/>;

  /* Compute totals from timeline */
  const totals = timeline.reduce((a,d)=>({
    requests: a.requests+d.requests,
    inTok: a.inTok+d.input_tokens,
    outTok: a.outTok+d.output_tokens,
    cost: a.cost+d.cost,
  }),{requests:0, inTok:0, outTok:0, cost:0});
  const avgLat = modelStats.length>0 ? Math.round(modelStats.reduce((s,m)=>s+m.avg_latency_ms,0)/modelStats.length) : 0;

  const labels = timeline.map(d=>{ const dt=new Date(d.date); return (dt.getMonth()+1)+'/'+dt.getDate(); });
  const palette = [COL.cyan,COL.blue,COL.magenta,COL.green,COL.amber];

  /* Model distribution for stacked chart */
  const totalModelReqs = modelStats.reduce((s,m)=>s+m.request_count,0);
  const topModels = modelStats.slice(0,5);
  const series = topModels.map((ms,i)=>{
    const share = totalModelReqs>0 ? ms.request_count/totalModelReqs : 0;
    return {
      label: modelName(ms.model), color: palette[i],
      data: timeline.map(day=>Math.round((day.input_tokens+day.output_tokens)*share)),
    };
  });

  const UAW = window.UsageAnalyticsWidget;

  return (
    <div className="grid" style={{gap:18}}>
      <PageHead desc="Token consumption, model distribution, and full 12-month history with drill-down.">
        <div className="seg">
          <button className={tab==='overview'?'active':''} onClick={()=>setTab('overview')}>Overview</button>
          <button className={tab==='history'?'active':''} onClick={()=>setTab('history')}>History</button>
        </div>
      </PageHead>

      {tab==='history' ? (
        UAW ? <UAW apiCall={function(params){ return NR_API.usageTimeseries(params); }} title="Usage History" groupOptions={['model','total']}/> : <EmptyState icon="analytics" title="History unavailable" desc="Usage history widget could not be loaded."/>
      ) : (
        <>
          <div className="seg" style={{justifyContent:'flex-end'}}>{['7d','15d','30d','90d'].map(r=><button key={r} className={range===r?'active':''} onClick={()=>setRange(r)}>{'Last '+r}</button>)}</div>
          {totals.requests===0 ?
            <EmptyState icon="analytics" title="No usage data yet" desc="Send requests through the NeuroRoute API to see token consumption and model usage trends here."/> :
          <>
            <div className="metric-grid">
              <Metric icon="zap"       color="blue"    value={fmtNum(totals.requests)} label="Total requests"/>
              <Metric icon="arrowdown" color="cyan"    value={fmtTok(totals.inTok)}    label="Input tokens"/>
              <Metric icon="arrowup"   color="magenta" value={fmtTok(totals.outTok)}   label="Output tokens"/>
              <Metric icon="clock"     color="amber"   value={avgLat+'ms'}             label="Avg latency"/>
            </div>

            {compression && compression.raw_input_tokens > 0 && <SectionCard title="Context compression" sub={"Input shrunk before the model — "+fmtNum(compression.compressed_requests)+" requests compressed (30d)"}>
              <div className="grid" style={{gridTemplateColumns:'repeat(auto-fit, minmax(160px, 1fr))', gap:14}}>
                <div style={{padding:'12px 14px',background:'var(--bg-inset)',borderRadius:12}}>
                  <div className="faint" style={{fontSize:11.5}}>Raw input tokens</div>
                  <div className="mono" style={{fontSize:20,marginTop:2}}>{fmtTok(compression.raw_input_tokens)}</div>
                </div>
                <div style={{padding:'12px 14px',background:'var(--bg-inset)',borderRadius:12}}>
                  <div className="faint" style={{fontSize:11.5}}>Compressed input tokens</div>
                  <div className="mono" style={{fontSize:20,marginTop:2,color:'var(--cyan)'}}>{fmtTok(compression.compressed_input_tokens)}</div>
                </div>
                <div style={{padding:'12px 14px',background:'var(--bg-inset)',borderRadius:12}}>
                  <div className="faint" style={{fontSize:11.5}}>Compression</div>
                  <div className="display route-text" style={{fontSize:24,marginTop:2}}>{(compression.compression_pct||0).toFixed(1)}%</div>
                </div>
                <div style={{padding:'12px 14px',background:'var(--green-t)',borderRadius:12,border:'1px solid rgba(16,185,129,.3)'}}>
                  <div className="faint" style={{fontSize:11.5}}>Approx. money saved</div>
                  <div className="display route-text" style={{fontSize:24,marginTop:2}}>{fmtUSD(compression.money_saved_usd||0,4)}</div>
                  <div className="faint" style={{fontSize:10.5,marginTop:2}}>{fmtTok(compression.saved_input_tokens)} input tokens avoided</div>
                </div>
              </div>
              <div className="faint" style={{fontSize:11.5,marginTop:12}}>Estimated (≈4 chars/token). Compression is lossless in default mode; aggressive mode is test-only.</div>
            </SectionCard>}
            {modelStats.length>0 && (function(){
              // 'unknown' is a real bucket, not a dropped one: excluding it would
              // silently rebase the percentages onto a subset of traffic and show a
              // distribution that sums to 100% while omitting requests.
              var tiers = {free:0, 'near-zero':0, standard:0, premium:0, unknown:0};
              modelStats.forEach(function(ms){ var ct=costTierFor(ms.model); if(tiers[ct]!==undefined) tiers[ct]+=ms.request_count; });
              var total = Object.values(tiers).reduce(function(a,b){return a+b;},0);
              var rows = Object.entries(tiers).filter(function(e){return e[1]>0;}).map(function(e){return {tier:e[0], pct:total>0?Math.round(e[1]/total*100):0};});
              return rows.length>0 && <SectionCard title="Provider cost-tier distribution" sub="Share of traffic by model cost tier — free = $0/tok, near-zero < $0.005/1K, standard < $0.025/1K, premium ≥ $0.025/1K">
                <div className="row" style={{gap:14,flexWrap:'wrap'}}>
                  {rows.map(function(r){return (
                    <div key={r.tier} style={{flex:'1 0 120px',padding:'12px 14px',background:'var(--bg-inset)',borderRadius:12,textAlign:'center'}}>
                      <div className="faint" style={{fontSize:11,marginBottom:4,textTransform:'capitalize'}}>{r.tier}</div>
                      <div className="display" style={{fontSize:28,color:'var(--'+COST_TIER_COLOR[r.tier]+')'}}>{r.pct}%</div>
                      <div className="faint" style={{fontSize:10.5,marginTop:2}}>of traffic</div>
                    </div>
                  );})}
                </div>
              </SectionCard>;
            })()}
            <div className="grid" style={{gridTemplateColumns:'1.6fr 1fr'}}>
              {series.length>0 && <SectionCard title="Daily token usage by model" sub="Input + output tokens, stacked">
                <BarStacked labels={labels} series={series} height={280}/>
              </SectionCard>}
              <SectionCard title="Requests per day" sub="Volume trend">
                <BarSimple labels={labels} data={timeline.map(d=>d.requests)} color={COL.blue} height={280} fmt={fmtTok}/>
              </SectionCard>
            </div>
            {modelStats.length>0 && <SectionCard title="Top models by usage" sub="Ranked by request count" pad={false}>
              <div className="scroll-x">
                <table className="table">
                  <thead><tr><th>Model</th><th>Provider</th><th style={{textAlign:'right'}}>Requests</th><th style={{textAlign:'right'}}>Avg Latency</th><th style={{textAlign:'right'}}>Total Cost</th><th>% of traffic</th><th>Cost tier</th></tr></thead>
                  <tbody>
                    {modelStats.map((ms,i)=>{
                      const m=D.modelById(ms.model); const c=palette[i%palette.length];
                      const pct = totalModelReqs>0 ? Math.round(ms.request_count/totalModelReqs*100) : 0;
                      return (
                        <tr key={ms.model}>
                          <td><ModelCell id={ms.model}/></td>
                          <td className="faint">{D.providerById(m.provider).name}</td>
                          <td className="num" style={{textAlign:'right'}}>{fmtNum(ms.request_count)}</td>
                          <td className="num" style={{textAlign:'right'}}>{ms.avg_latency_ms}ms</td>
                          <td className="num" style={{textAlign:'right'}}>{fmtUSD(ms.total_cost,2)}</td>
                          <td><span className="row" style={{gap:10}}><MiniBar pct={pct} color={c}/><span className="mono faint" style={{fontSize:12}}>{pct}%</span></span></td>
                          <td><Badge color={COST_TIER_COLOR[costTierFor(ms.model)]||'gray'} style={{fontSize:10.5,textTransform:'capitalize'}}>{costTierFor(ms.model)}</Badge></td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            </SectionCard>}
          </>}
        </>
      )}
    </div>
  );
}

/* =====================  BILLING  ===================== */
function PricingTermsCard({billing}){
  if(!billing || !billing.tier) return null;
  var t = billing.tier;
  var col = t==='enterprise'?'purple':t==='premium'?'blue':t==='standard'?'cyan':'gray';
  var inR = billing.rate_in_usd_1m || 0;
  var outR = billing.rate_out_usd_1m || 0;
  var disc = billing.rate_discount_pct;
  var hasCustom = billing.rate_has_custom_terms;
  return (
    <div className="card card-pad row" style={{gap:16,flexWrap:'wrap',alignItems:'center'}}>
      <div className="row" style={{gap:10}}>
        <div>
          <div className="faint" style={{fontSize:11,marginBottom:2}}>NEUROROUTE PLAN</div>
          <Badge color={col} style={{textTransform:'capitalize',fontSize:13}}>{t}</Badge>
        </div>
      </div>
      <div style={{flex:1,display:'flex',gap:14,flexWrap:'wrap'}}>
        <div style={{padding:'8px 12px',background:'var(--bg-inset)',borderRadius:8,minWidth:120}}>
          <div className="faint" style={{fontSize:11}}>Base fee / mo</div>
          <div className="mono" style={{fontSize:15,marginTop:2}}>{billing.base_fee!=null ? fmtUSD(billing.base_fee,2) : '—'}</div>
        </div>
        <div style={{padding:'8px 12px',background:'var(--bg-inset)',borderRadius:8,minWidth:120}}>
          <div className="faint" style={{fontSize:11}}>In-token rate</div>
          <div className="mono" style={{fontSize:15,marginTop:2}}>${inR.toFixed(2)}<span className="faint" style={{fontSize:10.5}}>/1M</span></div>
        </div>
        <div style={{padding:'8px 12px',background:'var(--bg-inset)',borderRadius:8,minWidth:120}}>
          <div className="faint" style={{fontSize:11}}>Out-token rate</div>
          <div className="mono" style={{fontSize:15,marginTop:2}}>${outR.toFixed(2)}<span className="faint" style={{fontSize:10.5}}>/1M</span></div>
        </div>
        {disc!=null && <div style={{padding:'8px 12px',background:'var(--green-t)',borderRadius:8,border:'1px solid rgba(16,185,129,.3)'}}>
          <div className="faint" style={{fontSize:11}}>Custom discount</div>
          <div className="mono" style={{fontSize:15,marginTop:2,color:'var(--green)'}}>{disc}% off</div>
        </div>}
      </div>
      {!hasCustom && t!=='enterprise' && <button className="btn btn-soft btn-sm" onClick={()=>go('settings')}>Upgrade plan</button>}
    </div>
  );
}

function BillingPage(){
  /* An invoice is always a calendar month, so the month picker drives the
     billing figures. The spend chart is a rolling window and gets its own
     day-range control — the two are deliberately independent. */
  const months = recentMonthOptions();
  const [month, setMonth] = React.useState(months[0].value);
  const [chartDays, setChartDays] = React.useState(30);

  const [loading, setLoading] = React.useState(true);
  const [billing, setBilling] = React.useState(null);
  const [config, setConfig] = React.useState(null);
  const [timeline, setTimeline] = React.useState([]);
  const [history, setHistory] = React.useState([]);

  React.useEffect(()=>{
    setLoading(true);
    Promise.all([
      NR_API.billingSummary(month),
      NR_API.billingConfig(),
    ]).then(([b,c])=>{
      setBilling(b);
      setConfig(c);
      setLoading(false);
    }).catch(()=>setLoading(false));
  },[month]);

  React.useEffect(()=>{
    NR_API.dashboardUsage(chartDays)
      .then(u=>setTimeline(u && u.timeline ? u.timeline : []))
      .catch(()=>setTimeline([]));
  },[chartDays]);

  /* Settled prior invoices — fetched once; independent of the month picker. */
  React.useEffect(()=>{
    NR_API.billingHistory()
      .then(r=>setHistory((r && r.records) || []))
      .catch(()=>setHistory([]));
  },[]);

  if(loading) return <LoadingPage/>;

  const hasBilling = billing && (billing.total_charge > 0 || billing.total_savings > 0);
  const labels = timeline.map(d=>{ const dt=new Date(d.date); return (dt.getMonth()+1)+'/'+dt.getDate(); });
  const feePct = (billing && billing.platform_fee_pct) || 25;
  const isCurrentMonth = month === months[0].value;

  /* Usage consumed in the selected month, summed from the per-model breakdown
     (the same rows the table below renders, so the totals always reconcile). */
  const byModel = (billing && billing.by_model) || [];
  const used = byModel.reduce((a,m)=>({
    requests: a.requests + (m.requests||0),
    inTok:    a.inTok    + (m.input_tokens||0),
    outTok:   a.outTok   + (m.output_tokens||0),
  }), {requests:0, inTok:0, outTok:0});

  const invStatusColor = s =>
    (s==='paid'||s==='settled'||s==='finalized') ? 'green' : (s==='pending' ? 'amber' : 'gray');
  const monthLabel = ym => {
    const o = months.filter(x=>x.value===ym)[0];
    return o ? o.label : ym;
  };

  return (
    <div className="grid" style={{gap:18}}>
      <PageHead desc="Your spend, savings, and billing details. Invoices are issued per calendar month.">
        <select className="input input-sm" style={{width:132}} value={month}
          onChange={e=>setMonth(e.target.value)}>
          {months.map(o=><option key={o.value} value={o.value}>{o.label}</option>)}
        </select>
        {hasBilling && <button className="btn btn-soft btn-sm" onClick={function(){
          window.open('/v1/customer/billing-summary/export?month='+month, '_blank');
        }}><Icon name="download" size={15}/>Download statement (CSV)</button>}
      </PageHead>

      {!hasBilling ?
        <EmptyState icon="billing" title={'No billing data for '+monthLabel(month)} desc="Nothing was billed in this period. Pick another month, or send requests through the API to start accruing charges."/> :
      <>
        <PricingTermsCard billing={billing}/>
        <div className="grid" style={{gridTemplateColumns:'1.3fr 1fr 1fr', gap:14}}>
          <div className="card" style={{position:'relative',overflow:'hidden',padding:24}}>
            <div style={{position:'absolute',inset:0,background:'radial-gradient(120% 140% at 100% 0%, rgba(59,130,246,.14), transparent 55%)'}}/>
            <div style={{position:'relative'}}>
              <div className="eyebrow" style={{marginBottom:8}}>{monthLabel(month).toUpperCase()}</div>
              <div className="display" style={{fontSize:40,lineHeight:1}}>{fmtUSD(billing.total_charge||0,2)}</div>
              <div className="faint" style={{marginTop:8,fontSize:13}}>
                {isCurrentMonth ? 'Charge so far this period' : 'Total charged for this period'}
              </div>
              {isCurrentMonth && billing.projected_total > (billing.total_charge||0) && <div className="row" style={{gap:6,marginTop:10}}>
                <Icon name="trendup" size={14} style={{color:'var(--blue)'}}/>
                <span className="faint" style={{fontSize:12.5}}>Projected month-end: <b style={{color:'var(--tx-0)'}}>{fmtUSD(billing.projected_total,2)}</b></span>
              </div>}
            </div>
          </div>
          <Metric icon="dollar" color="green" value={fmtUSD(billing.total_savings||0,2)} label="Total savings"/>
          <Metric icon="billing" color="magenta" value={fmtUSD(billing.platform_fee||0,2)} label={billing.base_fee!=null?"Platform fee":feePct+"% platform fee"}/>
        </div>

        {/* Usage consumed in the selected month */}
        <SectionCard title={'Usage '+(isCurrentMonth?'so far this month':'in '+monthLabel(month))}
          sub="What you have consumed in this billing period">
          <div className="grid" style={{gridTemplateColumns:'repeat(auto-fit, minmax(150px, 1fr))', gap:12}}>
            <Metric icon="zap"       color="blue"    value={fmtNum(used.requests)}            label="Requests"/>
            <Metric icon="arrowdown" color="cyan"    value={fmtTok(used.inTok)}               label="Input tokens"/>
            <Metric icon="arrowup"   color="purple"  value={fmtTok(used.outTok)}              label="Output tokens"/>
            <Metric icon="layers"    color="amber"   value={fmtNum(byModel.length)}           label="Models used"/>
            <Metric icon="dollar"    color="magenta" value={fmtUSD(billing.sisl_managed_cost||0,2)} label="Provider cost"/>
          </div>
        </SectionCard>

        <div className="grid" style={{gridTemplateColumns:'1fr 1fr'}}>
          <SectionCard title="Billing breakdown" sub="How your bill is calculated">
            <div className="grid" style={{gap:14}}>
              {/* base_fee is always a plain float from the API (never null — see
                  billing_endpoints.go's computeBillingModel/handleBillingSummary), so
                  the legacy "% of savings" branch this ternary used to have was dead
                  code; it also contradicted landing-story.jsx's "no % of savings"
                  claim, so it's been removed rather than left reachable. */}
              <>
                <div className="spread" style={{padding:'12px 14px',background:'var(--bg-inset)',borderRadius:12}}>
                  <div><div style={{fontWeight:600}}>Monthly base fee</div><div className="faint" style={{fontSize:12.5}}>Flat monthly charge for your plan tier</div></div>
                  <div style={{textAlign:'right'}}><div className="mono">{fmtUSD(billing.base_fee||0,2)}</div></div>
                </div>
                <div className="spread" style={{padding:'12px 14px',background:'var(--bg-inset)',borderRadius:12}}>
                  <div><div style={{fontWeight:600}}>Token usage fee</div><div className="faint" style={{fontSize:12.5}}>Per-token platform fee on all routed requests</div>{(billing.rate_in_usd_1m!=null || billing.rate_out_usd_1m!=null) && <div className="faint mono" style={{fontSize:11,marginTop:2}}>@ ${(billing.rate_in_usd_1m||0).toFixed(2)}/1M in · ${(billing.rate_out_usd_1m||0).toFixed(2)}/1M out</div>}</div>
                  <div style={{textAlign:'right'}}><div className="mono">{fmtUSD(billing.token_fee||0,2)}</div></div>
                </div>
              </>
              <div className="spread" style={{padding:'12px 14px',background:'var(--bg-inset)',borderRadius:12}}>
                <div><div style={{fontWeight:600}}>SISL-managed keys — at cost</div><div className="faint" style={{fontSize:12.5}}>Provider cost passed through, no markup</div></div>
                <div style={{textAlign:'right'}}><div className="mono">{fmtUSD(billing.sisl_managed_cost||0,2)}</div><div className="faint mono" style={{fontSize:12}}>provider cost</div></div>
              </div>
              <div className="spread" style={{padding:'12px 14px',background:'var(--bg-inset)',borderRadius:12,opacity:.75}}>
                <div><div style={{fontWeight:600}}>BYOK — Bring Your Own Keys <Badge color="gray">informational</Badge></div><div className="faint" style={{fontSize:12.5}}>You pay providers directly · not billed by NeuroRoute</div></div>
                <div style={{textAlign:'right'}}><div className="mono faint">{fmtUSD(billing.byok_cost||0,2)}</div><div className="faint mono" style={{fontSize:12}}>paid to providers</div></div>
              </div>
              <hr className="divider"/>
              <div className="spread"><span style={{fontWeight:700}}>Total this period</span><span className="display" style={{fontSize:22}}>{fmtUSD(billing.total_charge||0,2)}</span></div>
              <div className="faint" style={{fontSize:11.5,marginTop:-6}}>*Taxes as applicable</div>
            </div>
          </SectionCard>
          <SectionCard title="Spend by day" sub={'Provider cost over the last '+chartDays+' days'}
            action={
              <div className="seg">
                {[7,15,30,90].map(d=>(
                  <button key={d} className={chartDays===d?'active':''}
                    onClick={()=>setChartDays(d)}>{d}d</button>
                ))}
              </div>
            }>
            {timeline.length>0
              ? <BarSimple labels={labels} data={timeline.map(d=>d.cost)} color={COL.magenta} height={228} fmt={(v)=>fmtUSD(v, v<1?4:2)}/>
              : <EmptyState icon="analytics" title="No spend in this window" desc="Try a longer range."/>}
          </SectionCard>
        </div>

        {billing.by_model && billing.by_model.length>0 && <SectionCard title="Cost & savings by model" sub="This month's usage, provider cost, and savings per model" pad={false}>
          <div className="scroll-x"><table className="table">
            <thead><tr><th>Model</th><th style={{textAlign:'right'}}>Requests</th><th style={{textAlign:'right'}}>Input tok</th><th style={{textAlign:'right'}}>Output tok</th><th style={{textAlign:'right'}}>Savings</th><th style={{textAlign:'right'}}>Provider cost</th></tr></thead>
            <tbody>{billing.by_model.slice().sort((a,b)=>(b.cost||0)-(a.cost||0)).map(m=>(
              <tr key={m.model}>
                <td><ModelCell id={m.model}/></td>
                <td className="num" style={{textAlign:'right'}}>{fmtNum(m.requests)}</td>
                <td className="num faint" style={{textAlign:'right'}}>{fmtNum(m.input_tokens)}</td>
                <td className="num faint" style={{textAlign:'right'}}>{fmtNum(m.output_tokens)}</td>
                <td className="num" style={{textAlign:'right',color:'var(--green)'}}>{fmtUSD(m.savings||0,4)}</td>
                <td className="num" style={{textAlign:'right',fontWeight:700}}>{fmtUSD(m.cost||0,4)}</td>
              </tr>
            ))}</tbody>
          </table></div>
        </SectionCard>}

        {billing.by_purpose && billing.by_purpose.length>0 && <SectionCard title="AI sub-call costs" sub="Model calls NeuroRoute made on your behalf while serving your requests — task classification, content moderation, injection detection, context summarization — billed at real provider cost, no markup. Not counted as your own requests on Usage." pad={false}>
          <div className="scroll-x"><table className="table">
            <thead><tr><th>Purpose</th><th style={{textAlign:'right'}}>Calls</th><th style={{textAlign:'right'}}>Input tok</th><th style={{textAlign:'right'}}>Output tok</th><th style={{textAlign:'right'}}>Cost</th></tr></thead>
            <tbody>{billing.by_purpose.slice().sort((a,b)=>(b.cost||0)-(a.cost||0)).map(p=>(
              <tr key={p.purpose}>
                <td>{PURPOSE_LABELS[p.purpose]||p.purpose}</td>
                <td className="num" style={{textAlign:'right'}}>{fmtNum(p.requests)}</td>
                <td className="num faint" style={{textAlign:'right'}}>{fmtNum(p.input_tokens)}</td>
                <td className="num faint" style={{textAlign:'right'}}>{fmtNum(p.output_tokens)}</td>
                <td className="num" style={{textAlign:'right',fontWeight:700}}>{fmtUSD(p.cost||0,4)}</td>
              </tr>
            ))}</tbody>
          </table></div>
        </SectionCard>}
      </>}

      {/* Settled invoices — outside the hasBilling gate on purpose, so prior
          months stay reachable even when the selected month has no activity. */}
      {history.length>0 && <SectionCard title="Invoice history" sub="Finalized invoices for previous billing periods" pad={false}>
        <div className="scroll-x"><table className="table">
          <thead><tr>
            <th>Period</th><th>Status</th>
            <th style={{textAlign:'right'}}>Savings</th>
            <th style={{textAlign:'right'}}>Invoiced</th>
            <th></th>
          </tr></thead>
          <tbody>{history.map(function(rec,i){
            var ym = (rec.period_start||'').slice(0,7);
            return (
              <tr key={(rec.period_start||'')+i}>
                <td style={{fontWeight:600}}>{monthLabel(ym)}</td>
                <td><Badge color={invStatusColor(rec.status)}>{rec.status||'—'}</Badge></td>
                <td className="num" style={{textAlign:'right',color:'var(--green)'}}>{fmtUSD(rec.byok_savings||0,2)}</td>
                <td className="num" style={{textAlign:'right',fontWeight:700}}>{fmtUSD(rec.total_customer_charge||0,2)}</td>
                <td style={{textAlign:'right'}}>
                  <button className="btn btn-ghost btn-sm" onClick={function(){
                    window.open('/v1/customer/billing-summary/export?month='+ym,'_blank');
                  }}><Icon name="download" size={13}/>CSV</button>
                </td>
              </tr>
            );
          })}</tbody>
        </table></div>
      </SectionCard>}
    </div>
  );
}

/* Human-readable labels for usage_events.metadata.internal_purpose values —
   gateway-initiated sub-calls billed via recordInternalLLMCall. */
const PURPOSE_LABELS = {
  classification: 'Task classification (routing)',
  moderation: 'Content moderation',
  summarization: 'Context summarization',
  prompt_injection_llm: 'AI prompt-injection detection',
};

/* =====================  MY PROVIDER KEYS  ===================== */
function MyKeysPage(){
  const t=useToast();
  const [loading, setLoading] = React.useState(true);
  const [keys, setKeys] = React.useState([]);
  const [modal, setModal] = React.useState(false);
  const [prov, setProv] = React.useState('openai');
  const [val, setVal] = React.useState('');
  const [saving, setSaving] = React.useState(false);

  React.useEffect(()=>{
    NR_API.customerKeys().then(data=>{
      setKeys(data && data.keys ? data.keys : []);
      setLoading(false);
    }).catch(()=>setLoading(false));
  },[]);

  if(loading) return <LoadingPage/>;

  const statusColor = (s) => (s==='active'||s==='valid')?'green':s==='expired'?'amber':s==='invalid'?'red':'gray';

  /* Merge with full provider list to show all providers */
  const merged = D.PROVIDERS.map(p=>{
    const k = keys.find(k=>k.provider===p.id);
    return k ? {...p, key: '••••••••'+k.key_last_4, status: k.status||'active', added: k.created_at ? new Date(k.created_at).toLocaleDateString() : '—', keyId: k.key_id}
             : {...p, key: null, status: 'Not Set', added: null, keyId: null};
  });

  const addKey = ()=>{
    setSaving(true);
    NR_API.addCustomerKey(prov, val).then(res=>{
      setSaving(false);
      if(res && res.key_id) {
        setKeys(ks=>[...ks, {key_id:res.key_id, provider:prov, key_last_4:val.slice(-4), status:'active', created_at:new Date().toISOString()}]);
        setModal(false); setVal('');
        t({title:'Key saved & validated', msg:D.providerById(prov).name+' is now active.'});
      } else {
        t({kind:'error', title:'Failed to save key', msg:(res&&res.error)||'Unknown error'});
      }
    }).catch(()=>{ setSaving(false); t({kind:'error', title:'Failed to save key'}); });
  };

  const removeKey = (keyId, provId)=>{
    NR_API.deleteCustomerKey(keyId).then(()=>{
      setKeys(ks=>ks.filter(k=>k.key_id!==keyId));
      t({kind:'info', title:'Key removed', msg:D.providerById(provId).name+' key deleted.'});
    });
  };

  return (
    <div className="grid" style={{gap:18}}>
      <PageHead desc="Bring your own provider keys. NeuroRoute routes through them and you keep the savings.">
        <button className="btn btn-primary btn-sm" onClick={()=>setModal(true)}><Icon name="plus" size={15}/>Add key</button>
      </PageHead>
      <div className="card card-pad row" style={{gap:12,background:'var(--blue-t)',borderColor:'rgba(59,130,246,.3)'}}>
        <Icon name="lock" size={18} style={{color:'var(--blue)'}}/>
        <span style={{fontSize:13.5}}>Keys are encrypted with <b>AES-256-GCM</b> envelope encryption. We never store or log your raw keys.</span>
      </div>
      <div className="cards-grid">
        {merged.map(k=>(
          <div key={k.id} className="card card-pad card-hover">
            <div className="spread"><span className="row" style={{gap:11}}><ProviderLogo id={k.id} size={40}/><div><div style={{fontWeight:700}}>{k.name}</div><div className="faint" style={{fontSize:12}}>{k.added?'Added '+k.added:'No key configured'}</div></div></span>
              <Badge color={statusColor(k.status)} dot>{k.status}</Badge></div>
            <div className="mono" style={{margin:'18px 0',fontSize:13,color:k.key?'var(--tx-1)':'var(--tx-3)',background:'var(--bg-inset)',padding:'10px 12px',borderRadius:8,border:'1px solid var(--line)'}}>{k.key||'— not set —'}</div>
            <div className="row" style={{gap:8}}>
              {k.key ? <button className="btn btn-danger btn-sm btn-block" onClick={()=>removeKey(k.keyId, k.id)}><Icon name="trash" size={14}/>Remove</button>
                     : <button className="btn btn-ghost btn-sm btn-block" onClick={()=>{setProv(k.id);setModal(true);}}><Icon name="plus" size={14}/>Add key</button>}
            </div>
          </div>
        ))}
      </div>
      {modal && <Modal title="Add provider key" sub="Encrypted and stored securely." onClose={()=>setModal(false)}
        footer={<><button className="btn btn-ghost" onClick={()=>setModal(false)}>Cancel</button><button className="btn btn-primary" disabled={!val||saving} onClick={addKey}>{saving?'Saving…':'Validate & save'}</button></>}>
        <div className="grid" style={{gap:16}}>
          <Field label="Provider"><select className="select" value={prov} onChange={e=>setProv(e.target.value)}>{D.PROVIDERS.map(p=><option key={p.id} value={p.id}>{p.name}</option>)}</select></Field>
          <Field label="API key" hint="Encrypted with AES-256-GCM. Never logged."><input className="input input-mono" placeholder="sk-..." value={val} onChange={e=>setVal(e.target.value)}/></Field>
        </div>
      </Modal>}
    </div>
  );
}

window.PAGES = Object.assign(window.PAGES||{}, {dashboard:DashboardPage, usage:UsagePage, billing:BillingPage, mykeys:MyKeysPage});
