// Vyuu admin console — MCP Invocation Policies, MCP Catalog v2, Create Rule drawer, Device detail drawer, Relation graph
const { X, Search: SearchIcon, Upload, Plus, FileCode, Users, User, Shield: ShieldIcon,
  Clock: ClockIcon, HardDrive: HDIcon, Cpu: CpuIcon, Wifi, Battery, MapPin,
  Terminal: TerminalIcon, Github: GithubIcon, Database: DBIcon, FileText: FileIcon,
  Mail: MailIcon, Box: BoxIcon, Cloud: CloudIcon, Slack, Figma, Chrome,
  ChevronDown: ChevronDownV2, Check: CheckV2, AlertTriangle: AlertV2,
  MoreHorizontal: MoreH2, Filter: FilterV2, Download: DLIcon, Trash2: TrashV2,
  Copy, Zap } = window.LucideReact;

// ─────────────────────────────────────────────────────────────────
// Drawer shell (right-side slide-over)
// ─────────────────────────────────────────────────────────────────
const Drawer = ({open, onClose, width=560, children}) => (
  <>
    <div onClick={onClose} style={{
      position:'fixed', inset:0, background:'rgba(31,42,46,0.28)',
      opacity: open?1:0, pointerEvents: open?'auto':'none',
      transition:'opacity .18s', zIndex:100,
    }}/>
    <aside style={{
      position:'fixed', top:0, right:0, bottom:0, width, maxWidth:'96vw',
      background:theme.bg, borderLeft:`1px solid ${theme.line}`,
      transform: open?'translateX(0)':'translateX(100%)',
      transition:'transform .22s cubic-bezier(.2,.7,.2,1)', zIndex:101,
      display:'flex', flexDirection:'column',
      boxShadow: open ? '-24px 0 60px rgba(31,42,46,0.12)' : 'none',
    }}>
      {children}
    </aside>
  </>
);
const DrawerHeader = ({title, eyebrow, onClose, actions}) => (
  <div style={{padding:'20px 24px', borderBottom:`1px solid ${theme.line}`, display:'flex', alignItems:'flex-start', justifyContent:'space-between', gap:12, background:theme.panel}}>
    <div>
      {eyebrow && <div style={{fontSize:10, letterSpacing:2.2, textTransform:'uppercase', color:theme.orangeDeep, fontWeight:600, marginBottom:6}}>{eyebrow}</div>}
      <div style={{fontFamily:theme.serif, fontSize:22, color:theme.ink, letterSpacing:-0.3, fontWeight:500, lineHeight:1.15}}>{title}</div>
    </div>
    <div style={{display:'flex', gap:8, alignItems:'center'}}>
      {actions}
      <button onClick={onClose} style={{background:'transparent', border:`1px solid ${theme.line}`, borderRadius:8, padding:6, cursor:'pointer', color:theme.muted}}><X size={15}/></button>
    </div>
  </div>
);

// ─────────────────────────────────────────────────────────────────
// MCP Invocation Policies — distinct from Prompt rules
// ─────────────────────────────────────────────────────────────────
const INVOCATION_RULES = [
  { id:1, active:true, name:'Block writes to main branch', server:'github', tools:'push_*, merge_*', predicate:'branch == "main"', action:'block', scope:'All engineering', hits:47, version:9, lastEdit:'arjun.d@llp.in · today' },
  { id:2, active:true, name:'Require approval · destructive SQL', server:'postgres', tools:'execute_query', predicate:'matches /DROP|TRUNCATE|DELETE/i', action:'approve', scope:'All developers', hits:12, version:5, lastEdit:'meera.nair@llp.in · 4 days ago' },
  { id:3, active:true, name:'Mask PII on gmail.send', server:'gmail', tools:'send_message', predicate:'to contains "@" + external_domain', action:'redact', scope:'All users', hits:88, version:3, lastEdit:'krishna@llp.in · 1 week ago' },
  { id:4, active:true, name:'Block shell-exec entirely', server:'shell-exec', tools:'*', predicate:'always', action:'block', scope:'All users', hits:47, version:14, lastEdit:'meera.nair@llp.in · today' },
  { id:5, active:false, name:'Rate-limit jira bulk create', server:'jira', tools:'create_issue', predicate:'count > 20 / 5min', action:'warn', scope:'All users', hits:0, version:1, lastEdit:'sundar.v@llp.in · drafted today' },
  { id:6, active:true, name:'Read-only filesystem outside workspace', server:'filesystem', tools:'write_*, delete_*', predicate:'path !startsWith workspace_root', action:'block', scope:'All users', hits:28, version:6, lastEdit:'arjun.d@llp.in · 2 days ago' },
];

