/* ============================================================
   NeuroRoute — Team Members + Settings — wired to live APIs.
   ============================================================ */

/* ----- Guardrails helpers -----
   GUARDRAIL_RULE_DEFS / parseGuardrailRows / buildGuardrailsConfig now live
   in ui.jsx (shared with admin.jsx's Customers -> Edit guardrails section —
   see the ALERT_RULE_TYPES pattern there), since the two copies here and in
   admin.jsx had drifted into a byte-for-byte duplicate that would only
   drift again the next time a rule was added to one file and not the other. */

/* =====================  TEAM  ===================== */
function TeamPage(){
  var t=useToast();
  var _loading=useState(true); var loading=_loading[0], setLoading=_loading[1];
  var _team=useState([]); var team=_team[0], setTeam=_team[1];
  var _invites=useState([]); var invites=_invites[0], setInvites=_invites[1];
  var _modal=useState(false); var modal=_modal[0], setModal=_modal[1];
  var _email=useState(''); var email=_email[0], setEmail=_email[1];
  var _role=useState('org_member'); var role=_role[0], setRole=_role[1];
  var _inviteWs=useState(''); var inviteWs=_inviteWs[0], setInviteWs=_inviteWs[1];
  var _sending=useState(false); var sending=_sending[0], setSending=_sending[1];

  var _workspaces=useState([]); var workspaces=_workspaces[0], setWorkspaces=_workspaces[1];
  var _wsModal=useState(false); var wsModal=_wsModal[0], setWsModal=_wsModal[1];
  var _wsName=useState(''); var wsName=_wsName[0], setWsName=_wsName[1];
  var _wsDaily=useState(''); var wsDaily=_wsDaily[0], setWsDaily=_wsDaily[1];
  var _wsMonthly=useState(''); var wsMonthly=_wsMonthly[0], setWsMonthly=_wsMonthly[1];
  var _wsSaving=useState(false); var wsSaving=_wsSaving[0], setWsSaving=_wsSaving[1];
  var _wsManage=useState(null); var wsManage=_wsManage[0], setWsManage=_wsManage[1]; // workspace whose members are being managed

  // Active members who belong to a given workspace (a user may be in many).
  var wsMembers=function(wsId){ return team.filter(function(m){return (m.workspace_ids||[]).indexOf(wsId)>=0 && m.is_active!==false;}); };

  // Persist a user's FULL workspace membership set, then reflect it locally.
  var saveUserWorkspaces=function(uid,name,ids){
    NR_API.setUserWorkspaces(uid, ids).then(function(ok){
      if(ok){
        var names=ids.map(function(id){var w=workspaces.filter(function(x){return x.id===id;})[0];return (w&&w.name)||'';}).filter(Boolean);
        setTeam(function(ts){return ts.map(function(x){var xid=x.id||x.uid; return xid===uid?Object.assign({},x,{workspace_ids:ids,workspace_names:names,workspace_id:ids[0]||'',workspace_name:names[0]||''}):x;});});
        t({title:'Workspaces updated',msg:name});
      } else t({kind:'error',title:'Failed to update workspaces'});
    }).catch(function(){ t({kind:'error',title:'Failed to update workspaces'}); });
  };

  var rc=function(r){return ({admin:'magenta',org_admin:'magenta',sisl_admin:'magenta',developer:'blue',org_member:'blue',viewer:'gray',org_viewer:'gray',org_billing:'amber'})[r]||'gray';};
  var roleName=function(r){return ({admin:'Admin',org_admin:'Admin',sisl_admin:'Sisl Admin',developer:'Developer',org_member:'Member',viewer:'Viewer',org_viewer:'Viewer',org_billing:'Billing'})[r]||r;};

  var loadWorkspaces=function(){
    NR_API.workspaces().then(function(res){ setWorkspaces((res&&res.workspaces)||[]); }).catch(function(){});
  };

  useEffect(function(){
    Promise.all([NR_API.users(), NR_API.invitations()]).then(function(results){
      var usersData = results[0];
      var invData = results[1];
      if(usersData && Array.isArray(usersData.users||usersData)) {
        setTeam(usersData.users||usersData);
      }
      if(invData && Array.isArray(invData.invitations||invData)) {
        setInvites(invData.invitations||invData);
      }
      setLoading(false);
    }).catch(function(){
      /* Endpoints may not exist yet — show empty state */
      setLoading(false);
    });
    loadWorkspaces();
  },[]);

  var createWorkspace=function(){
    if(!wsName.trim()) return;
    setWsSaving(true);
    var daily = wsDaily.trim()!==''? parseFloat(wsDaily) : null;
    var monthly = wsMonthly.trim()!==''? parseFloat(wsMonthly) : null;
    NR_API.createWorkspace(wsName.trim(), daily, monthly).then(function(res){
      setWsSaving(false);
      if(res && res.id){
        t({title:'Workspace created', msg:wsName.trim()});
        setWsModal(false); setWsName(''); setWsDaily(''); setWsMonthly('');
        loadWorkspaces();
      } else { t({kind:'error',title:'Failed to create workspace'}); }
    }).catch(function(){ setWsSaving(false); t({kind:'error',title:'Failed to create workspace'}); });
  };

  var deleteWorkspace=function(id,name){
    NR_API.deleteWorkspace(id).then(function(ok){
      if(ok){ setWorkspaces(function(ws){return ws.filter(function(w){return w.id!==id;});}); t({kind:'info',title:'Workspace removed',msg:name}); }
      else t({kind:'error',title:'Failed to remove workspace'});
    }).catch(function(){ t({kind:'error',title:'Failed to remove workspace'}); });
  };

  var invite=function(){
    if(!email) return;
    setSending(true);
    NR_API.invite(email, role, inviteWs).then(function(res){
      setSending(false);
      if(res && res.id) {
        setInvites(function(iv){return [res].concat(iv);});
        setModal(false); setEmail(''); setRole('org_member'); setInviteWs('');
        t({title:'Invitation sent',msg:email});
      } else {
        t({kind:'error',title:'Failed to send invite',msg:'Endpoint may not be wired yet.'});
      }
    }).catch(function(){ setSending(false); t({kind:'error',title:'Failed to send invite'}); });
  };

  var deactivateUser=function(uid,name){
    NR_API.removeUser(uid).then(function(ok){
      if(ok){
        // Soft-deactivate: keep the row but flip status + stamp the date so the
        // member stays visible (and reactivatable) in the lifecycle view.
        setTeam(function(tm){return tm.map(function(x){return (x.id||x.uid)===uid?Object.assign({},x,{is_active:false,deactivated_at:new Date().toISOString()}):x;});});
        t({kind:'info',title:'Member deactivated',msg:name});
      } else {
        t({kind:'error',title:'Failed to deactivate member'});
      }
    }).catch(function(){ t({kind:'error',title:'Failed to deactivate member'}); });
  };

  var reactivateUser=function(uid,name){
    NR_API.reactivateUser(uid).then(function(res){
      if(res){
        setTeam(function(tm){return tm.map(function(x){return (x.id||x.uid)===uid?Object.assign({},x,{is_active:true,deactivated_at:null}):x;});});
        t({title:'Member reactivated',msg:name});
      } else t({kind:'error',title:'Failed to reactivate member'});
    }).catch(function(){ t({kind:'error',title:'Failed to reactivate member'}); });
  };

  var changeRole=function(uid,name,newRole){
    NR_API.updateRole(uid,newRole).then(function(res){
      if(res){
        setTeam(function(tm){return tm.map(function(x){return (x.id||x.uid)===uid?Object.assign({},x,{role:newRole}):x;});});
        t({title:'Role updated',msg:name+' is now '+roleName(newRole)});
      } else t({kind:'error',title:'Failed to update role'});
    }).catch(function(){ t({kind:'error',title:'Failed to update role'}); });
  };

  var cancelInvite=function(id,email){
    NR_API.cancelInvite(id).then(function(ok){
      if(ok){ setInvites(function(iv){return iv.filter(function(y){return y.id!==id;});}); t({kind:'info',title:'Invite cancelled',msg:email}); }
      else t({kind:'error',title:'Failed to cancel invite'});
    }).catch(function(){ t({kind:'error',title:'Failed to cancel invite'}); });
  };

  var resendInvite=function(id,email){
    NR_API.resendInvite(id).then(function(res){
      if(res){ t({title:'Invitation resent',msg:email}); }
      else t({kind:'error',title:'Failed to resend invite'});
    }).catch(function(){ t({kind:'error',title:'Failed to resend invite'}); });
  };

  // Toggle a single workspace on/off for a user, preserving their other
  // memberships (multi-workspace). Computes the new set and persists it.
  var toggleUserWorkspace=function(uid,name,wsId,on){
    var m=team.filter(function(x){return (x.id||x.uid)===uid;})[0];
    var cur=(m&&m.workspace_ids)?m.workspace_ids.slice():[];
    var i=cur.indexOf(wsId);
    if(on && i<0) cur.push(wsId);
    if(!on && i>=0) cur.splice(i,1);
    saveUserWorkspaces(uid,name,cur);
  };

  if(loading) return <LoadingPage/>;

  return (
    <div className="grid" style={{gap:18}}>
      <PageHead desc="Manage who can access your NeuroRoute organization and what they can do.">
        <button className="btn btn-primary btn-sm" onClick={function(){setModal(true);}}><Icon name="onboard" size={15}/>Invite team member</button>
      </PageHead>

      {team.length===0 && invites.length===0 ?
        <EmptyState icon="team" title="No team members yet"
          desc="You're the only member of this organization. Invite team members to collaborate on NeuroRoute."
          actions={[{label:'Invite Member', onClick:function(){setModal(true);}, primary:true}]}/> :
        <>
          <SectionCard title="Members" sub={team.filter(function(m){return m.is_active!==false;}).length+' active · '+team.length+' total'} pad={false}>
            {team.length>0 ? <div className="scroll-x"><table className="table">
              <thead><tr><th>Member</th><th>Role</th><th>Workspace</th><th>Status</th><th>Joined</th><th>Last login</th><th style={{textAlign:'right'}}>Actions</th></tr></thead>
              <tbody>
                {team.map(function(m){
                  var name = m.name||m.email||'User';
                  var initials = name.split(' ').map(function(x){return x[0]||'';}).join('').toUpperCase().slice(0,2);
                  var uid = m.id||m.uid;
                  var active = m.is_active!==false;
                  return (
                    <tr key={uid||m.email} style={active?null:{opacity:.55}}>
                      <td><span className="row" style={{gap:10}}><span className="avatar" style={{background:m.color||'var(--blue)',width:30,height:30,fontSize:11.5}}>{initials}</span><span><b style={{color:'var(--tx-0)'}}>{name}</b><div className="faint" style={{fontSize:12}}>{m.email}</div></span></span></td>
                      <td>
                        <select className="select" style={{minWidth:110,fontSize:12,padding:'4px 8px'}} value={m.role||'org_member'} disabled={!active}
                          onChange={function(e){changeRole(uid,name,e.target.value);}}>
                          <option value="org_admin">Admin</option>
                          <option value="org_member">Member</option>
                          <option value="org_viewer">Viewer</option>
                          <option value="org_billing">Billing</option>
                        </select>
                      </td>
                      <td>
                        {workspaces.length>0 ?
                          <div className="row" style={{gap:4,flexWrap:'wrap',maxWidth:220}}>
                            {workspaces.map(function(w){
                              var member=(m.workspace_ids||[]).indexOf(w.id)>=0;
                              return <button key={w.id} disabled={!active}
                                className={'btn btn-sm '+(member?'btn-soft':'btn-ghost')}
                                style={{fontSize:11,padding:'2px 8px',opacity:member?1:.6}}
                                onClick={function(){toggleUserWorkspace(uid,name,w.id,!member);}}
                                title={member?('In '+w.name+' — click to remove'):('Add to '+w.name)}>
                                {member?'✓ ':''}{w.name}
                              </button>;
                            })}
                          </div>
                          : <span className="faint">—</span>}
                      </td>
                      <td>{active
                        ? <Badge color="green" dot style={{fontSize:10}}>Active</Badge>
                        : <span><Badge color="gray" dot style={{fontSize:10}}>Deactivated</Badge>{m.deactivated_at && <div className="faint" style={{fontSize:11,marginTop:3}}>{new Date(m.deactivated_at).toLocaleDateString()}</div>}</span>}
                      </td>
                      <td className="faint" style={{fontSize:12,whiteSpace:'nowrap'}}>{m.activated_at?new Date(m.activated_at).toLocaleDateString():'—'}</td>
                      <td className="faint" style={{fontSize:12,whiteSpace:'nowrap'}}>{m.last_login?timeAgo(m.last_login):'never'}</td>
                      <td style={{textAlign:'right'}}>
                        <div className="row" style={{gap:6,justifyContent:'flex-end'}}>
                          {active
                            ? <button className="iconbtn" onClick={function(){deactivateUser(uid,name);}} title="Deactivate member"><Icon name="trash" size={14}/></button>
                            : <button className="btn btn-soft btn-sm" onClick={function(){reactivateUser(uid,name);}}>Reactivate</button>}
                        </div>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table></div> : <div className="empty" style={{padding:32}}><p className="faint">No team members loaded.</p></div>}
          </SectionCard>

          <div className="grid" style={{gridTemplateColumns:'1.5fr 1fr'}}>
            <SectionCard title="Pending invitations" sub={invites.length+' pending'} pad={false}>
              {invites.length? <table className="table">
                <thead><tr><th>Email</th><th>Role</th><th>Sent</th><th style={{textAlign:'right'}}></th></tr></thead>
                <tbody>{invites.map(function(iv){return (
                  <tr key={iv.id||iv.email}><td style={{color:'var(--tx-0)'}}>{iv.email}</td><td><Badge color={rc(iv.role)}>{roleName(iv.role)}</Badge></td><td className="faint">{timeAgo(iv.created_at||iv.sent)||iv.created_at||iv.sent}</td>
                    <td style={{textAlign:'right'}}>
                      <div className="row" style={{gap:6,justifyContent:'flex-end'}}>
                        {iv.id && <button className="btn btn-soft btn-sm" onClick={function(){resendInvite(iv.id,iv.email);}}>Resend</button>}
                        <button className="btn btn-soft btn-sm" onClick={function(){iv.id?cancelInvite(iv.id,iv.email):setInvites(function(x){return x.filter(function(y){return y!==iv;});});}}>Cancel</button>
                      </div>
                    </td></tr>
                );})}</tbody>
              </table> : <div className="empty" style={{padding:32}}><div className="e-ico"><Icon name="onboard" size={22}/></div><p className="faint">No pending invitations.</p></div>}
            </SectionCard>
            <SectionCard title="Role permissions">
              <div className="grid" style={{gap:12}}>
                {[['Admin','magenta','Full access — manage members, keys, billing & config'],['Member','blue','Use the API and view all usage data'],['Viewer','gray','Read-only access to dashboards'],['Billing','amber','Billing & Costs and My Provider Keys pages only']].map(function(arr){
                  var r=arr[0],c=arr[1],d=arr[2];
                  return <div key={r} className="row" style={{gap:12,alignItems:'flex-start'}}><Badge color={c} style={{marginTop:2}}>{r}</Badge><span className="faint" style={{fontSize:13}}>{d}</span></div>;
                })}
              </div>
            </SectionCard>
          </div>
        </>
      }

      <SectionCard title="Workspaces" sub="Team groupings under your org — bind API keys to a workspace for chargeback and per-workspace budgets."
        action={<button className="btn btn-primary btn-sm" onClick={function(){setWsModal(true);}}><Icon name="onboard" size={15}/>New workspace</button>} pad={workspaces.length>0?false:undefined}>
        {workspaces.length===0 ? <div className="empty" style={{padding:32}}><div className="e-ico"><Icon name="team" size={22}/></div><p className="faint">No workspaces yet — API keys stay unassigned until you create one.</p></div> :
          <table className="table">
            <thead><tr><th>Name</th><th>Members</th><th>Daily budget</th><th>Monthly budget</th><th style={{textAlign:'right'}}>Actions</th></tr></thead>
            <tbody>
              {workspaces.map(function(ws){
                var count=wsMembers(ws.id).length;
                return <tr key={ws.id}>
                  <td style={{color:'var(--tx-0)',fontWeight:600}}>{ws.name}</td>
                  <td className="faint">{count} member{count===1?'':'s'}</td>
                  <td className="faint tnum">{ws.daily_budget_usd!=null?('$'+ws.daily_budget_usd.toFixed(2)):'Unlimited'}</td>
                  <td className="faint tnum">{ws.monthly_budget_usd!=null?('$'+ws.monthly_budget_usd.toFixed(2)):'Unlimited'}</td>
                  <td style={{textAlign:'right'}}>
                    <div className="row" style={{gap:6,justifyContent:'flex-end'}}>
                      <button className="btn btn-soft btn-sm" onClick={function(){setWsManage(ws);}}>Manage members</button>
                      <button className="iconbtn" onClick={function(){deleteWorkspace(ws.id,ws.name);}} title="Delete workspace"><Icon name="trash" size={14}/></button>
                    </div>
                  </td>
                </tr>;
              })}
            </tbody>
          </table>}
      </SectionCard>

      {wsModal && <Modal title="New workspace" sub="Bind API keys to this workspace to track spend and set a per-team budget."
        onClose={function(){setWsModal(false);}}
        footer={<><button className="btn btn-ghost" onClick={function(){setWsModal(false);}}>Cancel</button>
          <button className="btn btn-primary" disabled={!wsName.trim()||wsSaving} onClick={createWorkspace}>{wsSaving?'Creating…':'Create workspace'}</button></>}>
        <div className="grid" style={{gap:16}}>
          <Field label="Name"><input className="input" placeholder="Growth team" value={wsName} onChange={function(e){setWsName(e.target.value);}}/></Field>
          <div className="grid" style={{gridTemplateColumns:'1fr 1fr',gap:14}}>
            <Field label="Daily budget (USD)" hint="Optional — blank means unlimited."><input className="input" type="number" min="0" step="1" placeholder="Unlimited" value={wsDaily} onChange={function(e){setWsDaily(e.target.value);}}/></Field>
            <Field label="Monthly budget (USD)" hint="Optional — blank means unlimited."><input className="input" type="number" min="0" step="1" placeholder="Unlimited" value={wsMonthly} onChange={function(e){setWsMonthly(e.target.value);}}/></Field>
          </div>
        </div>
      </Modal>}

      {wsManage && <Modal title={'Members of '+wsManage.name}
        sub="Add or remove members. A member can belong to several workspaces — toggling here only affects this one."
        onClose={function(){setWsManage(null);}}
        footer={<button className="btn btn-primary" onClick={function(){setWsManage(null);}}>Done</button>}>
        {team.filter(function(m){return m.is_active!==false;}).length===0
          ? <p className="faint" style={{fontSize:13,margin:0}}>No active members to add. Invite teammates first.</p>
          : <div className="grid" style={{gap:4,maxHeight:360,overflowY:'auto'}}>
              {team.filter(function(m){return m.is_active!==false;}).map(function(m){
                var uid=m.id||m.uid; var name=m.name||m.email||'User';
                var inHere=(m.workspace_ids||[]).indexOf(wsManage.id)>=0;
                var others=(m.workspace_names||[]).filter(function(n){return n!==wsManage.name;});
                return <label key={uid||m.email} className="spread" style={{gap:12,padding:'9px 6px',borderBottom:'1px solid var(--line)',cursor:'pointer'}}>
                  <span>
                    <b style={{color:'var(--tx-0)',fontSize:13.5}}>{name}</b>
                    <div className="faint" style={{fontSize:12}}>{m.email}{others.length?(' · also in '+others.join(', ')):''}</div>
                  </span>
                  <Switch on={inHere} onChange={function(v){ toggleUserWorkspace(uid, name, wsManage.id, v); }}/>
                </label>;
              })}
            </div>}
      </Modal>}

      {modal && <Modal title="Invite team member" sub={"They'll get an email invitation to join "+window.DATA.ORG.name+"."} onClose={function(){setModal(false);}}
        footer={<><button className="btn btn-ghost" onClick={function(){setModal(false);}}>Cancel</button><button className="btn btn-primary" disabled={!email||sending} onClick={invite}><Icon name="send" size={15}/>{sending?'Sending…':'Send invitation'}</button></>}>
        <div className="grid" style={{gap:16}}>
          <Field label="Email address"><input className="input" type="email" placeholder="teammate@company.com" value={email} onChange={function(e){setEmail(e.target.value);}}/></Field>
          <Field label="Role"><select className="select" value={role} onChange={function(e){setRole(e.target.value);}}><option value="org_admin">Admin (org)</option><option value="org_member">Member</option><option value="org_viewer">Viewer</option><option value="org_billing">Billing</option></select></Field>
          {workspaces.length>0 && <Field label="Workspace" hint="Optional — the member is mapped to this workspace when they accept.">
            <select className="select" value={inviteWs} onChange={function(e){setInviteWs(e.target.value);}}>
              <option value="">— none —</option>
              {workspaces.map(function(w){return <option key={w.id} value={w.id}>{w.name}</option>;})}
            </select>
          </Field>}
        </div>
      </Modal>}
    </div>
  );
}

/* =====================  SETTINGS  ===================== */
function SettingsPage(){
  var t=useToast();
  var _loading=useState(true); var loading=_loading[0], setLoading=_loading[1];
  var _config=useState(null); var config=_config[0], setConfig=_config[1];
  var _strategy=useState('balanced'); var strategy=_strategy[0], setStrategy=_strategy[1];
  var _quality=useState(70); var quality=_quality[0], setQuality=_quality[1];
  var _pctx=useState(''); var pctx=_pctx[0], setPctx=_pctx[1];
  var _pctxSaving=useState(false); var pctxSaving=_pctxSaving[0], setPctxSaving=_pctxSaving[1];
  var _sctx=useState(''); var sctx=_sctx[0], setSctx=_sctx[1];
  var _sctxSaving=useState(false); var sctxSaving=_sctxSaving[0], setSctxSaving=_sctxSaving[1];
  var PCTX_MAX=32768;

  var _grEnabled=useState(false); var grEnabled=_grEnabled[0], setGrEnabled=_grEnabled[1];
  var _grRows=useState(function(){return parseGuardrailRows('[]');}); var grRows=_grRows[0], setGrRows=_grRows[1];
  var _grShowRules=useState(false); var grShowRules=_grShowRules[0], setGrShowRules=_grShowRules[1];
  var _grSaving=useState(false); var grSaving=_grSaving[0], setGrSaving=_grSaving[1];

  var _rcRaw=useState('{\n  "rules": []\n}'); var rcRaw=_rcRaw[0], setRcRaw=_rcRaw[1];
  var _rcConfigured=useState(false); var rcConfigured=_rcConfigured[0], setRcConfigured=_rcConfigured[1];
  var _rcVersion=useState(0); var rcVersion=_rcVersion[0], setRcVersion=_rcVersion[1];
  var _rcVersions=useState([]); var rcVersions=_rcVersions[0], setRcVersions=_rcVersions[1];
  var _rcSaving=useState(false); var rcSaving=_rcSaving[0], setRcSaving=_rcSaving[1];
  var _rcError=useState(''); var rcError=_rcError[0], setRcError=_rcError[1];

  var _sso=useState(null); var sso=_sso[0], setSso=_sso[1];
  var _ssoDomain=useState(''); var ssoDomain=_ssoDomain[0], setSsoDomain=_ssoDomain[1];
  var _ssoIssuer=useState(''); var ssoIssuer=_ssoIssuer[0], setSsoIssuer=_ssoIssuer[1];
  var _ssoClientId=useState(''); var ssoClientId=_ssoClientId[0], setSsoClientId=_ssoClientId[1];
  var _ssoClientSecret=useState(''); var ssoClientSecret=_ssoClientSecret[0], setSsoClientSecret=_ssoClientSecret[1];
  var _ssoLabel=useState(''); var ssoLabel=_ssoLabel[0], setSsoLabel=_ssoLabel[1];
  var _ssoEnabled=useState(true); var ssoEnabled=_ssoEnabled[0], setSsoEnabled=_ssoEnabled[1];
  var _ssoSaving=useState(false); var ssoSaving=_ssoSaving[0], setSsoSaving=_ssoSaving[1];
  /* SAML 2.0 SSO (I-4) — sibling to the OIDC state above, same shape. */
  var _saml=useState(null); var saml=_saml[0], setSaml=_saml[1];
  var _samlDomain=useState(''); var samlDomain=_samlDomain[0], setSamlDomain=_samlDomain[1];
  var _samlLabel=useState(''); var samlLabel=_samlLabel[0], setSamlLabel=_samlLabel[1];
  var _samlMetadataUrl=useState(''); var samlMetadataUrl=_samlMetadataUrl[0], setSamlMetadataUrl=_samlMetadataUrl[1];
  var _samlMetadataXml=useState(''); var samlMetadataXml=_samlMetadataXml[0], setSamlMetadataXml=_samlMetadataXml[1];
  var _samlEnabled=useState(true); var samlEnabled=_samlEnabled[0], setSamlEnabled=_samlEnabled[1];
  var _samlSaving=useState(false); var samlSaving=_samlSaving[0], setSamlSaving=_samlSaving[1];

  var _ewh=useState(null); var ewh=_ewh[0], setEwh=_ewh[1];
  var _ewhUrl=useState(''); var ewhUrl=_ewhUrl[0], setEwhUrl=_ewhUrl[1];
  var _ewhSecret=useState(''); var ewhSecret=_ewhSecret[0], setEwhSecret=_ewhSecret[1];
  var _ewhEvents=useState([]); var ewhEvents=_ewhEvents[0], setEwhEvents=_ewhEvents[1];
  var _ewhEnabled=useState(true); var ewhEnabled=_ewhEnabled[0], setEwhEnabled=_ewhEnabled[1];
  var _ewhSaving=useState(false); var ewhSaving=_ewhSaving[0], setEwhSaving=_ewhSaving[1];
  var EVENT_TYPES=[['budget.tripped','Budget tripped'],['org.erasure.completed','Erasure completed'],['key.created','API key created']];

  var _uexSchedule=useState(''); var uexSchedule=_uexSchedule[0], setUexSchedule=_uexSchedule[1];
  var _uexLastRun=useState(null); var uexLastRun=_uexLastRun[0], setUexLastRun=_uexLastRun[1];
  var _uexSaving=useState(false); var uexSaving=_uexSaving[0], setUexSaving=_uexSaving[1];

  var _ent=useState(null); var ent=_ent[0], setEnt=_ent[1];
  var _conciseOutput=useState(false); var conciseOutput=_conciseOutput[0], setConciseOutput=_conciseOutput[1];
  var _coSaving=useState(false); var coSaving=_coSaving[0], setCoSaving=_coSaving[1];
  var _mpc=useState([]); var mpc=_mpc[0], setMpc=_mpc[1]; // model priority chain
  var _mpcSaving=useState(false); var mpcSaving=_mpcSaving[0], setMpcSaving=_mpcSaving[1];
  var _mpcNewModel=useState(''); var mpcNewModel=_mpcNewModel[0], setMpcNewModel=_mpcNewModel[1];

  /* Data retention — self-service (customer-facing mirror of the SISL admin
     Customers->Edit retention fields, scoped to this org). */
  var _drMode=useState('retain'); var drMode=_drMode[0], setDrMode=_drMode[1];
  var _drDays=useState('30'); var drDays=_drDays[0], setDrDays=_drDays[1];
  var _drLogMode=useState('metadata'); var drLogMode=_drLogMode[0], setDrLogMode=_drLogMode[1];
  var _drSaving=useState(false); var drSaving=_drSaving[0], setDrSaving=_drSaving[1];
  /* CMEK — self-service, Enterprise-gated (see `ent` above). */
  var _cmek=useState(''); var cmek=_cmek[0], setCmek=_cmek[1];
  var _cmekSaving=useState(false); var cmekSaving=_cmekSaving[0], setCmekSaving=_cmekSaving[1];

  useEffect(function(){
    NR_API.config().then(function(res){
      if(res) {
        setConfig(res);
        // Server response nests these under `routing` — not flat top-level keys.
        var routing = res.routing || {};
        setStrategy(routing.default_strategy || 'balanced');
        setQuality(Math.round((routing.quality_threshold!=null ? routing.quality_threshold : 0.7)*100));
      }
      setLoading(false);
    }).catch(function(){ setLoading(false); });
    NR_API.getProjectContext().then(function(res){
      if(res && typeof res.project_context==='string') setPctx(res.project_context);
    }).catch(function(){});
    NR_API.getSprintContext().then(function(res){
      if(res && typeof res.sprint_context==='string') setSctx(res.sprint_context);
    }).catch(function(){});
    NR_API.getConciseOutput().then(function(res){
      if(res && typeof res.concise_output==='boolean') setConciseOutput(res.concise_output);
    }).catch(function(){});
    NR_API.getModelPriorityChain().then(function(res){
      if(res && Array.isArray(res.model_priority_chain)) setMpc(res.model_priority_chain);
    }).catch(function(){});
    NR_API.getDataRetention().then(function(res){
      if(!res) return;
      if(typeof res.retention_mode==='string') setDrMode(res.retention_mode);
      if(res.content_retention_days!=null) setDrDays(String(res.content_retention_days));
      if(typeof res.request_logging_mode==='string') setDrLogMode(res.request_logging_mode);
    }).catch(function(){});
    NR_API.getCMEK().then(function(res){
      if(res && typeof res.cmek_key_name==='string') setCmek(res.cmek_key_name);
    }).catch(function(){});
    NR_API.getGuardrails().then(function(res){
      if(!res) return;
      setGrEnabled(!!res.guardrails_enabled);
      setGrRows(parseGuardrailRows(JSON.stringify(res.guardrails_config||[])));
    }).catch(function(){});
    NR_API.getSSOConfig().then(function(res){
      if(!res) return;
      setSso(res);
      if(res.configured){
        setSsoDomain(res.domain||''); setSsoIssuer(res.issuer||''); setSsoClientId(res.client_id||'');
        setSsoLabel(res.provider_label||''); setSsoEnabled(!!res.enabled);
      }
    }).catch(function(){});
    NR_API.getSAMLConfig().then(function(res){
      if(!res) return;
      setSaml(res);
      if(res.configured){
        setSamlDomain(res.domain||''); setSamlMetadataUrl(res.idp_metadata_url||'');
        setSamlLabel(res.provider_label||''); setSamlEnabled(!!res.enabled);
      }
    }).catch(function(){});
    NR_API.getRoutingConfig().then(function(res){
      if(res && res.configured && res.active){
        setRcConfigured(true); setRcVersion(res.active.version);
        setRcRaw(JSON.stringify(res.active.config, null, 2));
      }
    }).catch(function(){});
    loadRoutingConfigVersions();
    NR_API.getEventWebhook().then(function(res){
      if(!res) return;
      setEwh(res);
      if(res.configured){
        setEwhUrl(res.url||''); setEwhEvents(res.events||[]); setEwhEnabled(!!res.enabled);
      }
    }).catch(function(){});
    NR_API.getUsageExportSchedule().then(function(res){
      if(!res) return;
      setUexSchedule(res.schedule||''); setUexLastRun(res.last_run||null);
    }).catch(function(){});
    NR_API.entitlements().then(function(res){ if(res) setEnt(res); }).catch(function(){});
  },[]);

  var toggleEwhEvent=function(ev){
    setEwhEvents(function(list){
      return list.indexOf(ev)!==-1 ? list.filter(function(x){return x!==ev;}) : list.concat([ev]);
    });
  };

  var saveEventWebhook=function(){
    setEwhSaving(true);
    NR_API.setEventWebhook({url:ewhUrl.trim(), secret:ewhSecret, events:ewhEvents, enabled:ewhEnabled}).then(function(ok){
      setEwhSaving(false);
      if(ok){ t({title:'Event webhook saved'}); setEwhSecret(''); setEwh({configured:true, url:ewhUrl, events:ewhEvents, enabled:ewhEnabled}); }
      else t({kind:'error',title:'Failed to save event webhook'});
    }).catch(function(){ setEwhSaving(false); t({kind:'error',title:'Failed to save event webhook'}); });
  };

  var deleteEventWebhook=function(){
    NR_API.deleteEventWebhook().then(function(ok){
      if(ok){ t({title:'Event webhook removed'}); setEwh(null); setEwhUrl(''); setEwhSecret(''); setEwhEvents([]); setEwhEnabled(true); }
      else t({kind:'error',title:'Failed to remove event webhook'});
    }).catch(function(){ t({kind:'error',title:'Failed to remove event webhook'}); });
  };

  var saveUsageExportSchedule=function(next){
    setUexSaving(true);
    NR_API.setUsageExportSchedule(next).then(function(ok){
      setUexSaving(false);
      if(ok){ setUexSchedule(next); t({title:'Usage export schedule updated', msg:next?next:'Turned off'}); }
      else t({kind:'error',title:'Failed to update export schedule'});
    }).catch(function(){ setUexSaving(false); t({kind:'error',title:'Failed to update export schedule'}); });
  };

  var loadRoutingConfigVersions=function(){
    NR_API.listRoutingConfigVersions().then(function(res){ setRcVersions((res&&res.versions)||[]); }).catch(function(){});
  };

  var saveRoutingConfig=function(){
    var parsed;
    try{ parsed = JSON.parse(rcRaw||'{}'); }
    catch(e){ setRcError('Invalid JSON: '+e.message); return; }
    setRcSaving(true); setRcError('');
    NR_API.setRoutingConfig(parsed).then(function(res){
      setRcSaving(false);
      if(res.ok && res.data && res.data.version){
        t({title:'Routing config published', msg:'v'+res.data.version+' is now active'});
        setRcVersion(res.data.version); setRcConfigured(true);
        loadRoutingConfigVersions();
      } else {
        setRcError((res.data && res.data.error) || 'Failed to publish routing config');
      }
    }).catch(function(){ setRcSaving(false); setRcError('Failed to publish routing config'); });
  };

  var activateRoutingVersion=function(v){
    NR_API.activateRoutingConfigVersion(v).then(function(res){
      if(res){
        t({title:'Activated version '+v});
        setRcVersion(v); setRcConfigured(true);
        var found = rcVersions.filter(function(x){return x.version===v;})[0];
        if(found) setRcRaw(JSON.stringify(found.config, null, 2));
      } else t({kind:'error',title:'Failed to activate version'});
    }).catch(function(){ t({kind:'error',title:'Failed to activate version'}); });
  };

  var savePctx=function(){
    setPctxSaving(true);
    NR_API.setProjectContext(pctx).then(function(ok){
      setPctxSaving(false);
      if(ok) t({title:'Project context saved'});
      else t({kind:'error',title:'Failed to save project context'});
    }).catch(function(){ setPctxSaving(false); t({kind:'error',title:'Failed to save project context'}); });
  };

  var saveSctx=function(){
    setSctxSaving(true);
    NR_API.setSprintContext(sctx).then(function(ok){
      setSctxSaving(false);
      if(ok) t({title:'Sprint context saved'});
      else t({kind:'error',title:'Failed to save sprint context'});
    }).catch(function(){ setSctxSaving(false); t({kind:'error',title:'Failed to save sprint context'}); });
  };

  var saveConciseOutput=function(val){
    setCoSaving(true);
    NR_API.setConciseOutput(val).then(function(ok){
      setCoSaving(false);
      if(ok) t({title: val ? 'Concise output enabled' : 'Concise output disabled'});
      else t({kind:'error',title:'Failed to save concise output setting'});
    }).catch(function(){ setCoSaving(false); t({kind:'error',title:'Failed to save concise output setting'}); });
  };

  var saveMpc=function(chain){
    setMpcSaving(true);
    NR_API.setModelPriorityChain(chain).then(function(ok){
      setMpcSaving(false);
      if(ok) t({title:'Model priority chain saved'});
      else t({kind:'error',title:'Failed to save model priority chain'});
    }).catch(function(){ setMpcSaving(false); t({kind:'error',title:'Failed to save model priority chain'}); });
  };
  var mpcAdd=function(){
    var id=mpcNewModel.trim();
    if(!id||mpc.indexOf(id)>=0) return;
    if(mpc.length>=10){t({kind:'error',title:'Maximum 10 models in chain'});return;}
    setMpc(mpc.concat([id]));
    setMpcNewModel('');
  };
  var mpcRemove=function(idx){setMpc(mpc.filter(function(_,i){return i!==idx;}));};
  var mpcMove=function(idx,dir){
    var a=mpc.slice();
    var j=idx+dir;
    if(j<0||j>=a.length) return;
    var tmp=a[idx];a[idx]=a[j];a[j]=tmp;
    setMpc(a);
  };

  var saveDataRetention=function(){
    setDrSaving(true);
    var payload={retention_mode:drMode};
    if(drMode==='retain'){
      var d=parseInt(drDays,10);
      payload.content_retention_days=(d>=1&&d<=365)?d:30;
      payload.request_logging_mode=drLogMode;
    } else {
      payload.request_logging_mode='metadata';
    }
    NR_API.setDataRetention(payload).then(function(res){
      setDrSaving(false);
      if(res && res.ok) t({title:'Data retention settings saved'});
      else t({kind:'error',title:(res&&res.error)||'Failed to save data retention settings'});
    }).catch(function(){ setDrSaving(false); t({kind:'error',title:'Failed to save data retention settings'}); });
  };

  var cmekEntitled = !!(ent && ent.effective_features && ent.effective_features.indexOf('cmek')!==-1);
  var saveCMEK=function(){
    setCmekSaving(true);
    NR_API.setCMEK(cmek.trim()).then(function(res){
      setCmekSaving(false);
      if(res && res.ok) t({title: cmek.trim() ? 'CMEK saved' : 'CMEK cleared (using platform key)'});
      else t({kind:'error',title:(res&&res.error)||'Failed to save CMEK'});
    }).catch(function(){ setCmekSaving(false); t({kind:'error',title:'Failed to save CMEK'}); });
  };

  var saveGuardrails=function(){
    setGrSaving(true);
    NR_API.setGuardrails(grEnabled, buildGuardrailsConfig(grRows)).then(function(ok){
      setGrSaving(false);
      if(ok) t({title:'Guardrails saved'});
      else t({kind:'error',title:'Failed to save guardrails'});
    }).catch(function(){ setGrSaving(false); t({kind:'error',title:'Failed to save guardrails'}); });
  };

  var saveSSO=function(){
    setSsoSaving(true);
    NR_API.setSSOConfig({
      domain: ssoDomain.trim().toLowerCase(), issuer: ssoIssuer.trim(), client_id: ssoClientId.trim(),
      client_secret: ssoClientSecret, provider_label: ssoLabel.trim(), enabled: ssoEnabled
    }).then(function(ok){
      setSsoSaving(false);
      if(ok){ t({title:'SSO configuration saved'}); setSsoClientSecret(''); setSso({configured:true, domain:ssoDomain, issuer:ssoIssuer, client_id:ssoClientId, provider_label:ssoLabel, enabled:ssoEnabled}); }
      else t({kind:'error',title:'Failed to save SSO configuration'});
    }).catch(function(){ setSsoSaving(false); t({kind:'error',title:'Failed to save SSO configuration'}); });
  };

  var deleteSSO=function(){
    NR_API.deleteSSOConfig().then(function(ok){
      if(ok){ t({title:'SSO configuration removed'}); setSso(null); setSsoDomain(''); setSsoIssuer(''); setSsoClientId(''); setSsoLabel(''); setSsoClientSecret(''); setSsoEnabled(true); }
      else t({kind:'error',title:'Failed to remove SSO configuration'});
    }).catch(function(){ t({kind:'error',title:'Failed to remove SSO configuration'}); });
  };

  var saveSAML=function(){
    setSamlSaving(true);
    NR_API.setSAMLConfig({
      domain: samlDomain.trim().toLowerCase(), idp_metadata_url: samlMetadataUrl.trim(),
      idp_metadata_xml: samlMetadataXml, provider_label: samlLabel.trim(), enabled: samlEnabled
    }).then(function(ok){
      setSamlSaving(false);
      if(ok){ t({title:'SAML configuration saved'}); setSamlMetadataXml(''); setSaml({configured:true, domain:samlDomain, idp_metadata_url:samlMetadataUrl, has_metadata_xml:!!samlMetadataXml||(saml&&saml.has_metadata_xml), provider_label:samlLabel, enabled:samlEnabled}); }
      else t({kind:'error',title:'Failed to save SAML configuration'});
    }).catch(function(){ setSamlSaving(false); t({kind:'error',title:'Failed to save SAML configuration'}); });
  };

  var deleteSAML=function(){
    NR_API.deleteSAMLConfig().then(function(ok){
      if(ok){ t({title:'SAML configuration removed'}); setSaml(null); setSamlDomain(''); setSamlLabel(''); setSamlMetadataUrl(''); setSamlMetadataXml(''); setSamlEnabled(true); }
      else t({kind:'error',title:'Failed to remove SAML configuration'});
    }).catch(function(){ t({kind:'error',title:'Failed to remove SAML configuration'}); });
  };

  if(loading) return <LoadingPage/>;

  var org = window.DATA.ORG;

  return (
    <div className="grid" style={{gap:18,maxWidth:900}}>
      <PageHead desc="Organization details and default routing behavior."/>
      <SectionCard title="Organization">
        <div className="grid" style={{gridTemplateColumns:'1fr 1fr',gap:16}}>
          <Field label="Organization name"><input className="input" value={org.name} readOnly/></Field>
          {org.id && <Field label="Organization ID"><input className="input input-mono" value={org.id} readOnly/></Field>}
        </div>
      </SectionCard>
      {ent && <SectionCard title="Plan & features" sub={'Your organization is on the '+((ent.tier||'enterprise').charAt(0).toUpperCase()+(ent.tier||'enterprise').slice(1))+' plan.'}>
        {(function(){
          // Hand-authored display copy ONLY — which features exist and their
          // required tier come live from ent.features/ent.required_tiers
          // (GET /v1/customer/entitlements), not from this map. A feature
          // key with no entry here still renders via the `||k` fallback
          // below, so a newly added backend Feature always shows up.
          var FEATURE_LABELS={
            routing:'Routing',fusion:'Fusion routing',compression:'Compression',workspaces:'Workspaces',
            cache_l1:'L1 cache',cache_l2:'Semantic cache',byok:'BYOK keys',mcp:'MCP endpoint',webhooks:'Webhooks',
            alerts:'Alerts',audit_log:'Audit log',scoped_keys:'Scoped keys',encryption_at_rest:'Encryption at rest',
            erasure:'Erasure / RTBF',sso_oidc:'SSO (OIDC)',sso_saml:'SSO (SAML)',ccr:'Conversation retrieval (CCR)',
            cmek:'CMEK',otel:'OpenTelemetry',custom_provider:'Custom provider',dek_rotation:'DEK rotation',
            concise_output:'Concise output',pipeline:'Pipeline chaining',agent_memory:'Agent memory',
            a2a:'A2A (agent-to-agent)',guardrails:'Guardrails',evals:'Evaluation framework',
            fair_share:'Fair-share scheduling',run_budgets:'Run budgets',model_priority_chain:'Model priority chain'
          };
          var TIER_LABELS={basic:'Basic',standard:'Standard',premium:'Premium',enterprise:'Enterprise'};
          var effective=ent.effective_features||[];
          // Derive the row list from the live feature map, not the label map,
          // so every feature the API knows about renders — even ones without
          // a hand-authored label yet.
          var allKeys=Object.keys(ent.features||{});
          return <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(180px,1fr))',gap:'6px 16px',fontSize:13}}>
            {allKeys.map(function(k){
              var included=effective.indexOf(k)!==-1;
              var reqTier=ent.required_tiers&&ent.required_tiers[k];
              return <div key={k} style={{display:'flex',alignItems:'center',gap:6,opacity:included?1:0.5}}>
                <span style={{color:included?'var(--green)':'var(--fg-3)',fontSize:14}}>{included?'✓':'✗'}</span>
                <span>{FEATURE_LABELS[k]||k}</span>
                {!included && reqTier && <Badge color="amber" style={{fontSize:10}}>{TIER_LABELS[reqTier]||reqTier}+</Badge>}
              </div>;
            })}
          </div>;
        })()}
        <div className="faint" style={{fontSize:12,marginTop:8}}>To upgrade your plan, contact <a href="mailto:raman@sislinfotech.com">raman@sislinfotech.com</a>.</div>
      </SectionCard>}
      <SectionCard title="Project context" sub="Standing instructions prepended to every request for your org — project conventions, glossary, tone."
        action={<button className="btn btn-primary btn-sm" disabled={pctxSaving||pctx.length>PCTX_MAX} onClick={savePctx}>{pctxSaving?'Saving…':'Save'}</button>}>
        <Field hint="Max 32 KB. Applies org-wide; individual API keys can override this.">
          <textarea className="input" rows={6} style={{resize:'vertical',fontFamily:'inherit',lineHeight:1.5}}
            placeholder="e.g. We are a fintech team. Prefer concise answers. Our product is called 'Ledgerly'. Always use British English."
            value={pctx} onChange={function(e){setPctx(e.target.value);}}/>
        </Field>
        <div className="row" style={{justifyContent:'flex-end',marginTop:2}}>
          <span className="faint tnum" style={{fontSize:12,color:pctx.length>PCTX_MAX?'var(--red)':undefined}}>{pctx.length.toLocaleString()} / {PCTX_MAX.toLocaleString()}</span>
        </div>
      </SectionCard>
      <SectionCard title="Sprint context" sub="What your team is building right now — current sprint goals, in-flight work, blockers. Appended after Project context on every request; update it weekly without touching the long-lived text above."
        action={<button className="btn btn-primary btn-sm" disabled={sctxSaving||sctx.length>PCTX_MAX} onClick={saveSctx}>{sctxSaving?'Saving…':'Save'}</button>}>
        <Field hint="Max 32 KB. Org-wide. Leave empty to skip this layer.">
          <textarea className="input" rows={5} style={{resize:'vertical',fontFamily:'inherit',lineHeight:1.5}}
            placeholder="e.g. Sprint 12 (Jul 14–25): shipping the payments-reconciliation service. New endpoints live under /v2/recon. The 'ledger-sync' branch is frozen — don't suggest changes there."
            value={sctx} onChange={function(e){setSctx(e.target.value);}}/>
        </Field>
        <div className="row" style={{justifyContent:'flex-end',marginTop:2}}>
          <span className="faint tnum" style={{fontSize:12,color:sctx.length>PCTX_MAX?'var(--red)':undefined}}>{sctx.length.toLocaleString()} / {PCTX_MAX.toLocaleString()}</span>
        </div>
      </SectionCard>
      <SectionCard title="Concise output" sub="Append a brevity directive to every request so models respond concisely and skip filler. Automatically skipped when your request already specifies a style.">
        <div className="spread" style={{padding:'4px 0'}}>
          <div>
            <div style={{fontWeight:600}}>Enable concise output</div>
            <div className="faint" style={{fontSize:12.5}}>Adds a short system-level instruction: answer directly, avoid hedging or repetition.</div>
          </div>
          <Switch on={conciseOutput} onChange={function(val){ setConciseOutput(val); saveConciseOutput(val); }} disabled={coSaving}/>
        </div>
      </SectionCard>
      <SectionCard title="Model priority chain" sub="Restrict routing to an explicit ordered list of models — cascade tries them in order, direct routing scores within them. Leave empty for normal AI-driven routing."
        action={<button className="btn btn-primary btn-sm" disabled={mpcSaving} onClick={function(){saveMpc(mpc);}}>Save chain</button>}>
        <div className="grid" style={{gap:8}}>
          {mpc.length===0 && <div className="faint" style={{fontSize:12.5}}>No chain configured — AI routing selects the best model per request.</div>}
          {mpc.map(function(id,idx){
            return <div key={id} className="spread" style={{padding:'4px 0',borderBottom:'1px solid var(--line)'}}>
              <span className="row" style={{gap:6}}>
                <span style={{color:'var(--fg-3)',fontSize:12,minWidth:18}}>{idx+1}.</span>
                <code style={{fontSize:12.5}}>{id}</code>
              </span>
              <span className="row" style={{gap:4}}>
                <button className="btn btn-ghost btn-sm" style={{padding:'2px 5px'}} disabled={idx===0} onClick={function(){mpcMove(idx,-1);}}>↑</button>
                <button className="btn btn-ghost btn-sm" style={{padding:'2px 5px'}} disabled={idx===mpc.length-1} onClick={function(){mpcMove(idx,1);}}>↓</button>
                <button className="btn btn-ghost btn-sm" style={{padding:'2px 5px',color:'var(--red)'}} onClick={function(){mpcRemove(idx);}}>×</button>
              </span>
            </div>;
          })}
          {mpc.length<10 && <div className="row" style={{gap:8,marginTop:4}}>
            <input className="input mono" style={{flex:1,fontSize:12.5}} placeholder="e.g. gpt-4o-mini, claude-haiku-3, gemma-3-12b-it"
              value={mpcNewModel} onChange={function(e){setMpcNewModel(e.target.value);}}
              onKeyDown={function(e){if(e.key==='Enter'){mpcAdd();}}}/>
            <button className="btn btn-soft btn-sm" onClick={mpcAdd}>+ Add</button>
          </div>}
          {mpc.length>0 && <div className="faint" style={{fontSize:11.5,marginTop:2}}>Clear all entries and save to restore normal AI routing.</div>}
        </div>
      </SectionCard>
      <SectionCard title={<span>Guardrails <Badge color="amber" style={{fontSize:10}}>beta</Badge></span>}
        sub="Content-safety checks on requests (PII, secrets, prompt-injection, moderation, vision, length, custom rules) and responses (JSON schema, denylist, length). Flags/blocks show up in Logs."
        action={<button className="btn btn-primary btn-sm" disabled={grSaving} onClick={saveGuardrails}>{grSaving?'Saving…':'Save'}</button>}>
        <div className="spread" style={{padding:'4px 0'}}>
          <div><div style={{fontWeight:600}}>Enable guardrails</div><div className="faint" style={{fontSize:12.5}}>Off = no checks run for your org.</div></div>
          <Switch on={grEnabled} onChange={setGrEnabled}/>
        </div>
        {grEnabled && <div style={{marginTop:4}}>
          <button type="button" className="btn btn-ghost btn-sm" style={{padding:'2px 4px',height:'auto'}}
            onClick={function(){setGrShowRules(!grShowRules);}}>
            <Icon name={grShowRules?'chevdown':'chevron'} size={12}/>
            {grShowRules?'Hide rule configuration':'Configure rules'}
          </button>
          {grShowRules && <div className="codeblock" style={{fontSize:12,lineHeight:1.5,marginTop:8}}>
            {['input','output'].map(function(phase){
              return <div key={phase}>
                <div className="faint" style={{fontSize:10.5,textTransform:'uppercase',letterSpacing:'.04em',margin:'10px 0 2px',opacity:.7}}>
                  {phase==='input'?'Input rules (checked before routing)':'Output rules (checked on the model response)'}
                </div>
                {grRows.filter(function(row){return row.phase===phase;}).map(function(row){
                  var idx = grRows.indexOf(row);
                  function patchRow(patch){
                    setGrRows(grRows.map(function(r,i){return i===idx?Object.assign({},r,patch):r;}));
                  }
                  return (
                  <div key={row.name} style={{padding:'8px 0',borderTop:'1px solid rgba(128,128,128,.2)'}}>
                    <div className="spread">
                      <div style={{display:'flex',alignItems:'flex-start',gap:8}}>
                        <input type="checkbox" style={{marginTop:3}} checked={row.enabled} onChange={function(e){patchRow({enabled:e.target.checked});}}/>
                        <div>
                          <div style={{fontWeight:600}}>{row.label}</div>
                          <div className="faint" style={{fontSize:11}}>{row.desc}</div>
                        </div>
                      </div>
                      <select className="select" style={{minWidth:100}} disabled={!row.enabled} value={row.action} onChange={function(e){patchRow({action:e.target.value});}}>
                        <option value="flag">Flag</option>
                        <option value="redact">Redact</option>
                        <option value="block">Block</option>
                      </select>
                    </div>
                    {row.enabled && (row.name==='length-cap'||row.name==='output-length-cap') && <div style={{marginTop:6,marginLeft:24,maxWidth:200}}>
                      <Field label="Max characters"><input className="input" type="number" min="1" step="1000" value={row.maxChars} onChange={function(e){patchRow({maxChars:e.target.value});}}/></Field>
                    </div>}
                    {row.enabled && (row.name==='denylist'||row.name==='output-denylist') && <div style={{marginTop:6,marginLeft:24}}>
                      <Field label="Patterns (one per line, regex)"><textarea className="input mono" rows={3} style={{fontSize:11.5,width:'100%'}} placeholder={'e.g.\nproject-codename-x\ninternal-only'} value={row.patterns} onChange={function(e){patchRow({patterns:e.target.value});}}/></Field>
                    </div>}
                    {row.enabled && row.name==='json-schema' && <div style={{marginTop:6,marginLeft:24}}>
                      <Field label="Required top-level JSON keys (comma-separated)" hint="Leave blank to only check the response is valid JSON.">
                        <input className="input" placeholder="e.g. name, amount" value={row.required} onChange={function(e){patchRow({required:e.target.value});}}/>
                      </Field>
                    </div>}
                    {row.enabled && row.name==='webhook' && <div style={{marginTop:6,marginLeft:24,display:'grid',gap:8}}>
                      <Field label="Endpoint URL"><input className="input mono" placeholder="https://yourapp.example.com/guardrail" value={row.webhookUrl} onChange={function(e){patchRow({webhookUrl:e.target.value});}}/></Field>
                      <Field label="Signing secret" hint="Used to HMAC-SHA256 sign each request (header X-NeuroRoute-Signature)."><input className="input mono" type="password" placeholder="shared secret" value={row.webhookSecret} onChange={function(e){patchRow({webhookSecret:e.target.value});}}/></Field>
                    </div>}
                    {row.enabled && row.name==='moderation' && <div style={{marginTop:6,marginLeft:24}}>
                      <Field label="System prompt override (optional)" hint="Leave blank to use the default binary safety classifier prompt.">
                        <textarea className="input mono" rows={2} style={{fontSize:11.5,width:'100%'}} value={row.systemPrompt} onChange={function(e){patchRow({systemPrompt:e.target.value});}}/>
                      </Field>
                    </div>}
                    {row.enabled && row.name==='vision' && <div style={{marginTop:6,marginLeft:24,display:'grid',gap:8}}>
                      <Field label="Max image size (bytes)" hint="Blank = default 10 MB. -1 = unlimited.">
                        <input className="input" type="number" step="1" placeholder="10485760" value={row.maxImageSizeBytes} onChange={function(e){patchRow({maxImageSizeBytes:e.target.value});}}/>
                      </Field>
                      <Field label="Allowed MIME types (comma-separated)" hint="Blank = allow all standard image types (jpeg/png/gif/webp/bmp/tiff/svg+xml).">
                        <input className="input mono" placeholder="e.g. image/png, image/jpeg" value={row.allowedMimeTypes} onChange={function(e){patchRow({allowedMimeTypes:e.target.value});}}/>
                      </Field>
                    </div>}
                  </div>
                  );
                })}
              </div>;
            })}
            {grRows.filter(function(r){return r.__unknownRule;}).length>0 && <div className="faint" style={{fontSize:11,marginTop:10,paddingTop:8,borderTop:'1px solid rgba(128,128,128,.2)'}}>
              {grRows.filter(function(r){return r.__unknownRule;}).length} rule(s) configured outside this UI ({grRows.filter(function(r){return r.__unknownRule;}).map(function(r){return r.name;}).join(', ')}) are already active for your org and will be preserved when you save.
            </div>}
          </div>}
        </div>}
      </SectionCard>
      <SectionCard title={<span>Single sign-on (OIDC) <Badge color="amber" style={{fontSize:10}}>beta</Badge></span>}
        sub="Bring your own identity provider (Okta, Azure AD, or any standards-compliant OIDC IdP) for your organization's email domain."
        action={<button className="btn btn-primary btn-sm" disabled={ssoSaving||!ssoDomain.trim()||!ssoIssuer.trim()||!ssoClientId.trim()} onClick={saveSSO}>{ssoSaving?'Saving…':'Save'}</button>}>
        <div className="grid" style={{gap:14}}>
          {sso&&sso.configured && <div className="spread" style={{padding:'2px 0'}}>
            <div><div style={{fontWeight:600}}>Status</div><div className="faint" style={{fontSize:12.5}}>Configured for @{sso.domain}</div></div>
            <Badge color={ssoEnabled?'green':'gray'} dot>{ssoEnabled?'Enabled':'Disabled'}</Badge>
          </div>}
          <div className="grid" style={{gridTemplateColumns:'1fr 1fr',gap:14}}>
            <Field label="Email domain" hint="Users with this email domain sign in via your IdP.">
              <input className="input" placeholder="acme.com" value={ssoDomain} onChange={function(e){setSsoDomain(e.target.value);}}/>
            </Field>
            <Field label="Provider label" hint="Display name only, e.g. Okta or Azure AD.">
              <input className="input" placeholder="Okta" value={ssoLabel} onChange={function(e){setSsoLabel(e.target.value);}}/>
            </Field>
          </div>
          <Field label="Issuer URL" hint="Your IdP's OIDC issuer, e.g. https://acme.okta.com or https://login.microsoftonline.com/{tenant}/v2.0">
            <input className="input mono" placeholder="https://acme.okta.com" value={ssoIssuer} onChange={function(e){setSsoIssuer(e.target.value);}}/>
          </Field>
          <div className="grid" style={{gridTemplateColumns:'1fr 1fr',gap:14}}>
            <Field label="Client ID"><input className="input mono" value={ssoClientId} onChange={function(e){setSsoClientId(e.target.value);}}/></Field>
            <Field label="Client secret" hint={sso&&sso.configured?'Leave blank to keep the existing secret.':'Required on first setup.'}>
              <input className="input mono" type="password" placeholder={sso&&sso.configured?'••••••••':''} value={ssoClientSecret} onChange={function(e){setSsoClientSecret(e.target.value);}}/>
            </Field>
          </div>
          <div className="spread" style={{padding:'2px 0'}}>
            <div><div style={{fontWeight:600}}>Enabled</div><div className="faint" style={{fontSize:12.5}}>Off = users on this domain fall back to email/Google sign-in.</div></div>
            <Switch on={ssoEnabled} onChange={setSsoEnabled}/>
          </div>
          {sso&&sso.configured && <div className="row" style={{justifyContent:'flex-end'}}>
            <button className="btn btn-ghost btn-sm" style={{color:'var(--red)'}} onClick={deleteSSO}>Remove SSO configuration</button>
          </div>}
        </div>
      </SectionCard>
      <SectionCard title={<span>Single sign-on (SAML 2.0) <Badge color="amber" style={{fontSize:10}}>beta</Badge></span>}
        sub="SP-initiated SAML 2.0 SSO for your organization's email domain — for identity providers that don't speak OIDC (e.g. legacy Azure AD / ADFS, some Okta configurations)."
        action={<button className="btn btn-primary btn-sm" disabled={samlSaving||!samlDomain.trim()||(!samlMetadataUrl.trim()&&!samlMetadataXml.trim())} onClick={saveSAML}>{samlSaving?'Saving…':'Save'}</button>}>
        <div className="grid" style={{gap:14}}>
          {saml&&saml.configured && <div className="spread" style={{padding:'2px 0'}}>
            <div><div style={{fontWeight:600}}>Status</div><div className="faint" style={{fontSize:12.5}}>Configured for @{saml.domain}</div></div>
            <Badge color={samlEnabled?'green':'gray'} dot>{samlEnabled?'Enabled':'Disabled'}</Badge>
          </div>}
          <div className="grid" style={{gridTemplateColumns:'1fr 1fr',gap:14}}>
            <Field label="Email domain" hint="Users with this email domain sign in via your IdP.">
              <input className="input" placeholder="acme.com" value={samlDomain} onChange={function(e){setSamlDomain(e.target.value);}}/>
            </Field>
            <Field label="Provider label" hint="Display name only, e.g. Okta or ADFS.">
              <input className="input" placeholder="Okta" value={samlLabel} onChange={function(e){setSamlLabel(e.target.value);}}/>
            </Field>
          </div>
          <Field label="IdP metadata URL" hint="Your IdP's SAML metadata XML, fetched over HTTPS. Provide this OR paste the metadata XML directly below.">
            <input className="input mono" placeholder="https://acme.okta.com/app/.../sso/saml/metadata" value={samlMetadataUrl} onChange={function(e){setSamlMetadataUrl(e.target.value);}}/>
          </Field>
          <Field label="IdP metadata XML" hint={saml&&saml.has_metadata_xml?'Metadata XML is already configured. Leave blank to keep it, or paste new XML to replace it (max 512 KB).':'Paste your IdP\'s SAML metadata XML here if you are not using a metadata URL (max 512 KB).'}>
            <textarea className="input mono" rows={5} style={{resize:'vertical',fontSize:12}}
              placeholder={saml&&saml.has_metadata_xml?'<EntityDescriptor ...> (leave blank to keep existing)':'<EntityDescriptor ...>'}
              value={samlMetadataXml} onChange={function(e){setSamlMetadataXml(e.target.value);}}/>
          </Field>
          <div className="spread" style={{padding:'2px 0'}}>
            <div><div style={{fontWeight:600}}>Enabled</div><div className="faint" style={{fontSize:12.5}}>Off = users on this domain fall back to email/Google sign-in.</div></div>
            <Switch on={samlEnabled} onChange={setSamlEnabled}/>
          </div>
          {saml&&saml.configured && <div className="row" style={{justifyContent:'flex-end'}}>
            <button className="btn btn-ghost btn-sm" style={{color:'var(--red)'}} onClick={deleteSAML}>Remove SAML configuration</button>
          </div>}
        </div>
      </SectionCard>
      <SectionCard title={<span>Routing config <Badge color="amber" style={{fontSize:10}}>beta</Badge></span>}
        sub="Config-as-code: JSON rules that pin a model (or A/B-split traffic between models) by request metadata or workspace — bypasses normal scoring when matched."
        action={<button className="btn btn-primary btn-sm" disabled={rcSaving} onClick={saveRoutingConfig}>{rcSaving?'Publishing…':'Publish'}</button>}>
        <div className="grid" style={{gap:12}}>
          {rcConfigured && <div className="spread" style={{padding:'2px 0'}}>
            <div><div style={{fontWeight:600}}>Active version</div><div className="faint" style={{fontSize:12.5}}>Takes effect immediately for new auto-routed requests.</div></div>
            <Badge color="blue" style={{fontSize:13,padding:'4px 10px'}}>v{rcVersion}</Badge>
          </div>}
          <Field hint={'Each rule: {"name","match":{"metadata":{...}, "workspace_id":"..."},"action":{"type":"pin"|"weighted","model":"...","weights":{...}}}. First matching rule wins.'}>
            <textarea className="input mono" rows={12} style={{resize:'vertical',fontSize:12.5,lineHeight:1.5}}
              spellCheck={false} value={rcRaw} onChange={function(e){setRcRaw(e.target.value);}}/>
          </Field>
          {rcError && <div className="faint" style={{color:'var(--red)',fontSize:12.5}}>{rcError}</div>}
          {rcVersions.length>0 && <div style={{marginTop:4}}>
            <div className="faint" style={{fontSize:10.5,textTransform:'uppercase',letterSpacing:'.04em',marginBottom:6,opacity:.7}}>Version history</div>
            <table className="table">
              <thead><tr><th>Version</th><th>Published</th><th>By</th><th style={{textAlign:'right'}}>Actions</th></tr></thead>
              <tbody>
                {rcVersions.map(function(v){
                  return <tr key={v.version}>
                    <td style={{color:'var(--tx-0)',fontWeight:600}}>v{v.version}{v.version===rcVersion?<Badge color="green" style={{marginLeft:8,fontSize:10}}>active</Badge>:null}</td>
                    <td className="faint">{timeAgo(v.created_at)||v.created_at}</td>
                    <td className="faint">{v.created_by||'—'}</td>
                    <td style={{textAlign:'right'}}>
                      {v.version!==rcVersion && <button className="btn btn-soft btn-sm" onClick={function(){activateRoutingVersion(v.version);}}>Activate</button>}
                    </td>
                  </tr>;
                })}
              </tbody>
            </table>
          </div>}
        </div>
      </SectionCard>
      <SectionCard title={<span>Event webhooks <Badge color="amber" style={{fontSize:10}}>beta</Badge></span>}
        sub="Outbound HTTP notifications on discrete lifecycle events — a budget cap tripping, an erasure request completing, a new API key being created."
        action={<button className="btn btn-primary btn-sm" disabled={ewhSaving||!ewhUrl.trim()} onClick={saveEventWebhook}>{ewhSaving?'Saving…':'Save'}</button>}>
        <div className="grid" style={{gap:14}}>
          {ewh&&ewh.configured && <div className="spread" style={{padding:'2px 0'}}>
            <div><div style={{fontWeight:600}}>Status</div><div className="faint" style={{fontSize:12.5}}>Signed via HMAC-SHA256 (X-NeuroRoute-Signature header).</div></div>
            <Badge color={ewhEnabled?'green':'gray'} dot>{ewhEnabled?'Enabled':'Disabled'}</Badge>
          </div>}
          <Field label="Endpoint URL"><input className="input mono" placeholder="https://your-service.example.com/webhooks/neuroroute" value={ewhUrl} onChange={function(e){setEwhUrl(e.target.value);}}/></Field>
          <Field label="Signing secret" hint={ewh&&ewh.configured?'Leave blank to keep the existing secret.':'Required on first setup — used to verify the X-NeuroRoute-Signature header.'}>
            <input className="input mono" type="password" placeholder={ewh&&ewh.configured?'••••••••':''} value={ewhSecret} onChange={function(e){setEwhSecret(e.target.value);}}/>
          </Field>
          <Field label="Events">
            <div className="grid" style={{gap:8}}>
              {EVENT_TYPES.map(function(pair){
                var val=pair[0], label=pair[1];
                return <label key={val} className="row" style={{gap:8,alignItems:'center',fontSize:13}}>
                  <input type="checkbox" checked={ewhEvents.indexOf(val)!==-1} onChange={function(){toggleEwhEvent(val);}}/>
                  {label} <code className="faint" style={{fontSize:11}}>{val}</code>
                </label>;
              })}
            </div>
          </Field>
          <div className="spread" style={{padding:'2px 0'}}>
            <div><div style={{fontWeight:600}}>Enabled</div><div className="faint" style={{fontSize:12.5}}>Off = configured but no deliveries sent.</div></div>
            <Switch on={ewhEnabled} onChange={setEwhEnabled}/>
          </div>
          {ewh&&ewh.configured && <div className="row" style={{justifyContent:'flex-end'}}>
            <button className="btn btn-ghost btn-sm" style={{color:'var(--red)'}} onClick={deleteEventWebhook}>Remove event webhook</button>
          </div>}
        </div>
      </SectionCard>
      <SectionCard title="Scheduled usage export" sub="Automatically export usage data to cloud storage on a recurring cadence, in addition to the on-demand export above.">
        <div className="spread" style={{padding:'2px 0'}}>
          <div><div style={{fontWeight:600}}>Cadence</div>
            <div className="faint" style={{fontSize:12.5}}>{uexLastRun ? ('Last exported '+(timeAgo(uexLastRun)||uexLastRun)) : 'Not run yet.'}</div></div>
          <select className="select" style={{minWidth:140}} disabled={uexSaving} value={uexSchedule} onChange={function(e){saveUsageExportSchedule(e.target.value);}}>
            <option value="">Off</option>
            <option value="daily">Daily</option>
            <option value="weekly">Weekly</option>
          </select>
        </div>
      </SectionCard>
      <SectionCard title="Alerts" sub="Get notified on budget thresholds, error-rate spikes, latency, spend anomalies, or provider health flips.">
        <AlertsPanel/>
      </SectionCard>
      <SectionCard title="Data & privacy" sub="Export everything we hold for your organization.">
        <div className="spread" style={{gap:16}}>
          <div><div style={{fontWeight:600}}>Download my data (JSON)</div>
            <div className="faint" style={{fontSize:12.5}}>GDPR Art. 20 — everything we hold for your org, machine-readable.</div></div>
          <button className="btn btn-soft btn-sm" onClick={function(){ window.open('/v1/customer/export','_blank'); }}><Icon name="download" size={14}/>Download JSON</button>
        </div>
      </SectionCard>
      <SectionCard title="Data retention" sub="Controls what NeuroRoute stores about your organization's traffic. Proven per-request via the X-Data-Retention response header."
        action={<button className="btn btn-primary btn-sm" disabled={drSaving} onClick={saveDataRetention}>{drSaving?'Saving…':'Save'}</button>}>
        <div className="grid" style={{gap:16}}>
          <Field label="Retention mode" hint="Zero modes store no prompts/responses platform-side; strict also disables provider prompt caching.">
            <select className="select" value={drMode} onChange={function(e){setDrMode(e.target.value);}}>
              <option value="zero-strict">Zero — strict (no provider caching)</option>
              <option value="zero">Zero — platform stores nothing</option>
              <option value="retain">Retain content N days</option>
            </select>
          </Field>
          {drMode==='retain' && <Field label="Retention window (days)" hint="Content older than this is deleted daily. 1-365.">
            <input className="input" type="number" min="1" max="365" step="1" value={drDays} onChange={function(e){setDrDays(e.target.value);}}/>
          </Field>}
          {drMode==='retain' && <Field label="Request content logging" hint="Metadata-only (default) never stores prompts/responses. Content mode encrypts and stores them under your org's key, viewable in Logs.">
            <select className="select" value={drLogMode} onChange={function(e){setDrLogMode(e.target.value);}}>
              <option value="metadata">Metadata only (default)</option>
              <option value="content">Content — store encrypted prompt + response</option>
            </select>
          </Field>}
        </div>
      </SectionCard>
      {ent && <SectionCard title="Customer-managed encryption key (CMEK)"
        sub={cmekEntitled ? "Encrypt your stored data at rest with a key in your own Cloud KMS project. Revoking our access is your instant kill switch." : undefined}>
        {!cmekEntitled ? (
          <div className="faint" style={{fontSize:12.5}}>
            Requires the Enterprise plan <Badge color="amber" style={{fontSize:10,marginLeft:2}}>Enterprise+</Badge>. Contact <a href="mailto:raman@sislinfotech.com">raman@sislinfotech.com</a> to enable.
          </div>
        ) : (
          <div className="grid" style={{gap:10}}>
            <Field label="KMS key resource name" hint="Full Cloud KMS key resource name in YOUR project (projects/P/locations/L/keyRings/R/cryptoKeys/K), granted to our service account. Blank = platform-managed key.">
              <input className="input mono" style={{fontSize:12}} placeholder="Platform key (default)" value={cmek} onChange={function(e){setCmek(e.target.value);}}/>
            </Field>
            <div className="row" style={{justifyContent:'flex-end'}}>
              <button className="btn btn-primary btn-sm" disabled={cmekSaving} onClick={saveCMEK}>{cmekSaving?'Saving…':'Save'}</button>
            </div>
          </div>
        )}
      </SectionCard>}
      <SectionCard title="Routing preferences" sub="Current server-side defaults (read-only). Per-request override via X-Routing-Strategy header.">
        <div className="grid" style={{gap:20}}>
          <div className="spread"><div><div style={{fontWeight:600}}>Default strategy</div><div className="faint" style={{fontSize:12.5}}>Applied when a request doesn't specify its own.</div></div>
            <Badge color="blue" style={{fontSize:13,padding:'4px 10px'}}>{strategy}</Badge></div>
          <hr className="divider"/>
          <div className="spread"><div><div style={{fontWeight:600}}>Quality threshold</div><div className="faint" style={{fontSize:12.5}}>Minimum quality score a model must clear.</div></div>
            <span className="display tnum" style={{fontSize:22}}>{quality}</span></div>
        </div>
      </SectionCard>
      {config && <SectionCard title="Provider status" sub="Configured providers and live model counts (admin view).">
        <div className="grid" style={{gap:8}}>
          {(config.providers||[]).map(function(p){
            return <div key={p.id} className="spread" style={{padding:'8px 0',borderBottom:'1px solid var(--line)'}}>
              <span className="row" style={{gap:9}}><ProviderLogo id={p.id} size={22}/><span style={{fontWeight:600,fontSize:13}}>{p.name}</span></span>
              <span className="row" style={{gap:10}}>
                {p.role==='failover'
                  ? <span className="faint" style={{fontSize:12}}>Failover backend</span>
                  : (p.configured && <span className="faint mono" style={{fontSize:12}}>{p.model_count} model{p.model_count===1?'':'s'}</span>)}
                <Badge color={p.configured?'green':'gray'} dot>{p.configured?'Configured':'Not set'}</Badge>
              </span>
            </div>;
          })}
        </div>
      </SectionCard>}
      {config && <SectionCard title="Platform features" sub="Subsystems active on this gateway.">
        <div className="grid" style={{gridTemplateColumns:'1fr 1fr',gap:10}}>
          {[['Semantic cache', (config.routing||{}).cache_enabled],
            ['PII policy gate', (config.routing||{}).pii_gate_enabled],
            ['Context manager', (config.features||{}).context_manager],
            ['Usage tracking', (config.features||{}).usage_tracking]].map(function(pair){
            return <div key={pair[0]} className="spread" style={{padding:'8px 0',borderBottom:'1px solid var(--line)'}}>
              <span className="faint" style={{fontSize:12.5}}>{pair[0]}</span>
              <Badge color={pair[1]?'green':'gray'} dot>{pair[1]?'On':'Off'}</Badge>
            </div>;
          })}
        </div>
      </SectionCard>}
    </div>
  );
}

/* ── A2A Agent Registry (customer-facing, G.3 / I-5a) ────────────────────
   This used to live only in the SISL admin nav even though /a2a/agents is
   org-scoped (internal/gateway/a2a_endpoints.go reads AuthContext.OrgID,
   not an admin-supplied {org_id} — there is no cross-org A2A path at all),
   and its only entitlement-gated capability (POST /a2a/agents/{id}/tasks,
   task dispatch) is FeatureA2A, a Premium+ CUSTOMER entitlement — so a
   Premium customer had no way to register their own agents; only a SISL
   admin could, and only for whatever org THEIR OWN login belongs to (i.e.
   SISL's own internal org), not on a customer's behalf.
   No separate admin variant was kept: since the backend has zero cross-org
   read/write capability here (unlike price-terms or the org PATCH, which
   take an explicit {org_id}), an "admin view" would not add any SISL-
   support cross-org visibility beyond what a SISL admin already gets by
   visiting this exact customer page — sisl_admin/admin roles already see
   the full customer nav (see allowedRoutesFor in app.jsx returning null
   for those roles), so nothing was lost by removing the admin.jsx copy.
   Note CRUD (list/create/update/delete) is NOT entitlement-gated on the
   backend at all — only task dispatch is Premium+ — so the banner below is
   informational, not a functional lock; blocking the whole page here would
   misrepresent what the backend actually allows. */
function A2APage(){
  var t=useToast();
  var _ent=useState(null); var ent=_ent[0], setEnt=_ent[1];
  var _agents=useState([]); var agents=_agents[0], setAgents=_agents[1];
  var _loading=useState(true); var loading=_loading[0], setLoading=_loading[1];
  var _loadFailed=useState(false); var loadFailed=_loadFailed[0], setLoadFailed=_loadFailed[1];
  var _editing=useState(null); var editing=_editing[0], setEditing=_editing[1];
  var _form=useState({agent_id:'',display_name:'',description:'',prompt_slug:'',routing_config:'',model_pin:'',is_public:false});
  var form=_form[0], setForm=_form[1];

  var load=function(){
    setLoading(true); setLoadFailed(false);
    // NR_API.listA2AAgents() is api()-backed (data.js): it resolves to null
    // on ANY non-2xx status OR a network failure, and never rejects — so a
    // .catch() here would be dead code. Detect failure via the null result
    // instead, matching evals.jsx's EvalLoadError/Retry convention.
    NR_API.listA2AAgents(true).then(function(r){
      if(r===null){ setLoadFailed(true); } else { setAgents(r.agents||[]); }
      setLoading(false);
    });
  };
  useEffect(function(){
    NR_API.entitlements().then(function(res){ if(res) setEnt(res); }).catch(function(){});
    load();
  },[]);

  var startEdit=function(ag){
    setEditing(ag.agent_id);
    setForm({agent_id:ag.agent_id,display_name:ag.display_name||'',description:ag.description||'',
      prompt_slug:ag.prompt_slug||'',routing_config:ag.routing_config||'',model_pin:ag.model_pin||'',is_public:ag.is_public||false});
  };
  var startNew=function(){setEditing('__new__');setForm({agent_id:'',display_name:'',description:'',prompt_slug:'',routing_config:'',model_pin:'',is_public:false});};
  var cancel=function(){setEditing(null);};

  var save=function(){
    if(!form.agent_id||!form.display_name){t({kind:'error',title:'agent_id and display_name are required'});return;}
    var p={agent_id:form.agent_id,display_name:form.display_name,description:form.description,
      prompt_slug:form.prompt_slug||undefined,routing_config:form.routing_config||undefined,
      model_pin:form.model_pin||undefined,is_public:form.is_public};
    var call=editing==='__new__'?NR_API.createA2AAgent(p):NR_API.updateA2AAgent(form.agent_id,p);
    call.then(function(r){
      if(r&&r.agent_id){t({title:(editing==='__new__'?'Agent created':'Agent updated'),msg:r.agent_id});setEditing(null);load();}
      else{t({kind:'error',title:'Save failed'});}
    }).catch(function(){t({kind:'error',title:'Save failed'});});
  };

  var del=function(agentId){
    if(!window.confirm('Delete agent '+agentId+'?'))return;
    NR_API.deleteA2AAgent(agentId).then(function(ok){
      if(ok){t({title:'Deleted',msg:agentId});load();}else{t({kind:'error',title:'Delete failed'});}
    });
  };

  var setField=function(k){return function(e){setForm(function(f){return Object.assign({},f,{[k]:e.target.type==='checkbox'?e.target.checked:e.target.value});});};};

  if(loading) return <LoadingPage/>;

  // effective_features is only meaningful once `ent` has loaded; fail-open
  // (treat as entitled) while it's still null so the page doesn't flash a
  // false "Premium required" banner before the entitlements call returns.
  var dispatchEntitled = !ent || (ent.effective_features||[]).indexOf('a2a')!==-1;

  return (
    <div className="grid" style={{gap:18}}>
      <PageHead desc="Registered A2A agents. Each agent exposes a task dispatch endpoint compatible with the Google A2A spec (POST /a2a/agents/{id}/tasks)."/>
      {!dispatchEntitled && <div className="card card-pad row" style={{gap:12,background:'var(--amber-t)',borderColor:'rgba(245,158,11,.32)'}}>
        <Icon name="lock" size={18} style={{color:'var(--amber)'}}/>
        <span style={{fontSize:13.5}}>You can register and manage agents on any plan, but <b>dispatching a task</b> to one requires the <b>Premium</b> plan. <a href="mailto:raman@sislinfotech.com">Contact sales</a> to upgrade.</span>
      </div>}
      <SectionCard title="Agent registry" action={<button className="btn btn-sm btn-primary" onClick={startNew}>+ New agent</button>} pad={false}>
        {loadFailed ? <EvalLoadError what="your A2A agents" onRetry={load}/> :
         agents.length===0 ? <EmptyState icon="route" title="No agents" desc="Create an agent to enable A2A task dispatch."/> :
        <div className="scroll-x"><table className="table">
          <thead><tr><th>ID</th><th>Name</th><th>Model / template</th><th>Public</th><th></th></tr></thead>
          <tbody>{agents.map(function(ag){return(
            <tr key={ag.id}>
              <td className="mono" style={{fontSize:12}}>{ag.agent_id}</td>
              <td>{ag.display_name}</td>
              <td className="faint" style={{fontSize:12}}>{ag.model_pin||ag.prompt_slug||'auto'}</td>
              <td>{ag.is_public?<Badge color="green">public</Badge>:<span className="faint">private</span>}</td>
              <td>
                <button className="btn btn-xs btn-soft" onClick={function(){startEdit(ag);}}>Edit</button>{' '}
                <button className="btn btn-xs btn-danger" onClick={function(){del(ag.agent_id);}}>Del</button>
              </td>
            </tr>
          );})}</tbody>
        </table></div>}
      </SectionCard>
      {editing&&(
        <SectionCard title={editing==='__new__'?'New agent':'Edit agent: '+editing}>
          <div className="grid" style={{gap:12}}>
            <div className="row" style={{gap:10,flexWrap:'wrap'}}>
              <div style={{flex:'0 0 160px'}}>
                <Field label="agent_id (slug)">
                  <input className="input" value={form.agent_id} disabled={editing!=='__new__'} onChange={setField('agent_id')} placeholder="summarizer"/>
                </Field>
              </div>
              <div style={{flex:'1 1 200px'}}>
                <Field label="Display name">
                  <input className="input" value={form.display_name} onChange={setField('display_name')} placeholder="Document Summarizer"/>
                </Field>
              </div>
            </div>
            <Field label="Description">
              <input className="input" value={form.description} onChange={setField('description')} placeholder="Summarizes uploaded documents"/>
            </Field>
            <div className="row" style={{gap:10,flexWrap:'wrap'}}>
              <div style={{flex:'1 1 160px'}}>
                <Field label="Model pin (optional)">
                  <input className="input" value={form.model_pin} onChange={setField('model_pin')} placeholder="auto"/>
                </Field>
              </div>
              <div style={{flex:'1 1 160px'}}>
                <Field label="Prompt slug (optional)">
                  <input className="input" value={form.prompt_slug} onChange={setField('prompt_slug')} placeholder="my-template"/>
                </Field>
              </div>
              <div style={{flex:'1 1 200px'}}>
                <Field label="Routing config UUID (optional)">
                  <input className="input" value={form.routing_config} onChange={setField('routing_config')} placeholder="uuid"/>
                </Field>
              </div>
            </div>
            <div>
              <label style={{display:'flex',alignItems:'center',gap:8,cursor:'pointer'}}>
                <input type="checkbox" checked={form.is_public} onChange={setField('is_public')}/>
                <span>Public — discoverable by other orgs</span>
              </label>
            </div>
            <div className="row" style={{gap:8}}>
              <button className="btn btn-primary" onClick={save}>Save</button>
              <button className="btn btn-ghost" onClick={cancel}>Cancel</button>
            </div>
          </div>
        </SectionCard>
      )}
    </div>
  );
}

window.PAGES = Object.assign(window.PAGES||{}, {team:TeamPage, settings:SettingsPage, a2a:A2APage});
