     @ {% extends "base.html" %}
{% block content %}

<div style="display:flex;height:100vh;width:100%;overflow:hidden;background:#0d0d0d;">

  <!-- SIDEBAR -->
  <aside style="width:248px;flex-shrink:0;border-right:1px solid #1b1b1b;background:#0f0f0f;display:flex;flex-direction:column;">
    <div style="padding:22px 20px 18px 20px;border-bottom:1px solid #1a1a1a;">
      <div style="display:flex;align-items:center;gap:9px;">
        <div style="width:9px;height:9px;border-radius:2px;background:#d97757;"></div>
        <div style="font-size:15px;font-weight:700;letter-spacing:0.04em;">CONCEPT</div>
      </div>
      <div style="margin-top:8px;font-family:'JetBrains Mono',monospace;font-size:11px;color:#5e5c58;letter-spacing:0.01em;">context.bolbol.tn:3093</div>
    </div>

    <nav id="nav-container" style="padding:14px 12px 8px 12px;display:flex;flex-direction:column;gap:2px;"></nav>

    <div style="padding:18px 22px 8px 22px;font-size:10.5px;font-weight:600;letter-spacing:0.13em;color:#4f4d49;">SCOPES</div>
    <div id="sidebar-scopes" style="padding:0 12px;display:flex;flex-direction:column;gap:1px;overflow-y:auto;"></div>
    
    <div style="padding:14px 20px;border-top:1px solid #1a1a1a;display:flex;align-items:center;gap:9px;">
      <div style="width:7px;height:7px;border-radius:50%;background:#6fa888;animation:pulse 2.4s ease-in-out infinite;"></div>
      <span style="font-size:11.5px;color:#8f8d88;">Serveur en ligne</span>
      <span style="margin-left:auto;font-family:'JetBrains Mono',monospace;font-size:10.5px;color:#4f4d49;">v1.5</span>
    </div>

    <a href="/logout" style="margin: 0 20px 14px 20px; padding:10px 0; background:#181818; border:1px solid #222; border-radius:6px; color:#a3a19c; font-size:11.5px; font-weight:500; text-align:center; text-decoration:none; transition:all 0.2s;" onmouseover="this.style.background='#222';this.style.color='#fff';" onmouseout="this.style.background='#181818';this.style.color='#a3a19c';">
      Déconnexion
    </a>

    <footer class="nyora-footer">
        <div class="nyora-line-top"></div>
        <div class="nyora-brand">
            <span class="nyora-dot"></span>
            <span class="nyora-name">NYORA</span>
            <span class="nyora-dot"></span>
        </div>
        <div class="nyora-tag">Crafted with precision</div>
    </footer>
  </aside>

  <!-- MAIN -->
  <main id="main-content" style="flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0;">
  </main>
  
  <div id="toast-container"></div>
</div>

<script>
// INITIAL DATA
const scopesDef = [
  { id:'infra', label:'infra', color:'#7b95c4', desc:'Serveurs, ports et déploiement de toute la stack.', updated:'Live', agents:['Hermes','Claude'] },
  { id:'llm',   label:'llm',   color:'#9b87c4', desc:'Modèles, prompts système et budgets de tokens.', updated:'Live', agents:['Claude','Gemini'] },
  { id:'nyora', label:'nyora', color:'#7bb592', desc:'État, priorités et stack du projet Nyora.', updated:'Live', agents:['Hermes','Claude'] },
  { id:'perso', label:'perso', color:'#c4a878', desc:'Préférences, fuseau et style de réponse de Nabil.', updated:'Live', agents:['Claude','Gemini'] },
  { id:'tt',    label:'tt',    color:'#c48a7b', desc:'Repo, hôte et état du projet TT.', updated:'Live', agents:['Hermes','Claude'] },
];

let state = {
  screen: 'home',
  scope: 'infra',
  filter: 'all',
  auditData: [],
  portsData: {},
  llmData: {},
  infraData: {},
  keysData: [],
  drNexum: { subs: localStorage.getItem('dr_nexum_subs')||0, rev: localStorage.getItem('dr_nexum_rev')||0 }
};