const InvocationPolicies = () => {
  const [rules, setRules] = React.useState(INVOCATION_RULES);
  const [createOpen, setCreateOpen] = React.useState(false);
  const [historyFor, setHistoryFor] = React.useState(null);
  return (
    <div>
      <SectionTitle eyebrow="MCP Security · Invocation Policies" title="Rules that govern every tool call"
        actions={<>
          <Button small icon={FilterV2}>Filter</Button>
          <Button small onClick={()=>setHistoryFor({all:true, name:'Invocation policy bundle'})}>Bundle history</Button>
          <Button primary icon={Plus} onClick={()=>setCreateOpen(true)}>Create invocation rule</Button>
        </>}/>

      <div style={{display:'grid', gridTemplateColumns:'repeat(4,1fr)', gap:14, marginBottom:20}}>
        <KPI label="Active rules" value="24" delta="Governing 18 servers" tone="orange"/>
        <KPI label="Invocations blocked · 7d" value="2,184" delta="Across all rules" tone="terracotta"/>
        <KPI label="Pending approvals" value="7" delta="Awaiting admin" tone="amber"/>
        <KPI label="Rules drafted" value="3" delta="Not yet active" tone="neutral"/>
      </div>

      <div style={{display:'flex', gap:14, marginBottom:14, padding:'10px 14px', border:`1px solid ${theme.line}`, borderRadius:10, background:theme.panel, fontSize:12, color:theme.muted, alignItems:'center'}}>
        <Pill tone="ocean">Bundle v18</Pill>
        <span>Latest revision <strong style={{color:theme.ink, fontFamily:theme.mono}}>v18</strong> · published <strong style={{color:theme.ink}}>2 hr ago</strong> by <strong style={{color:theme.ink, fontFamily:theme.mono}}>arjun.d@llp.in</strong></span>
        <span style={{marginLeft:'auto', display:'inline-flex', alignItems:'center', gap:6}}><Pill tone="amber">1 unpublished draft</Pill></span>
      </div>

      <Card padded={false}>
        <table style={{width:'100%', borderCollapse:'collapse', fontSize:13}}>
          <thead><tr style={{borderBottom:`1px solid ${theme.line}`}}>
            {['Active','Rule','Version','Server · tools','Predicate','Action','Users / Groups','Hits (7d)',''].map((h,i)=>(
              <th key={i} style={{padding:'12px 16px', textAlign:'left', fontSize:10.5, letterSpacing:1.5, color:theme.muted, fontWeight:600, textTransform:'uppercase', fontFamily:theme.sans}}>{h}</th>
            ))}
          </tr></thead>
          <tbody>
            {rules.map(r => (
              <tr key={r.id} style={{borderBottom:`1px solid ${theme.lineSoft}`}}>
                <td style={{padding:'14px 16px'}}><Toggle on={r.active} onChange={()=>setRules(rs=>rs.map(x=>x.id===r.id?{...x,active:!x.active}:x))}/></td>
                <td style={{padding:'14px 16px', color:theme.ink, fontWeight:500}}>
                  {r.name}
                  <div style={{fontSize:11, color:theme.muted, marginTop:2, fontWeight:400}}>edited by {r.lastEdit}</div>
                </td>
                <td style={{padding:'14px 16px'}}>
                  <button onClick={()=>setHistoryFor(r)} style={{display:'inline-flex', alignItems:'center', gap:5, padding:'3px 9px', border:`1px solid ${theme.line}`, borderRadius:999, background:theme.panel, color:theme.oceanInk, fontFamily:theme.mono, fontSize:11.5, fontWeight:600, cursor:'pointer'}}>
                    v{r.version} <ClockIcon size={11} strokeWidth={1.8}/>
                  </button>
                </td>
                <td style={{padding:'14px 16px'}}>
                  <div style={{fontFamily:theme.mono, fontSize:12.5, color:theme.oceanInk, fontWeight:600}}>{r.server}</div>
                  <div style={{fontFamily:theme.mono, fontSize:11, color:theme.muted}}>{r.tools}</div>
                </td>
                <td style={{padding:'14px 16px', fontFamily:theme.mono, fontSize:11.5, color:theme.muted, maxWidth:280}}>{r.predicate}</td>
                <td style={{padding:'14px 16px'}}>
                  <Pill tone={r.action==='block'?'terracotta':r.action==='redact'?'amber':r.action==='approve'?'ocean':'neutral'}>{r.action.toUpperCase()}</Pill>
                </td>
                <td style={{padding:'14px 16px', color:theme.muted, fontSize:12}}>{r.scope}</td>
                <td style={{padding:'14px 16px', fontFamily:theme.mono, color:theme.ink}}>{r.hits}</td>
                <td style={{padding:'14px 16px', color:theme.muted, cursor:'pointer'}}><MoreH2 size={15}/></td>
              </tr>
            ))}
          </tbody>
        </table>
      </Card>

      <CreateRuleDrawer open={createOpen} onClose={()=>setCreateOpen(false)} kind="invocation"/>
      <PolicyHistoryDrawer rule={historyFor} onClose={()=>setHistoryFor(null)} kind="invocation"/>
    </div>
  );
};