function flash(msg) {
  const t = document.getElementById('toast-container');
  t.innerHTML = `<div style="position:fixed;bottom:24px;right:28px;display:flex;align-items:center;gap:10px;background:#181818;border:1px solid #2c2c2c;color:#e8e6e3;padding:11px 16px;border-radius:9px;font-size:13px;box-shadow:0 8px 30px rgba(0,0,0,0.5);animation:toastIn 0.18s ease-out;z-index:50;">
    <div style="width:7px;height:7px;border-radius:50%;background:#6fa888;"></div>
    <span>${msg}</span>
  </div>`;
  setTimeout(() => t.innerHTML='', 2000);
}

function copy(txt) {
  navigator.clipboard.writeText(txt).catch(()=>{});
  flash('Copié !');
}

function agentColor(a){ if(a==='Claude')return '#d99a86'; if(a==='Gemini')return '#9b87c4'; return '#8aa6c4'; }
function colorOf(id){ const s=scopesDef.find(x=>x.id===id); return s?s.color:'#6a6863'; }

function go(sc) { state.screen = sc; render(); }
function openScope(id) { state.screen = 'scope'; state.scope = id; render(); }
function setFilter(f) { state.filter = f; render(); }
function updateNexum(k, v) { state.drNexum[k] = v; localStorage.setItem('dr_nexum_'+k, v); render(); }

// DATA PARSING
function getEntries(scopeId) {
    let arr = [];
    if(scopeId==='infra') {
        for(let k in state.infraData) {
            arr.push({ key: k, value: JSON.stringify(state.infraData[k]), type:'config' });
        }
    } else if(scopeId==='llm') {
        for(let k in state.llmData) {
            arr.push({ key: k, value: state.llmData[k], type:'config' });
        }
    }
    return arr;
}

function renderSidebar() {
  const scopesActive = state.screen === 'home' || state.screen === 'scope';
  const navItems = [
    { id:'home', label:'Scopes', screen:'home', active: scopesActive },
    { id:'ports', label:'Ports', screen:'ports', active: state.screen==='ports' },
    { id:'keys', label:'Clés API', screen:'keys', active: state.screen==='keys' },
    { id:'activity', label:'Activité', screen:'activity', active: state.screen==='activity' },
  ];
  
  let navHtml = '';
  navItems.forEach(n => {
    const bg = n.active ? 'background:#181818;color:#e8e6e3;font-weight:500;' : 'color:#8f8d88;';
    const bar = n.active ? '#d97757' : 'transparent';
    navHtml += `<div class="hover-bg-17" onclick="go('${n.screen}')" style="display:flex;align-items:center;gap:11px;padding:9px 12px 9px 14px;border-radius:7px;cursor:pointer;font-size:13.5px;position:relative;transition:background .12s;${bg}">
      <div style="position:absolute;left:3px;top:9px;bottom:9px;width:2.5px;border-radius:2px;background:${bar};"></div>
      <span>${n.label}</span>
    </div>`;
  });
  document.getElementById('nav-container').innerHTML = navHtml;

  let scopesHtml = '';
  scopesDef.forEach(s => {
    const active = (state.screen === 'scope' && state.scope === s.id);
    const bg = active ? 'background:#181818;' : '';
    const count = getEntries(s.id).length;
    scopesHtml += `<div class="hover-bg-17" onclick="openScope('${s.id}')" style="display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:6px;cursor:pointer;${bg}">
      <div style="width:8px;height:8px;border-radius:2px;flex-shrink:0;background:${s.color};"></div>
      <span style="font-family:'JetBrains Mono',monospace;font-size:12.5px;flex:1;">${s.label}</span>
      <span style="font-size:11px;color:#5e5c58;font-variant-numeric:tabular-nums;">${count}</span>
    </div>`;
  });
  document.getElementById('sidebar-scopes').innerHTML = scopesHtml;
}

function renderNexum() {
    const s = parseInt(state.drNexum.subs) || 0;
    const r = parseInt(state.drNexum.rev) || 0;
    const pS = Math.min(100, (s/1000)*100);
    const pR = Math.min(100, (r/300)*100);
    const cS = pS>80?'#6fa888':pS>50?'#c4a878':'#c47a6e';
    const cR = pR>80?'#6fa888':pR>50?'#c4a878':'#c47a6e';
    
    return `<div style="border:1px solid #5a352f;border-left:3px solid #c47a6e;border-radius:8px;background:linear-gradient(90deg,#1c0e0b,transparent);padding:20px 24px;margin-bottom:26px;">
      <div style="display:flex;align-items:center;gap:12px;margin-bottom:16px;">
        <span style="font-family:'JetBrains Mono',monospace;font-size:15px;font-weight:600;color:#c47a6e;letter-spacing:0.05em;">KILL-SWITCH DR. NEXUM</span>
        <span style="font-size:12px;color:#e08864;background:#2a1215;padding:3px 8px;border-radius:4px;border:1px solid #5a352f;">J-X avant 15 nov 2026</span>
      </div>
      <div style="display:flex;gap:40px;">
        <div style="flex:1;">
          <div style="display:flex;justify-content:space-between;font-size:12px;color:#8f8d88;">
            <span>Abonnés YouTube</span>
            <span><input type="number" value="${s}" onchange="updateNexum('subs', this.value)" style="width:50px;background:transparent;border:none;color:#e8e6e3;text-align:right;font-family:'JetBrains Mono';font-size:12px;"> / 1000</span>
          </div>
          <div class="progress-bar-bg"><div class="progress-bar-fg" style="width:${pS}%;background:${cS};"></div></div>
        </div>
        <div style="flex:1;">
          <div style="display:flex;justify-content:space-between;font-size:12px;color:#8f8d88;">
            <span>Revenus €/mois</span>
            <span><input type="number" value="${r}" onchange="updateNexum('rev', this.value)" style="width:50px;background:transparent;border:none;color:#e8e6e3;text-align:right;font-family:'JetBrains Mono';font-size:12px;"> / 300</span>
          </div>
          <div class="progress-bar-bg"><div class="progress-bar-fg" style="width:${pR}%;background:${cR};"></div></div>
        </div>
      </div>
    </div>`;
}