// ─────────────────────────────────────────────────────────────────
// Create Rule drawer (works for Prompt or Invocation)
// ─────────────────────────────────────────────────────────────────
const PII_PRESETS = [
  { k:'AADHAAR', desc:'12-digit Aadhaar number' },
  { k:'PAN', desc:'ABCDE1234F' },
  { k:'GSTIN', desc:'15-char GST identifier' },
  { k:'PHONE_IN', desc:'+91 10-digit mobile' },
  { k:'EMAIL', desc:'RFC 5322 email address' },
  { k:'CREDENTIAL', desc:'password=, api_key=, DATABASE_URL=, AWS_\u2026' },
  { k:'IFSC', desc:'Bank IFSC code' },
  { k:'SOURCE_CODE', desc:'>20 lines of code with identifiers' },
];

// MCP server · tool presets for invocation rules
const MCP_SERVER_PRESETS = [
  { k:'github', desc:'push_*, merge_*, create_pr, comment' },
  { k:'filesystem', desc:'read_*, write_*, delete_*, list_dir' },
  { k:'postgres', desc:'execute_query, schema_list' },
  { k:'gmail', desc:'send_message, list_messages, get_attachment' },
  { k:'shell-exec', desc:'run, exec, spawn' },
  { k:'jira', desc:'create_issue, update_issue, transition' },
  { k:'*', desc:'Any MCP server (global rule)' },
];
const PREDICATE_PRESETS = [
  { k:'destructive', label:'Destructive verbs', expr:'tool matches /push|delete|drop|truncate|rm|revoke/i' },
  { k:'prod-branch', label:'Production branch', expr:'args.branch == "main" || args.branch == "production"' },
  { k:'external-recipient', label:'External recipient', expr:'args.to endsWith not in allowed_domains' },
  { k:'outside-workspace', label:'Path outside workspace', expr:'args.path !startsWith workspace_root' },
  { k:'bulk', label:'Bulk operations', expr:'args.limit > 1000 || count > 20 / 5min' },
  { k:'always', label:'Always (server-wide)', expr:'always' },
];
const GROUP_PRESETS = [
  {k:'all', label:'All users', count:2847, kind:'group'},
  {k:'eng', label:'Engineering', count:184, kind:'group'},
  {k:'finance', label:'Finance & Treasury', count:42, kind:'group'},
  {k:'support', label:'Customer Support', count:96, kind:'group'},
  {k:'exec', label:'Leadership', count:14, kind:'group'},
  {k:'u:priya', label:'priya.sharma@llp.in', kind:'user'},
  {k:'u:rahul', label:'rahul.menon@llp.in', kind:'user'},
];