function renderMain() {
  let h = '';
  
  if (state.screen === 'home') {
    let cards = '';
    scopesDef.forEach(s => {
      let agents = s.agents.map(a => `<span style="padding:2px 8px;border-radius:4px;border:1px solid #262626;background:#161616;font-size:10.5px;color:#a8a6a1;">${a}</span>`).join('');
      cards += `<div class="hover-card" onclick="openScope('${s.id}')" style="border:1px solid #1f1f1f;border-left:3px solid ${s.color};border-radius:8px;background:#111;padding:18px 20px;cursor:pointer;display:flex;flex-direction:column;gap:14px;transition:all 0.15s;">
        <div style="display:flex;align-items:center;gap:10px;">
          <span style="font-family:'JetBrains Mono',monospace;font-size:15px;font-weight:500;color:#e8e6e3;">${s.label}</span>
          <span style="margin-left:auto;font-family:'JetBrains Mono',monospace;font-size:13px;color:#8f8d88;">${getEntries(s.id).length} entrées</span>
        </div>
        <div style="font-size:13px;color:#8f8d88;line-height:1.5;">${s.desc}</div>
        <div style="display:flex;align-items:center;gap:8px;padding-top:12px;border-top:1px solid #1c1c1c;">
          <span style="font-size:11.5px;color:#5e5c58;">MAJ ${s.updated}</span>
          <div style="margin-left:auto;display:flex;gap:5px;">${agents}</div>
        </div>
      </div>`;
    });
    
    const activeAgents = state.keysData.length;
    const reqs = state.auditData.length;
    
    h = `<div style="display:flex;flex-direction:column;height:100%;overflow:hidden;">
        <header style="padding:22px 32px;border-bottom:1px solid #1a1a1a;flex-shrink:0;">
          <div style="font-size:17px;font-weight:600;">Scopes</div>
          <div style="margin-top:3px;font-size:12.5px;color:#8f8d88;">Le contenu vivant du cerveau, réparti en domaines.</div>
        </header>
        <div style="flex:1;overflow-y:auto;padding:26px 32px 40px 32px;">
          ${renderNexum()}
          <div style="display:flex;gap:0;border:1px solid #1f1f1f;border-radius:8px;background:#111;margin-bottom:26px;overflow:hidden;">
            <div style="flex:1;padding:16px 22px;border-right:1px solid #1c1c1c;">
              <div style="font-size:11px;color:#5e5c58;letter-spacing:0.04em;">ENTRÉES DOMAINE (Infra+LLM)</div>
              <div style="margin-top:6px;font-size:24px;font-weight:600;">${getEntries('infra').length+getEntries('llm').length}</div>
            </div>
            <div style="flex:1;padding:16px 22px;border-right:1px solid #1c1c1c;">
              <div style="font-size:11px;color:#5e5c58;letter-spacing:0.04em;">AGENTS ACTIFS</div>
              <div style="margin-top:6px;font-size:24px;font-weight:600;">${activeAgents}</div>
            </div>
            <div style="flex:1;padding:16px 22px;">
              <div style="font-size:11px;color:#5e5c58;letter-spacing:0.04em;">REQUÊTES AUDIT</div>
              <div style="margin-top:6px;font-size:24px;font-weight:600;">${reqs}</div>
            </div>
          </div>
          <div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(330px,1fr));gap:14px;">${cards}</div>
        </div>
      </div>`;
  }
  
  else if (state.screen === 'scope') {
    const cur = scopesDef.find(s=>s.id===state.scope);
    const entries = getEntries(state.scope);
    let rows = entries.map(e => `
      <div class="hover-bg-10" style="display:grid;grid-template-columns:170px minmax(120px,1fr) 92px 150px;min-width:540px;align-items:center;padding:13px 12px;border-bottom:1px solid #161616;font-size:13px;">
        <div style="font-family:'JetBrains Mono',monospace;font-size:12.5px;color:#d8d6d1;padding-right:12px;">${e.key}</div>
        <div style="font-family:'JetBrains Mono',monospace;font-size:12.5px;color:#9a9893;padding-right:12px;">${e.value}</div>
        <div><span style="padding:2px 8px;border-radius:4px;font-size:11px;border:1px solid #2a3a4d;color:#8aa6c4;">${e.type}</span></div>
        <div style="display:flex;gap:4px;justify-content:flex-end;">
          <button class="hover-border-3a" onclick="copy('${e.value.replace(/'/g, "\'")}')" style="background:transparent;border:1px solid #242424;color:#8f8d88;font-size:11px;padding:4px 8px;border-radius:5px;cursor:pointer;">copier</button>
        </div>
      </div>`).join('');
      
    if(entries.length===0) rows = `<div style="padding:20px 12px;color:#6a6863;font-size:13px;">Aucune donnée (Backend statique ou vide)</div>`;

    h = `<div style="display:flex;flex-direction:column;height:100%;overflow:hidden;">
        <header style="padding:20px 32px;border-bottom:1px solid #1a1a1a;flex-shrink:0;display:flex;align-items:center;gap:16px;">
          <div>
            <div style="display:flex;align-items:center;gap:9px;font-size:12px;color:#5e5c58;">
              <span class="hover-border-3a" onclick="go('home')" style="cursor:pointer;color:#8f8d88;">Scopes</span>
              <span>/</span>
              <span style="display:inline-flex;align-items:center;gap:6px;color:#a8a6a1;"><span style="width:8px;height:8px;border-radius:2px;background:${cur.color};"></span></span>
            </div>
            <div style="margin-top:4px;display:flex;align-items:baseline;gap:10px;">
              <span style="font-family:'JetBrains Mono',monospace;font-size:18px;font-weight:500;">${cur.label}</span>
              <span style="font-size:12.5px;color:#8f8d88;">${cur.desc}</span>
            </div>
          </div>
        </header>
        <div style="flex:1;overflow:auto;padding:0 32px 40px 32px;">
          <div style="display:grid;grid-template-columns:170px minmax(120px,1fr) 92px 150px;min-width:540px;padding:14px 12px;border-bottom:1px solid #1c1c1c;font-size:10.5px;font-weight:600;letter-spacing:0.1em;color:#4f4d49;position:sticky;top:0;background:#0d0d0d;z-index:2;">
            <div>CLÉ</div><div>VALEUR</div><div>TYPE</div><div style="text-align:right;">ACTIONS</div>
          </div>
          ${rows}
        </div>
      </div>`;
  }
  
  else if (state.screen === 'ports') {
    const explicitFree = [3091, 3001, 3002, 3015];
    const allPorts = new Set(explicitFree);
    for(let i=3100; i<=3199; i++) allPorts.add(i);
    Object.keys(state.portsData).forEach(p => allPorts.add(parseInt(p)));
    const sorted = Array.from(allPorts).sort((a,b)=>a-b);
    
    let chips = '';
    sorted.forEach(p => {
        let serv = state.portsData[p];
        if(serv) {
            chips += `<div style="padding:6px 12px;border-radius:6px;font-size:12px;background:#1a0f0e;border:1px solid #5a352f;color:#c47a6e;font-family:'JetBrains Mono';display:flex;align-items:center;gap:6px;"><div style="width:4px;height:4px;border-radius:50%;background:#d97757;animation:pulse 1s infinite;"></div>${p} <span style="font-size:10px;opacity:0.6;font-family:sans-serif;">${serv}</span></div>`;
        } else {
            chips += `<div style="padding:6px 12px;border-radius:6px;font-size:12px;background:transparent;border:1px solid #222;color:#6a6863;font-family:'JetBrains Mono';">${p}</div>`;
        }
    });

    h = `<div style="display:flex;flex-direction:column;height:100%;overflow:hidden;">
        <header style="padding:22px 32px;border-bottom:1px solid #1a1a1a;flex-shrink:0;">
          <div style="font-size:17px;font-weight:600;">Ports Réseau</div>
          <div style="margin-top:3px;font-size:12.5px;color:#8f8d88;">Surveillance des ports ouverts sur context.bolbol.tn.</div>
        </header>
        <div style="flex:1;overflow-y:auto;padding:26px 32px 40px 32px;">
          <div style="display:flex;flex-wrap:wrap;gap:8px;">${chips}</div>
        </div>
      </div>`;
  }
  
  else      if (state.screen === 'keys') {
    let rows = state.keysData.map((k, idx) => `
      <div class="hover-bg-10" style="display:grid;grid-template-columns:minmax(150px,1fr) 200px 100px;min-width:450px;align-items:center;padding:14px 12px;border-bottom:1px solid #161616;font-size:13px;">
        <div style="font-weight:500;color:${agentColor('Claude')};">Agent ${idx+1}</div>
        <div style="display:flex;align-items:center;gap:8px;">
          <span style="font-family:'JetBrains Mono',monospace;font-size:12px;color:#9a9893;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${k.api_key}</span>
        </div>
        <div style="display:flex;gap:5px;justify-content:flex-end;">
          <button class="hover-border-3a" onclick="copy('${k.api_key}')" style="background:transparent;border:1px solid #242424;color:#8f8d88;font-size:11px;padding:4px 8px;border-radius:5px;cursor:pointer;">copier</button>
        </div>
      </div>`).join('');

    h = `<div style="display:flex;flex-direction:column;height:100%;overflow:hidden;">
        <header style="padding:22px 32px;border-bottom:1px solid #1a1a1a;flex-shrink:0;">
          <div style="font-size:17px;font-weight:600;">Clés API</div>
          <div style="margin-top:3px;font-size:12.5px;color:#8f8d88;">Clés générées depuis la base de données de context-hub.</div>
        </header>
        <div style="flex:1;overflow:auto;padding:0 32px 40px 32px;">
          <div style="display:grid;grid-template-columns:minmax(150px,1fr) 200px 100px;min-width:450px;padding:14px 12px;border-bottom:1px solid #1c1c1c;font-size:10.5px;font-weight:600;letter-spacing:0.1em;color:#4f4d49;">
            <div>AGENT</div><div>CLÉ</div><div style="text-align:right;">ACTIONS</div>
          </div>
          ${rows}
        </div>
      </div>`;
  }
  
  else if (state.screen === 'activity') {
    const actMeta=(a)=> a.includes('écrit') ? {color:'#d99a86',border:'#5a352f'} : a.includes('refus') ? {color:'#c47a6e',border:'#5a352f'} : {color:'#7fae93',border:'#243f30'};
    let rows = state.auditData.filter(r=>state.filter==='all'||r.agent_name.includes(state.filter)||r.scope===state.filter).map(r=>{
      const am = actMeta(r.action.toLowerCase());
      const dt = new Date(r.timestamp);
      const time = dt.toLocaleTimeString('fr-FR', {hour:'2-digit', minute:'2-digit', second:'2-digit'});
      const sc = r.scope || 'infra';
      return `<div class="hover-bg-10" style="display:grid;grid-template-columns:96px 120px 120px minmax(140px,1fr) 104px;min-width:580px;align-items:center;padding:12px 12px;border-bottom:1px solid #161616;font-size:13px;">
        <div style="font-family:'JetBrains Mono',monospace;font-size:12px;color:#6a6863;">${time}</div>
        <div style="font-weight:500;color:${agentColor(r.agent_name)};">${r.agent_name}</div>
        <div style="display:flex;align-items:center;gap:7px;"><span style="width:7px;height:7px;border-radius:2px;background:${colorOf(sc)};"></span><span style="font-family:'JetBrains Mono',monospace;font-size:12px;color:#a8a6a1;">${sc}</span></div>
        <div style="font-family:'JetBrains Mono',monospace;font-size:12px;color:#9a9893;">${r.action}</div>
        <div style="text-align:right;"><span style="padding:2px 9px;border-radius:4px;font-size:11px;border:1px solid ${am.border};color:${am.color};">${r.action}</span></div>
      </div>`;
    }).join('');

    const chips = [{l:'Tous',v:'all'},{l:'Claude',v:'Claude'},{l:'Gemini',v:'Gemini'},{l:'infra',v:'infra'},{l:'llm',v:'llm'},{l:'nyora',v:'nyora'},{l:'perso',v:'perso'},{l:'tt',v:'tt'}].map(c=>{
        const a = state.filter===c.v;
        const style = `padding:5px 12px;border-radius:6px;font-size:12px;cursor:pointer;border:1px solid ${a?'#3a3a3a':'#222'};background:${a?'#1c1c1c':'transparent'};color:${a?'#e8e6e3':'#8f8d88'};`;
        return `<button class="hover-border-3a" onclick="setFilter('${c.v}')" style="${style}">${c.l}</button>`;
    }).join('');

    h = `<div style="display:flex;flex-direction:column;height:100%;overflow:hidden;">
        <header style="padding:22px 32px;border-bottom:1px solid #1a1a1a;flex-shrink:0;">
          <div style="display:flex;align-items:center;gap:10px;">
            <div style="font-size:17px;font-weight:600;">Activité</div>
            <div style="display:flex;align-items:center;gap:6px;padding:3px 9px;border-radius:5px;background:#13201a;border:1px solid #1f3329;">
              <div style="width:6px;height:6px;border-radius:50%;background:#6fa888;animation:pulse 2.4s ease-in-out infinite;"></div>
              <span style="font-size:11px;color:#7fae93;">temps réel</span>
            </div>
          </div>
          <div style="margin-top:12px;display:flex;flex-wrap:wrap;gap:6px;">${chips}</div>
        </header>
        <div style="flex:1;overflow-y:auto;padding:6px 32px 40px 32px;">${rows}</div>
      </div>`;
  }
  
  document.getElementById('main-content').innerHTML = h;
}

function render() {
  renderSidebar();
  renderMain();
}

// FETCH DATA
async function fetchData() {
    try {
        const [p, i, l, a, k] = await Promise.all([
            fetch('/api/ports').then(r=>r.json()),
            fetch('/api/infra').then(r=>r.json()),
            fetch('/api/llm').then(r=>r.json()),
            fetch('/api/audit').then(r=>r.json()),
            fetch('/api/keys').then(r=>r.json()).catch(()=>[])
        ]);
        state.portsData = p;
        state.infraData = i;
        state.llmData = l;
        state.auditData = Array.isArray(a) ? a.slice(0,50) : [];
        state.keysData = Array.isArray(k) ? k : [];
        render();
    } catch(e) {
        console.error(e);
        flash('Erreur de chargement');
        render(); // Render empty
    }
}

document.addEventListener('DOMContentLoaded', () => {
    fetchData();
});
</script>
{% endblock %}