const CreateRuleDrawer = ({open, onClose, kind='prompt'}) => {
  const isInvocation = kind === 'invocation';
  const [step, setStep] = React.useState(1);
  const [name, setName] = React.useState('');
  const [patterns, setPatterns] = React.useState(isInvocation ? ['github'] : ['AADHAAR']);
  const [customRegex, setCustomRegex] = React.useState('');
  const [toolFilter, setToolFilter] = React.useState('');
  const [predicate, setPredicate] = React.useState(isInvocation ? 'destructive' : null);
  const [action, setAction] = React.useState(isInvocation ? 'block' : 'redact');
  const [scopeSearch, setScopeSearch] = React.useState('');
  const [scopeSelected, setScopeSelected] = React.useState(['all']);
  const [apps, setApps] = React.useState(['all']);
  const [notify, setNotify] = React.useState(true);

  React.useEffect(() => {
    if (open) {
      setStep(1);
      // Reset defaults to match the current kind every time the drawer opens.
      setPatterns(isInvocation ? ['github'] : ['AADHAAR']);
      setPredicate(isInvocation ? 'destructive' : null);
      setAction(isInvocation ? 'block' : 'redact');
    }
  }, [open, isInvocation]);

  const STEP_LABELS = isInvocation
    ? ['Target', 'Action', 'Scope', 'Review']
    : ['Pattern', 'Action', 'Scope', 'Review'];

  const togglePattern = (k) => setPatterns(p => p.includes(k)?p.filter(x=>x!==k):[...p, k]);
  const toggleScope = (k) => setScopeSelected(s => s.includes(k)?s.filter(x=>x!==k):[...s, k]);
  const toggleApp = (k) => setApps(a => a.includes(k)?a.filter(x=>x!==k):[...a, k]);

  const scopeFiltered = GROUP_PRESETS.filter(g => !scopeSearch || g.label.toLowerCase().includes(scopeSearch.toLowerCase()));

  return (
    <Drawer open={open} onClose={onClose} width={640}>
      <DrawerHeader onClose={onClose}
        eyebrow={isInvocation?'MCP Security · New invocation rule':'Prompt Protection · New rule'}
        title={name || (isInvocation?'Untitled invocation rule':'Untitled rule')}/>

      {/* Stepper */}
      <div style={{display:'flex', gap:0, padding:'0 24px', background:theme.panel, borderBottom:`1px solid ${theme.line}`}}>
        {STEP_LABELS.map((s, i) => {
          const n = i+1;
          const active = step===n, done = step>n;
          return (
            <button key={s} onClick={()=>setStep(n)} style={{
              padding:'14px 16px', background:'transparent', border:'none', cursor:'pointer',
              borderBottom: active ? `2px solid ${theme.orangeDeep}` : '2px solid transparent',
              color: active ? theme.orangeDeep : done ? theme.ink : theme.muted,
              fontWeight: active?600:500, fontSize:12.5, fontFamily:theme.sans,
              display:'flex', alignItems:'center', gap:8,
            }}>
              <span style={{
                width:18, height:18, borderRadius:999, display:'inline-flex', alignItems:'center', justifyContent:'center',
                background: done?theme.orangeDeep:active?theme.orangeSoft:theme.lineSoft,
                color: done?theme.onPrimary:active?theme.orangeDeep:theme.muted,
                fontSize:10, fontWeight:700, fontFamily:theme.mono,
              }}>{done?'✓':n}</span>
              {s}
            </button>
          );
        })}
      </div>

      <div style={{flex:1, overflow:'auto', padding:'24px'}}>
        {step===1 && !isInvocation && (
          <div>
            <Eyebrow>Step 1 · What to detect in prompts</Eyebrow>
            <label style={{display:'block', fontSize:12, color:theme.muted, marginTop:16, marginBottom:6, fontWeight:600, letterSpacing:0.2}}>Rule name</label>
            <input value={name} onChange={e=>setName(e.target.value)} placeholder="e.g. Redact Aadhaar in prompts" style={{
              width:'100%', padding:'10px 14px', border:`1px solid ${theme.line}`, borderRadius:8,
              fontFamily:theme.sans, fontSize:14, color:theme.ink, background:theme.panel, outline:'none',
            }}/>

            <div style={{marginTop:24, fontSize:12, color:theme.muted, marginBottom:10, fontWeight:600, letterSpacing:0.2}}>PII / secret patterns</div>
            <div style={{display:'grid', gridTemplateColumns:'repeat(2,1fr)', gap:8}}>
              {PII_PRESETS.map(p => {
                const on = patterns.includes(p.k);
                return (
                  <button key={p.k} onClick={()=>togglePattern(p.k)} style={{
                    textAlign:'left', padding:'10px 12px', borderRadius:8, cursor:'pointer',
                    border:`1px solid ${on?theme.orangeDeep:theme.line}`,
                    background: on?theme.orangeSoft:theme.panel,
                  }}>
                    <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:2}}>
                      <span style={{fontFamily:theme.mono, fontSize:12, color:on?theme.orangeDeep:theme.ink, fontWeight:600}}>{p.k}</span>
                      {on && <CheckV2 size={13} color={theme.orangeDeep}/>}
                    </div>
                    <div style={{fontSize:11, color:theme.muted}}>{p.desc}</div>
                  </button>
                );
              })}
            </div>

            <div style={{marginTop:24, fontSize:12, color:theme.muted, marginBottom:6, fontWeight:600, letterSpacing:0.2}}>Custom regex <span style={{fontWeight:400, color:theme.subtle}}>(optional)</span></div>
            <input value={customRegex} onChange={e=>setCustomRegex(e.target.value)} placeholder="/CUST-\\d{6}/" style={{
              width:'100%', padding:'10px 14px', border:`1px solid ${theme.line}`, borderRadius:8,
              fontFamily:theme.mono, fontSize:13, color:theme.ink, background:theme.panel, outline:'none',
            }}/>

            <div style={{marginTop:20, padding:14, background:theme.orangeMist, borderRadius:10, border:`1px solid ${theme.orangeSoft}`, fontSize:12, color:theme.muted, lineHeight:1.6}}>
              <strong style={{color:theme.orangeDeep}}>Tip · </strong>
              Vyuu runs PII detection on-device using MiniLM ONNX. Custom regexes are evaluated in the agent, never sent to a cloud LLM.
            </div>
          </div>
        )}

        {step===1 && isInvocation && (
          <div>
            <Eyebrow>Step 1 · Which MCP calls to target</Eyebrow>
            <label style={{display:'block', fontSize:12, color:theme.muted, marginTop:16, marginBottom:6, fontWeight:600, letterSpacing:0.2}}>Rule name</label>
            <input value={name} onChange={e=>setName(e.target.value)} placeholder="e.g. Block writes to main branch" style={{
              width:'100%', padding:'10px 14px', border:`1px solid ${theme.line}`, borderRadius:8,
              fontFamily:theme.sans, fontSize:14, color:theme.ink, background:theme.panel, outline:'none',
            }}/>

            <div style={{marginTop:24, fontSize:12, color:theme.muted, marginBottom:10, fontWeight:600, letterSpacing:0.2}}>MCP server</div>
            <div style={{display:'grid', gridTemplateColumns:'repeat(2,1fr)', gap:8}}>
              {MCP_SERVER_PRESETS.map(p => {
                const on = patterns.includes(p.k);
                return (
                  <button key={p.k} onClick={()=>togglePattern(p.k)} style={{
                    textAlign:'left', padding:'10px 12px', borderRadius:8, cursor:'pointer',
                    border:`1px solid ${on?theme.oceanInk:theme.line}`,
                    background: on?theme.oceanSoft:theme.panel,
                  }}>
                    <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:2}}>
                      <span style={{fontFamily:theme.mono, fontSize:12, color:on?theme.oceanInk:theme.ink, fontWeight:600}}>{p.k}</span>
                      {on && <CheckV2 size={13} color={theme.oceanInk}/>}
                    </div>
                    <div style={{fontSize:11, color:theme.muted, fontFamily:theme.mono}}>{p.desc}</div>
                  </button>
                );
              })}
            </div>

            <div style={{marginTop:24, fontSize:12, color:theme.muted, marginBottom:6, fontWeight:600, letterSpacing:0.2}}>Tool pattern <span style={{fontWeight:400, color:theme.subtle}}>(glob, optional)</span></div>
            <input value={toolFilter} onChange={e=>setToolFilter(e.target.value)} placeholder="push_* · merge_* · delete_*" style={{
              width:'100%', padding:'10px 14px', border:`1px solid ${theme.line}`, borderRadius:8,
              fontFamily:theme.mono, fontSize:13, color:theme.ink, background:theme.panel, outline:'none',
            }}/>

            <div style={{marginTop:24, fontSize:12, color:theme.muted, marginBottom:10, fontWeight:600, letterSpacing:0.2}}>When to fire (predicate)</div>
            <div style={{display:'grid', gap:6}}>
              {PREDICATE_PRESETS.map(p => {
                const on = predicate===p.k;
                return (
                  <button key={p.k} onClick={()=>setPredicate(p.k)} style={{
                    textAlign:'left', padding:'10px 12px', borderRadius:8, cursor:'pointer',
                    border:`1px solid ${on?theme.oceanInk:theme.line}`,
                    background: on?theme.oceanSoft:theme.panel,
                    display:'flex', justifyContent:'space-between', alignItems:'center', gap:12,
                  }}>
                    <div>
                      <div style={{fontSize:13, color:theme.ink, fontWeight:600}}>{p.label}</div>
                      <div style={{fontFamily:theme.mono, fontSize:11, color:theme.muted, marginTop:2}}>{p.expr}</div>
                    </div>
                    {on && <CheckV2 size={14} color={theme.oceanInk}/>}
                  </button>
                );
              })}
            </div>

            <div style={{marginTop:20, padding:14, background:theme.oceanSoft, borderRadius:10, border:`1px solid ${theme.oceanSoft}`, fontSize:12, color:theme.muted, lineHeight:1.6}}>
              <strong style={{color:theme.oceanInk}}>Tip · </strong>
              Invocation rules are evaluated against the raw MCP JSON-RPC call on the agent before the tool runs. Predicates can reference <code style={{fontFamily:theme.mono}}>args.*</code>, <code style={{fontFamily:theme.mono}}>tool</code>, <code style={{fontFamily:theme.mono}}>user</code>, and counts.
            </div>
          </div>
        )}

        {step===2 && (
          <div>
            <Eyebrow>Step 2 · What to do when matched</Eyebrow>
            <div style={{display:'grid', gap:10, marginTop:16}}>
              {(isInvocation ? [
                {k:'allow', t:'Allow', d:'Let the tool call execute, log it for audit.', tone:'orange'},
                {k:'warn', t:'Warn', d:'Execute the call but surface a non-blocking warning to the user.', tone:'amber'},
                {k:'redact', t:'Redact args', d:'Mask matched fields in the JSON-RPC args before the tool runs.', tone:'amber'},
                {k:'approve', t:'Request approval', d:'Hold the tool call; an admin must approve before it proceeds.', tone:'ocean'},
                {k:'block', t:'Block', d:'Hard block the tool call. Agent receives a policy error with the rule name.', tone:'terracotta'},
              ] : [
                {k:'allow', t:'Allow', d:'Let the prompt through, log it for audit.', tone:'orange'},
                {k:'warn', t:'Warn', d:'Show the user a non-blocking warning; they can still proceed.', tone:'amber'},
                {k:'redact', t:'Redact', d:'Replace matches with ⟨REDACTED⟩ before the prompt leaves the device.', tone:'amber'},
                {k:'approve', t:'Request approval', d:'Hold the request in a queue; an admin must approve before it proceeds.', tone:'ocean'},
                {k:'block', t:'Block', d:'Hard block the prompt. User sees a policy banner with the rule name.', tone:'terracotta'},
              ]).map(a => {
                const on = action===a.k;
                return (
                  <button key={a.k} onClick={()=>setAction(a.k)} style={{
                    textAlign:'left', padding:14, borderRadius:10, cursor:'pointer',
                    border:`1px solid ${on?theme.orangeDeep:theme.line}`,
                    background: on?theme.panel:theme.panel,
                    boxShadow: on ? `0 0 0 3px ${theme.orangeSoft}` : 'none',
                  }}>
                    <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:4}}>
                      <div style={{display:'flex', alignItems:'center', gap:10}}>
                        <Pill tone={a.tone}>{a.t}</Pill>
                      </div>
                      {on && <CheckV2 size={16} color={theme.orangeDeep}/>}
                    </div>
                    <div style={{fontSize:12.5, color:theme.muted, marginTop:6, lineHeight:1.5}}>{a.d}</div>
                  </button>
                );
              })}
            </div>

            <label style={{marginTop:24, display:'flex', gap:10, alignItems:'center', padding:12, border:`1px solid ${theme.line}`, borderRadius:8, cursor:'pointer'}}>
              <input type="checkbox" checked={notify} onChange={e=>setNotify(e.target.checked)}/>
              <div>
                <div style={{fontSize:13, color:theme.ink, fontWeight:500}}>Notify the user inline</div>
                <div style={{fontSize:11.5, color:theme.muted}}>Show a small Vyuu toast explaining which rule fired and why.</div>
              </div>
            </label>
          </div>
        )}

        {step===3 && (
          <div>
            <Eyebrow>Step 3 · Who this applies to</Eyebrow>

            <div style={{marginTop:16, marginBottom:8, fontSize:12, color:theme.muted, fontWeight:600, letterSpacing:0.2}}>Users / Groups</div>
            <div style={{position:'relative', marginBottom:10}}>
              <SearchIcon size={14} color={theme.muted} style={{position:'absolute', left:12, top:12}}/>
              <input value={scopeSearch} onChange={e=>setScopeSearch(e.target.value)} placeholder="Search users or groups…" style={{
                width:'100%', padding:'9px 14px 9px 34px', border:`1px solid ${theme.line}`, borderRadius:8,
                fontFamily:theme.sans, fontSize:13, color:theme.ink, background:theme.panel, outline:'none',
              }}/>
            </div>

            <div style={{border:`1px solid ${theme.line}`, borderRadius:8, background:theme.panel, maxHeight:240, overflowY:'auto'}}>
              {scopeFiltered.map(g => {
                const on = scopeSelected.includes(g.k);
                const Icon = g.kind==='group'?Users:User;
                return (
                  <button key={g.k} onClick={()=>toggleScope(g.k)} style={{
                    width:'100%', display:'flex', alignItems:'center', gap:12,
                    padding:'10px 14px', cursor:'pointer',
                    background: on?theme.orangeMist:'transparent',
                    border:'none', borderBottom:`1px solid ${theme.lineSoft}`,
                    textAlign:'left',
                  }}>
                    <Icon size={14} color={theme.muted}/>
                    <div style={{flex:1}}>
                      <div style={{fontSize:13, color:theme.ink, fontWeight: g.kind==='group'?600:500}}>{g.label}</div>
                      {g.count && <div style={{fontSize:11, color:theme.muted, fontFamily:theme.mono}}>{g.count} users</div>}
                    </div>
                    {on && <CheckV2 size={14} color={theme.orangeDeep}/>}
                  </button>
                );
              })}
            </div>

            <div style={{marginTop:10, display:'flex', gap:6, flexWrap:'wrap'}}>
              {scopeSelected.map(k => {
                const g = GROUP_PRESETS.find(x=>x.k===k); if (!g) return null;
                return <Pill key={k} tone={g.kind==='group'?'orange':'ocean'}>{g.label} ✕</Pill>;
              })}
            </div>

            <div style={{marginTop:24, fontSize:12, color:theme.muted, marginBottom:8, fontWeight:600, letterSpacing:0.2}}>{isInvocation?'Which host environments':'Which AI apps'}</div>
            <div style={{display:'flex', gap:8, flexWrap:'wrap'}}>
              {(isInvocation
                ? ['all','Claude Desktop','Cursor','Claude Code','Cline','VS Code + Copilot']
                : ['all','Claude Desktop','ChatGPT (browser)','Cursor','Perplexity','Gemini','Browser only']
              ).map(app => {
                const on = apps.includes(app==='all'?'all':app);
                const key = app==='all'?'all':app;
                return (
                  <button key={key} onClick={()=>toggleApp(key)} style={{
                    padding:'7px 13px', borderRadius:999, cursor:'pointer',
                    border:`1px solid ${on?theme.orangeDeep:theme.line}`,
                    background: on?theme.orangeDeep:theme.panel,
                    color: on?theme.onPrimary:theme.ink,
                    fontSize:12, fontWeight:500,
                  }}>{app==='all'?(isInvocation?'All hosts':'All apps'):app}</button>
                );
              })}
            </div>
          </div>
        )}

        {step===4 && (
          <div>
            <Eyebrow>Step 4 · Review &amp; save</Eyebrow>
            <Card style={{marginTop:16}}>
              <div style={{display:'grid', gap:14, fontSize:13}}>
                <Row label="Rule name" value={name||'(untitled)'}/>
                <Row label={isInvocation?'Servers':'Patterns'} value={<div style={{display:'flex', gap:4, flexWrap:'wrap'}}>{patterns.map(p=><Pill key={p} tone="ocean">{p}</Pill>)}{customRegex && <Pill tone="neutral">custom: {customRegex}</Pill>}</div>}/>
                {isInvocation && toolFilter && <Row label="Tools" value={<span style={{fontFamily:theme.mono, fontSize:12}}>{toolFilter}</span>}/>}
                {isInvocation && <Row label="Predicate" value={<span style={{fontFamily:theme.mono, fontSize:12}}>{PREDICATE_PRESETS.find(p=>p.k===predicate)?.expr || '—'}</span>}/>}
                <Row label="Action" value={<Pill tone={action==='block'?'terracotta':action==='redact'?'amber':action==='approve'?'ocean':action==='warn'?'amber':'orange'}>{action.toUpperCase()}</Pill>}/>
                <Row label="Scope" value={scopeSelected.map(k=>GROUP_PRESETS.find(x=>x.k===k)?.label).filter(Boolean).join(', ')}/>
                <Row label={isInvocation?'Hosts':'Apps'} value={apps.includes('all')?(isInvocation?'All hosts':'All AI apps'):apps.join(', ')}/>
                <Row label="Notify user" value={notify?'Yes, inline toast':'Silent'}/>
              </div>
            </Card>
            <div style={{marginTop:16, padding:14, background:theme.amberSoft, borderRadius:10, fontSize:12, color:theme.amberInk, lineHeight:1.6}}>
              <strong>Dry-run first?</strong> Vyuu can shadow this rule for 48 hr — events will show "would have" verdicts so you can calibrate before enforcing.
            </div>
          </div>
        )}
      </div>

      <div style={{padding:'14px 24px', borderTop:`1px solid ${theme.line}`, background:theme.panel, display:'flex', justifyContent:'space-between', alignItems:'center'}}>
        <button onClick={onClose} style={{background:'transparent', border:'none', color:theme.muted, cursor:'pointer', fontSize:13, fontFamily:theme.sans}}>Cancel</button>
        <div style={{display:'flex', gap:8}}>
          {step>1 && <Button small onClick={()=>setStep(s=>s-1)}>Back</Button>}
          {step<4 && <Button small primary onClick={()=>setStep(s=>s+1)}>Continue</Button>}
          {step===4 && <>
            <Button small>Save as draft</Button>
            <Button small primary>Enable rule</Button>
          </>}
        </div>
      </div>
    </Drawer>
  );
};

const Row = ({label, value}) => (
  <div style={{display:'grid', gridTemplateColumns:'130px 1fr', gap:12, alignItems:'center'}}>
    <div style={{fontSize:11, color:theme.muted, letterSpacing:1.2, textTransform:'uppercase', fontWeight:600}}>{label}</div>
    <div style={{color:theme.ink, fontSize:13}}>{value}</div>
  </div>
);

Object.assign(window, {Drawer, DrawerHeader, CreateRuleDrawer, InvocationPolicies, Row, GROUP_PRESETS});
