<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Super Admin — Dashboard</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
  <style>
    :root{
      --bg-page:#F9FAFB; --bg-surface:#FFFFFF; --text-primary:#111827; --text-secondary:#6B7280;
      --accent-dark:#1F2937; --accent-active:#111827; --green:#10B981; --red:#EF4444; --border:#E5E7EB;
      --blue:#2563EB;
    }
    *{box-sizing:border-box}
    body{font-family:'Inter',system-ui,Segoe UI,Arial;background:var(--bg-page);color:var(--text-primary)}
    .metric-card{transition:all .3s}
    .metric-card:hover{transform:translateY(-2px);box-shadow:0 10px 25px rgba(0,0,0,.08)}
    .nav-item{padding:12px 16px;border-radius:8px;cursor:pointer;transition:.2s}
    .nav-item:hover{background:#F3F4F6}
    .nav-item.active{background:var(--accent-dark);color:#fff}
    .progress-bar{height:8px;background:#E5E7EB;border-radius:4px;overflow:hidden}
    .progress-fill{height:100%;background:linear-gradient(90deg,#10B981,#059669);border-radius:4px;transition:width 1.4s}
    .chart-bar{background:linear-gradient(180deg,#3B82F6,#1D4ED8);border-radius:4px 4px 0 0;transition:height 1s}
    .time-filter-btn{transition:.2s}
    .time-filter-btn:hover{background:#F3F4F6}
    .time-filter-btn.active{background:#111827;color:#fff}
    .badge{padding:2px 8px;border-radius:999px;font-size:12px}
    .scrollbox{max-height:260px;overflow:auto}
    .btn{padding:8px 10px;border-radius:8px}
    .btn-ghost{border:1px solid var(--border);background:#fff}
    .btn-ghost:hover{background:#F3F4F6}
    .btn-primary{background:#111827;color:#fff}
    .btn-primary:hover{background:#0b1220}
    .btn-danger{background:#EF4444;color:#fff}
    .btn-danger:hover{background:#dc2626}
    .pill{padding:2px 8px;font-size:12px;border-radius:999px}
  </style>
</head>
<body>
<div class="flex min-h-screen">
  <!-- Sidebar -->
  <aside class="w-64 bg-[var(--bg-surface)] border-r border-[var(--border)] p-6 flex flex-col justify-between">
    <div>
      <h2 class="text-2xl font-bold mb-8">FaceAttend <span class="text-sm font-normal text-[var(--text-secondary)]">Super Admin</span></h2>
      <nav class="mb-2">
        <ul class="space-y-2">
          <li class="nav-item active" data-page="dashboard">Dashboard</li>
          <li class="nav-item" data-page="users">Users</li>
          <li class="nav-item" data-page="students">Students</li>
          <li class="nav-item" data-page="model">Model</li>
          <li class="nav-item" data-page="attendance">Attendance</li>
          <li class="nav-item" data-page="settings">Settings</li>
        </ul>
      </nav>
    </div>
    <ul class="space-y-3 text-[var(--text-secondary)] text-sm mt-10">
      <li><a class="hover:text-gray-900" href="javascript:location.reload()">Refresh</a></li>
      <li><a class="hover:text-gray-900" href="/logout">Log out</a></li>
    </ul>
  </aside>

  <!-- Main -->
  <main class="flex-1 p-8 space-y-8">
    <!-- Header -->
    <header class="flex items-start justify-between">
      <div>
        <h1 id="page-title" class="text-3xl font-bold">Dashboard</h1>
        <div class="flex gap-2 mt-2">
          <button class="time-filter-btn px-3 py-1 text-sm border border-[var(--border)] rounded" data-period="day">Day</button>
          <button class="time-filter-btn px-3 py-1 text-sm border border-[var(--border)] rounded" data-period="week">Week</button>
          <button class="time-filter-btn active px-3 py-1 text-sm rounded" data-period="month">Month</button>
          <button class="time-filter-btn px-3 py-1 text-sm border border-[var(--border)] rounded" data-period="year">Year</button>
        </div>
      </div>
      <div class="flex items-center gap-4">
        <span id="date-range" class="text-sm text-[var(--text-secondary)]"></span>
        <input id="search-att" type="text" placeholder="Search by code/name…" class="px-3 py-2 text-sm border border-[var(--border)] rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
        <div class="w-10 h-10 bg-[var(--accent-dark)] rounded-full"></div>
      </div>
    </header>

    <!-- Metrics -->
    <section id="cards" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
      <div class="metric-card bg-[var(--bg-surface)] p-6 rounded-lg border border-[var(--border)]">
        <h3 class="text-sm text-[var(--text-secondary)]">Total Students</h3>
        <p id="card-students" class="text-2xl font-bold mt-2">—</p>
        <div class="progress-bar mt-3"><div class="progress-fill" id="bar-students" style="width:0%"></div></div>
      </div>
      <div class="metric-card bg-[var(--bg-surface)] p-6 rounded-lg border border-[var(--border)]">
        <h3 class="text-sm text-[var(--text-secondary)]">Users by Role</h3>
        <p id="card-users" class="text-2xl font-bold mt-2">—</p>
        <p class="text-xs text-[var(--text-secondary)] mt-1" id="roles-mini">—</p>
        <div class="progress-bar mt-3"><div class="progress-fill" id="bar-users" style="width:0%"></div></div>
      </div>
      <div class="metric-card bg-[var(--bg-surface)] p-6 rounded-lg border border-[var(--border)]">
        <h3 class="text-sm text-[var(--text-secondary)]">Today’s Recognitions</h3>
        <p id="card-today" class="text-2xl font-bold mt-2">—</p>
        <p class="text-xs text-[var(--text-secondary)] mt-1">auto + manual</p>
        <div class="progress-bar mt-3"><div class="progress-fill" id="bar-today" style="width:0%"></div></div>
      </div>
      <div class="metric-card bg-[var(--bg-surface)] p-6 rounded-lg border border-[var(--border)]">
        <h3 class="text-sm text-[var(--text-secondary)]">Model</h3>
        <p id="card-model" class="text-2xl font-bold mt-2">—</p>
        <p class="text-xs mt-1">
          <span id="badge-xml" class="badge bg-gray-100 border border-[var(--border)]">xml</span>
          <span id="badge-lbl" class="badge bg-gray-100 border border-[var(--border)]">labels</span>
          <span id="badge-cfg" class="badge bg-gray-100 border border-[var(--border)]">cfg</span>
        </p>
        <div class="progress-bar mt-3"><div class="progress-fill" id="bar-model" style="width:0%"></div></div>
      </div>
    </section>

    <!-- Charts + Recent activity -->
    <section class="grid grid-cols-1 lg:grid-cols-2 gap-8">
      <div class="bg-[var(--bg-surface)] p-6 rounded-lg border border-[var(--border)]">
        <div class="flex items-center justify-between mb-4">
          <h3 class="text-lg font-semibold">Attendance (last 7 days)</h3>
          <button id="btn-refresh-chart" class="text-sm px-3 py-1 border border-[var(--border)] rounded hover:bg-gray-50">Refresh</button>
        </div>
        <div id="chart" class="flex items-end gap-2 h-40"></div>
        <div id="chart-labels" class="flex justify-between text-xs text-[var(--text-secondary)] mt-2"></div>
      </div>

      <div class="bg-[var(--bg-surface)] p-6 rounded-lg border border-[var(--border)]">
        <h3 class="text-lg font-semibold mb-4">Recent Activity</h3>
        <div id="activity" class="space-y-3 scrollbox"></div>
      </div>
    </section>

    <!-- Model & Config -->
    <section id="model" class="bg-[var(--bg-surface)] p-6 rounded-lg border border-[var(--border)]">
      <div class="flex items-center justify-between">
        <h3 class="text-lg font-semibold">Model / Configuration</h3>
        <div class="flex gap-2">
          <button id="btn-train-fast" class="btn btn-primary">Train (Fast)</button>
          <button id="btn-train-full" class="btn btn-primary">Train (Full)</button>
        </div>
      </div>

      <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-5">
        <div class="p-4 border border-[var(--border)] rounded-lg">
          <label class="text-sm text-[var(--text-secondary)]">LBPH Threshold (55–95)</label>
          <input id="thr" type="range" min="55" max="95" step="1" class="w-full mt-2">
          <div class="flex justify-between text-sm mt-1"><span>Current:</span><span id="thr-val">—</span></div>
          <button id="btn-save-thr" class="mt-3 btn btn-primary">Save</button>
        </div>
        <div class="p-4 border border-[var(--border)] rounded-lg">
          <label class="text-sm text-[var(--text-secondary)]">Min Face Box Size</label>
          <input id="minbox" type="number" class="w-full mt-2 px-3 py-2 border border-[var(--border)] rounded" placeholder="e.g. 60">
          <button id="btn-save-box" class="mt-3 btn btn-primary">Save</button>
        </div>
        <div class="p-4 border border-[var(--border)] rounded-lg">
          <label class="text-sm text-[var(--text-secondary)]">Dataset / Training</label>
          <div id="train-status" class="text-sm mt-2 text-[var(--text-secondary)]">Idle</div>
        </div>
      </div>
    </section>

    <!-- Users -->
    <section id="users" class="bg-[var(--bg-surface)] p-6 rounded-lg border border-[var(--border)]">
      <div class="flex items-center justify-between mb-3">
        <h3 class="text-lg font-semibold">Users</h3>
        <div class="flex gap-2">
          <input id="u-search" class="px-3 py-2 border border-[var(--border)] rounded" placeholder="Search users…">
          <button id="btn-new-user" class="btn btn-primary">New User</button>
        </div>
      </div>

      <div class="overflow-auto border border-[var(--border)] rounded">
        <table class="w-full text-sm">
          <thead class="bg-gray-50">
          <tr>
            <th class="text-left p-2 border-b">ID</th>
            <th class="text-left p-2 border-b">Email</th>
            <th class="text-left p-2 border-b">Name</th>
            <th class="text-left p-2 border-b">Role</th>
            <th class="text-left p-2 border-b">Class</th>
            <th class="text-left p-2 border-b">Status</th>
            <th class="text-left p-2 border-b">Actions</th>
          </tr>
          </thead>
          <tbody id="users-tbody"></tbody>
        </table>
      </div>
      <div id="users-count" class="mt-2 text-sm text-[var(--text-secondary)]"></div>
    </section>

    <!-- Students -->
    <section id="students" class="bg-[var(--bg-surface)] p-6 rounded-lg border border-[var(--border)]">
      <div class="flex items-center justify-between mb-3">
        <h3 class="text-lg font-semibold">Students</h3>
        <div class="flex gap-2">
          <input id="s-search" class="px-3 py-2 border border-[var(--border)] rounded" placeholder="Search students…">
          <button id="btn-new-student" class="btn btn-primary">New Student</button>
        </div>
      </div>

      <div class="overflow-auto border border-[var(--border)] rounded">
        <table class="w-full text-sm">
          <thead class="bg-gray-50">
          <tr>
            <th class="text-left p-2 border-b">ID</th>
            <th class="text-left p-2 border-b">Code</th>
            <th class="text-left p-2 border-b">Name</th>
            <th class="text-left p-2 border-b">Class</th>
            <th class="text-left p-2 border-b">Faces</th>
            <th class="text-left p-2 border-b">Actions</th>
          </tr>
          </thead>
          <tbody id="students-tbody"></tbody>
        </table>
      </div>
      <div id="students-count" class="mt-2 text-sm text-[var(--text-secondary)]"></div>
      <p class="text-xs text-[var(--text-secondary)] mt-2">Tip: After capturing photos, re-train the model from the Model tab.</p>
    </section>

    <!-- Attendance -->
    <section id="attendance" class="bg-[var(--bg-surface)] p-6 rounded-lg border border-[var(--border)]">
      <div class="flex items-center justify-between mb-4">
        <h3 class="text-lg font-semibold">Attendance</h3>
        <div class="flex gap-2">
          <input id="att-date" type="date" class="px-3 py-2 border border-[var(--border)] rounded">
          <button id="btn-att-search" class="btn btn-ghost">Search</button>
          <button id="btn-export" class="btn btn-primary">Export CSV</button>
          <button id="btn-go-attendance" class="btn btn-primary">Take Attendance</button>
        </div>
      </div>
      <div class="overflow-auto border border-[var(--border)] rounded">
        <table class="w-full text-sm">
          <thead class="bg-gray-50">
          <tr>
            <th class="text-left p-2 border-b">Date</th>
            <th class="text-left p-2 border-b">Time In</th>
            <th class="text-left p-2 border-b">Source</th>
            <th class="text-left p-2 border-b">Code</th>
            <th class="text-left p-2 border-b">Name</th>
            <th class="text-left p-2 border-b">Class</th>
          </tr>
          </thead>
          <tbody id="att-tbody"></tbody>
        </table>
      </div>
      <div id="att-count" class="mt-2 text-sm text-[var(--text-secondary)]"></div>
    </section>

    <!-- Settings / About -->
    <section id="settings" class="bg-[var(--bg-surface)] p-6 rounded-lg border border-[var(--border)]">
      <h3 class="text-lg font-semibold mb-2">About</h3>
      <p class="text-sm text-[var(--text-secondary)]">This Super Admin dashboard includes Students CRUD and inline face capture for enrollment. No backend functionality was removed.</p>
    </section>
  </main>
</div>

<!-- User Modal -->
<div id="user-modal" class="fixed inset-0 bg-black/40 hidden items-center justify-center z-50">
  <div class="bg-white rounded-lg p-5 border border-[var(--border)] w-full max-w-lg">
    <h3 id="user-modal-title" class="text-lg font-semibold mb-3">New User</h3>
    <div class="grid grid-cols-1 md:grid-cols-2 gap-3">
      <input id="m-email" class="px-3 py-2 border border-[var(--border)] rounded" placeholder="Email">
      <input id="m-name" class="px-3 py-2 border border-[var(--border)] rounded" placeholder="Full name">
      <input id="m-pass" class="px-3 py-2 border border-[var(--border)] rounded" placeholder="Password (leave blank to keep)">
      <select id="m-role" class="px-3 py-2 border border-[var(--border)] rounded">
        <option value="admin">admin</option>
        <option value="teacher">teacher</option>
        <option value="student">student</option>
        <option value="super_admin">super_admin</option>
        <option value="guest">guest</option>
      </select>
      <input id="m-class" class="px-3 py-2 border border-[var(--border)] rounded" placeholder="Class (optional)">
    </div>
    <div class="flex justify-end gap-2 mt-4">
      <button id="user-cancel" class="btn btn-ghost">Cancel</button>
      <button id="user-save" class="btn btn-primary">Save</button>
    </div>
  </div>
</div>

<!-- Student Modal (Create/Edit) -->
<div id="student-modal" class="fixed inset-0 bg-black/40 hidden items-center justify-center z-50">
  <div class="bg-white rounded-lg p-5 border border-[var(--border)] w-full max-w-lg">
    <h3 id="student-modal-title" class="text-lg font-semibold mb-3">New Student</h3>
    <div class="grid grid-cols-1 md:grid-cols-2 gap-3">
      <input id="s-code" class="px-3 py-2 border border-[var(--border)] rounded" placeholder="Student Code">
      <input id="s-name" class="px-3 py-2 border border-[var(--border)] rounded" placeholder="Full name">
      <input id="s-class" class="px-3 py-2 border border-[var(--border)] rounded" placeholder="Class (e.g., 10-A)">
    </div>
    <div class="flex justify-between items-center mt-4">
      <div class="text-xs text-[var(--text-secondary)]">After saving, use “Capture Faces” to enroll.</div>
      <div class="flex gap-2">
        <button id="student-cancel" class="btn btn-ghost">Cancel</button>
        <button id="student-save" class="btn btn-primary">Save</button>
      </div>
    </div>
  </div>
</div>

<!-- Capture Modal -->
<div id="capture-modal" class="fixed inset-0 bg-black/50 hidden items-center justify-center z-50">
  <div class="bg-white rounded-lg p-5 border border-[var(--border)] w-full max-w-2xl">
    <h3 class="text-lg font-semibold mb-3">Capture Faces for <span id="cap-student-code" class="font-mono"></span></h3>
    <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
      <div class="relative">
        <video id="cap-video" autoplay playsinline class="w-full rounded bg-black"></video>
        <canvas id="cap-canvas" width="640" height="480" class="hidden"></canvas>
      </div>
      <div>
        <p class="text-sm text-[var(--text-secondary)]">Take 3–5 clear shots. Vary lighting/angles slightly.</p>
        <div id="cap-grid" class="grid grid-cols-5 gap-2 my-3"></div>
        <div class="flex gap-2">
          <button id="cap-start" class="btn btn-ghost">Start Camera</button>
          <button id="cap-capture" class="btn btn-primary" disabled>Capture</button>
          <button id="cap-reset" class="btn btn-ghost" disabled>Reset</button>
          <button id="cap-upload" class="btn btn-primary" disabled>Upload</button>
        </div>
        <div id="cap-status" class="text-xs text-[var(--text-secondary)] mt-2">Idle.</div>
      </div>
    </div>
    <div class="flex justify-end mt-4">
      <button id="cap-close" class="btn btn-ghost">Close</button>
    </div>
  </div>
</div>

<script>
  // ----- Nav -----
  const pageTitle = document.getElementById('page-title');
  document.querySelectorAll('.nav-item').forEach(el=>{
    el.addEventListener('click', ()=>{
      document.querySelectorAll('.nav-item').forEach(n=>n.classList.remove('active'));
      el.classList.add('active');
      setPage(el.dataset.page);
    });
  });
  function setPage(page){
    pageTitle.textContent = ({dashboard:"Dashboard",users:"Users",students:"Students",model:"Model",attendance:"Attendance",settings:"Settings"})[page] || "Dashboard";
    const sections = ["users","students","model","attendance","settings"];
    sections.forEach(id=>{ document.getElementById(id).style.display = (page===id) ? "block" : "none"; });
    // dashboard pieces visibility
    document.getElementById('cards').style.display      = page==="dashboard"?"grid":"none";
    document.getElementById('cards').nextElementSibling.style.display = page==="dashboard"?"grid":"none";
  }
  setPage("dashboard");

  // ----- Date helpers -----
  function fmtDate(d){ return d.toISOString().slice(0,10); }
  function addDays(d, n){ const x = new Date(d); x.setDate(x.getDate()+n); return x; }
  function last7Dates(){ const today = new Date(); const out=[]; for(let i=6;i>=0;i--){ out.push(addDays(today,-i)); } return out; }
  const dateRange = document.getElementById('date-range');
  function setRangeLabel(period){
    const now = new Date();
    if(period==="day"){ dateRange.textContent = "Today"; return; }
    if(period==="week"){ const end=fmtDate(now), start=fmtDate(addDays(now,-6)); dateRange.textContent = `${start} – ${end}`; return; }
    if(period==="month"){ const y=now.getFullYear(), m=now.getMonth()+1; const start=`${y}-${String(m).padStart(2,'0')}-01`; const end=fmtDate(now); dateRange.textContent=`${start} – ${end}`; return; }
    if(period==="year"){ dateRange.textContent = `${now.getFullYear()}-01-01 – ${fmtDate(now)}`; }
  }
  document.querySelectorAll('.time-filter-btn').forEach(b=>{
    b.addEventListener('click', ()=>{ document.querySelectorAll('.time-filter-btn').forEach(x=>x.classList.remove('active')); b.classList.add('active'); setRangeLabel(b.dataset.period); });
  });
  setRangeLabel("month");

  // ----- Metrics / API -----
  const cardStudents = document.getElementById('card-students');
  const cardUsers    = document.getElementById('card-users');
  const rolesMini    = document.getElementById('roles-mini');
  const cardToday    = document.getElementById('card-today');
  const cardModel    = document.getElementById('card-model');
  const barStudents  = document.getElementById('bar-students');
  const barUsers     = document.getElementById('bar-users');
  const barToday     = document.getElementById('bar-today');
  const barModel     = document.getElementById('bar-model');
  const badgeXml     = document.getElementById('badge-xml');
  const badgeLbl     = document.getElementById('badge-lbl');
  const badgeCfg     = document.getElementById('badge-cfg');

  async function fetchTodayCount(){
    const d = fmtDate(new Date());
    const j = await fetch(`/api/attendance?date=${d}`).then(r=>r.json());
    if(j.ok){ cardToday.textContent = j.rows.length.toString(); barToday.style.width = Math.min(100, j.rows.length)+"%"; }
  }
  async function fetchModel(){
    const j = await fetch('/api/health').then(r=>r.json());
    if(!j.ok) return;
    const ready = j.model_ready;
    cardModel.textContent = ready ? `Ready (${j.students} labels)` : 'Not Ready';
    barModel.style.width = ready ? "100%" : "35%";
    function setBadge(el, ok){ el.className = `badge ${ok?'bg-green-100 text-green-700':'bg-red-100 text-red-700'} border border-[var(--border)]`; }
    setBadge(badgeXml, j.model_files.xml); setBadge(badgeLbl, j.model_files.labels); setBadge(badgeCfg, j.model_files.config);
    try {
      const c = await fetch('/api/config').then(r=>r.json());
      if(c.ok){ document.getElementById('thr').value = c.config.lbph_threshold ?? 75; document.getElementById('thr-val').textContent = c.config.lbph_threshold ?? '—'; document.getElementById('minbox').value = c.min_box_size ?? 60; }
    } catch(e){}
  }
  async function populateTopCards(){
    const h = await fetch('/api/health').then(r=>r.json());
    if(h.ok){ cardStudents.textContent = h.students.toString(); barStudents.style.width = Math.min(100,h.students)+"%"; cardUsers.textContent = '—'; rolesMini.textContent = 'Use Users/Students tabs to manage.'; }
  }

  // Recent activity
  async function recentActivity(){
    const j = await fetch('/api/attendance').then(r=>r.json());
    const box = document.getElementById('activity'); box.innerHTML='';
    if(j.ok){
      const rows = (j.rows||[]).slice(0,20);
      for(const r of rows){
        const div = document.createElement('div');
        div.className = 'flex items-center gap-3';
        const dot = r.source==="auto" ? 'bg-green-500' : 'bg-blue-500';
        div.innerHTML = `<div class="w-2 h-2 ${dot} rounded-full"></div>
          <div><p class="text-sm"><span class="font-medium">${r.full_name}</span> <span class="text-[var(--text-secondary)]">(${r.student_code})</span></p>
          <p class="text-xs text-[var(--text-secondary)]">${r.attend_date} • ${r.time_in} • ${r.class_name} • <span class="uppercase">${r.source}</span></p></div>`;
        box.appendChild(div);
      }
    }
  }

  // Chart last 7 days
  async function buildChart(){
    const days = last7Dates();
    const labels = document.getElementById('chart-labels'); labels.innerHTML='';
    const chart = document.getElementById('chart'); chart.innerHTML='';
    for(const d of days){
      const ymd = fmtDate(d);
      const j = await fetch('/api/attendance?date='+ymd).then(r=>r.json());
      const count = j.ok ? (j.rows||[]).length : 0;
      const bar = document.createElement('div'); bar.className='chart-bar w-8'; bar.style.height='0%'; bar.dataset.h=Math.min(95,Math.round(count*8))+'%';
      chart.appendChild(bar);
      const lab = document.createElement('span'); lab.textContent = ymd.slice(5); labels.appendChild(lab);
      setTimeout(()=>{ bar.style.height = bar.dataset.h; }, 50);
    }
  }
  document.getElementById('btn-refresh-chart').addEventListener('click', buildChart);

  // ----- Config actions -----
  document.getElementById('btn-save-thr').addEventListener('click', async ()=>{
    const val = Number(document.getElementById('thr').value||75);
    const res = await fetch('/api/config/set',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({lbph_threshold:val})}).then(r=>r.json());
    if(res.ok){ document.getElementById('thr-val').textContent = res.config.lbph_threshold; toast('Threshold saved'); } else toast('Save failed: '+(res.error||''),'err');
  });
  document.getElementById('thr').addEventListener('input', e=>{ document.getElementById('thr-val').textContent = e.target.value; });
  document.getElementById('btn-save-box').addEventListener('click', async ()=>{
    const v = Number(document.getElementById('minbox').value||60);
    const res = await fetch('/api/config/set',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({min_box_size:v})}).then(r=>r.json());
    if(res.ok) toast('Min box saved'); else toast('Save failed','err');
  });

  // ----- Attendance table + button redirect -----
  const tbody = document.getElementById('att-tbody');
  const attCount = document.getElementById('att-count');
  function renderRows(rows){
    tbody.innerHTML='';
    for(const r of rows){
      const tr = document.createElement('tr');
      tr.innerHTML = `<td class="p-2 border-b">${r.attend_date}</td>
        <td class="p-2 border-b">${r.time_in}</td>
        <td class="p-2 border-b">${r.source}</td>
        <td class="p-2 border-b">${r.student_code}</td>
        <td class="p-2 border-b">${r.full_name}</td>
        <td class="p-2 border-b">${r.class_name}</td>`;
      tbody.appendChild(tr);
    }
    attCount.textContent = `${rows.length} record(s)`;
  }
  async function loadAttendance(date=null){
    const url = date? `/api/attendance?date=${date}` : '/api/attendance';
    const j = await fetch(url).then(r=>r.json());
    if(j.ok) renderRows(j.rows||[]);
  }
  (function seedDate(){ const d=new Date(); const m=String(d.getMonth()+1).padStart(2,'0'); const day=String(d.getDate()).padStart(2,'0'); document.getElementById('att-date').value = `${d.getFullYear()}-${m}-${day}`; })();
  document.getElementById('btn-att-search').addEventListener('click', ()=>{ const d=document.getElementById('att-date').value||null; loadAttendance(d); });
  document.getElementById('btn-export').addEventListener('click', ()=>{ const d=document.getElementById('att-date').value; const url=d? `/api/attendance/export?date=${d}`:'/api/attendance/export'; window.location.href=url; });
  document.getElementById('btn-go-attendance').addEventListener('click', ()=>{ window.location.href='/attendance'; });

  // ----- Users table -----
  const usersTbody = document.getElementById('users-tbody');
  const usersCount = document.getElementById('users-count');
  let USERS = [];
  function statusPill(role){
    const disabled = role === 'guest';
    return `<span class="pill ${disabled?'bg-red-100 text-red-700':'bg-green-100 text-green-700'}">${disabled?'disabled':'enabled'}</span>`;
  }
  function renderUsers(rows){
    USERS = rows || [];
    usersTbody.innerHTML = '';
    USERS.forEach(u=>{
      const tr = document.createElement('tr');
      tr.innerHTML = `
        <td class="p-2 border-b">${u.id}</td>
        <td class="p-2 border-b">${u.email}</td>
        <td class="p-2 border-b">${u.full_name}</td>
        <td class="p-2 border-b">${u.role}</td>
        <td class="p-2 border-b">${u.class_name??''}</td>
        <td class="p-2 border-b">${statusPill(u.role)}</td>
        <td class="p-2 border-b">
          <button class="btn btn-ghost text-blue-700" data-act="edit" data-id="${u.id}">Edit</button>
          <button class="btn btn-danger" data-act="delete" data-id="${u.id}">Delete</button>
          ${u.role==='guest'
            ? `<button class="btn btn-primary" data-act="enable" data-id="${u.id}">Enable</button>`
            : `<button class="btn btn-ghost" data-act="disable" data-id="${u.id}">Disable</button>`}
        </td>`;
      usersTbody.appendChild(tr);
    });
    usersCount.textContent = `${USERS.length} user(s)`;
  }
  async function loadUsers(){
    const j = await fetch('/api/users').then(r=>r.json()).catch(()=>({ok:false}));
    if(j.ok) renderUsers(j.rows||[]);
  }
  document.getElementById('u-search').addEventListener('input', e=>{
    const q=(e.target.value||'').toLowerCase();
    Array.from(usersTbody.children).forEach(tr=>{
      tr.style.display = tr.textContent.toLowerCase().includes(q)? '' : 'none';
    });
  });

  // User modal
  const userModal = document.getElementById('user-modal');
  const userTitle = document.getElementById('user-modal-title');
  const mEmail = document.getElementById('m-email');
  const mName = document.getElementById('m-name');
  const mPass = document.getElementById('m-pass');
  const mRole = document.getElementById('m-role');
  const mClass= document.getElementById('m-class');
  const btnUserSave = document.getElementById('user-save');
  let editUserId = null;

  function openUserModal(title){ userTitle.textContent=title; userModal.classList.remove('hidden'); userModal.classList.add('flex'); }
  function closeUserModal(){ userModal.classList.add('hidden'); userModal.classList.remove('flex'); editUserId=null; mPass.value=''; }
  document.getElementById('user-cancel').addEventListener('click', closeUserModal);
  document.getElementById('btn-new-user').addEventListener('click', ()=>{
    editUserId=null; mEmail.value=''; mName.value=''; mPass.value=''; mRole.value='admin'; mClass.value='';
    openUserModal('New User');
  });

  btnUserSave.addEventListener('click', async ()=>{
    const payload = { email:mEmail.value.trim(), full_name:mName.value.trim(), role:mRole.value, class_name:mClass.value.trim()||null };
    if(mPass.value) payload.password = mPass.value;
    let res;
    if(editUserId){ payload.id = editUserId; res = await fetch('/api/users/update',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}).then(r=>r.json()); }
    else { payload.password = mPass.value || '123456'; res = await fetch('/users/create',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}).then(r=>r.json()); }
    if(res.ok){ toast('Saved'); await loadUsers(); closeUserModal(); } else toast(res.error||'Save failed','err');
  });

  usersTbody.addEventListener('click', async (e)=>{
    const btn = e.target.closest('button'); if(!btn) return;
    const id = Number(btn.dataset.id);
    const act = btn.dataset.act;
    const user = USERS.find(x=>x.id===id);

    if(act==='edit'){
      editUserId = id; mEmail.value=user.email; mName.value=user.full_name; mRole.value=user.role; mClass.value=user.class_name||'';
      openUserModal('Edit User #'+id);
    }
    if(act==='delete'){
      if(!confirm('Delete this user?')) return;
      const res = await fetch('/api/users/delete',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id})}).then(r=>r.json());
      if(res.ok){ toast('Deleted'); loadUsers(); } else toast(res.error||'Delete failed','err');
    }
    if(act==='disable'){
      const res = await fetch('/api/users/update',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id, role:'guest'})}).then(r=>r.json());
      if(res.ok){ toast('Disabled'); loadUsers(); } else toast(res.error||'Disable failed','err');
    }
    if(act==='enable'){
      editUserId = id; mEmail.value=user.email; mName.value=user.full_name; mRole.value='admin'; mClass.value=user.class_name||'';
      openUserModal('Enable User #'+id+' (choose role)');
    }
  });

  // ----- Students table -----
  const studentsTbody = document.getElementById('students-tbody');
  const studentsCount = document.getElementById('students-count');
  let STUDENTS = [];
  function renderStudents(rows){
    STUDENTS = rows||[];
    studentsTbody.innerHTML='';
    STUDENTS.forEach(s=>{
      const tr = document.createElement('tr');
      tr.innerHTML = `
        <td class="p-2 border-b">${s.id}</td>
        <td class="p-2 border-b font-mono">${s.student_code}</td>
        <td class="p-2 border-b">${s.full_name}</td>
        <td class="p-2 border-b">${s.class_name??''}</td>
        <td class="p-2 border-b">${s.face_count}</td>
        <td class="p-2 border-b">
          <button class="btn btn-ghost text-blue-700" data-sact="edit" data-id="${s.id}">Edit</button>
          <button class="btn btn-danger" data-sact="delete" data-id="${s.id}">Delete</button>
          <button class="btn btn-primary" data-sact="capture" data-code="${s.student_code}">Capture Faces</button>
        </td>`;
      studentsTbody.appendChild(tr);
    });
    studentsCount.textContent = `${STUDENTS.length} student(s)`;
  }
  async function loadStudents(){
    const j = await fetch('/api/students').then(r=>r.json()).catch(()=>({ok:false}));
    if(j.ok) renderStudents(j.rows||[]);
  }
  document.getElementById('s-search').addEventListener('input', e=>{
    const q=(e.target.value||'').toLowerCase();
    Array.from(studentsTbody.children).forEach(tr=>{
      tr.style.display = tr.textContent.toLowerCase().includes(q)? '' : 'none';
    });
  });

  // Student modal
  const studentModal = document.getElementById('student-modal');
  const studentTitle = document.getElementById('student-modal-title');
  const sCode = document.getElementById('s-code');
  const sName = document.getElementById('s-name');
  const sClass = document.getElementById('s-class');
  const btnStudentSave = document.getElementById('student-save');
  let editStudentId = null;

  function openStudentModal(title){ studentTitle.textContent=title; studentModal.classList.remove('hidden'); studentModal.classList.add('flex'); }
  function closeStudentModal(){ studentModal.classList.add('hidden'); studentModal.classList.remove('flex'); editStudentId=null; }
  document.getElementById('student-cancel').addEventListener('click', closeStudentModal);
  document.getElementById('btn-new-student').addEventListener('click', ()=>{
    editStudentId=null; sCode.value=''; sName.value=''; sClass.value='';
    openStudentModal('New Student');
  });

  btnStudentSave.addEventListener('click', async ()=>{
    const payload = { student_code:sCode.value.trim(), full_name:sName.value.trim(), class_name:sClass.value.trim()||null };
    let res;
    if(editStudentId){ payload.id = editStudentId; res = await fetch('/api/students/update',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}).then(r=>r.json()); }
    else { res = await fetch('/api/students/create',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}).then(r=>r.json()); }
    if(res.ok){ toast('Saved'); await loadStudents(); closeStudentModal(); } else toast(res.error||'Save failed','err');
  });

  // Students row actions
  studentsTbody.addEventListener('click', async (e)=>{
    const btn = e.target.closest('button'); if(!btn) return;
    const act = btn.dataset.sact;
    if(act==='edit'){
      const id = Number(btn.dataset.id);
      const st = STUDENTS.find(x=>x.id===id);
      editStudentId = id; sCode.value=st.student_code; sName.value=st.full_name; sClass.value=st.class_name||'';
      openStudentModal('Edit Student #'+id);
    }
    if(act==='delete'){
      const id = Number(btn.dataset.id);
      if(!confirm('Delete this student (and optionally photos)?')) return;
      const res = await fetch('/api/students/delete',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id, remove_photos:true})}).then(r=>r.json());
      if(res.ok){ toast('Deleted'); loadStudents(); } else toast(res.error||'Delete failed','err');
    }
    if(act==='capture'){
      const code = btn.dataset.code;
      openCaptureModal(code);
    }
  });

  // ----- Capture popup -----
  const capModal = document.getElementById('capture-modal');
  const capCodeEl= document.getElementById('cap-student-code');
  const capVideo = document.getElementById('cap-video');
  const capCanvas= document.getElementById('cap-canvas');
  const capStart = document.getElementById('cap-start');
  const capCapture=document.getElementById('cap-capture');
  const capReset = document.getElementById('cap-reset');
  const capUpload= document.getElementById('cap-upload');
  const capGrid  = document.getElementById('cap-grid');
  const capStatus= document.getElementById('cap-status');
  const capClose = document.getElementById('cap-close');
  let capStream=null, CAPTURES=[];

  function openCaptureModal(code){
    capCodeEl.textContent = code;
    CAPTURES=[]; capGrid.innerHTML=''; updateCapButtons();
    capModal.classList.remove('hidden'); capModal.classList.add('flex');
    capStatus.textContent='Idle.';
  }
  async function startCamera(){
    if(capStream) return;
    try{
      capStream = await navigator.mediaDevices.getUserMedia({video:{width:{ideal:1280},height:{ideal:720},facingMode:'user'},audio:false});
      capVideo.srcObject = capStream;
      await new Promise(r=>{capVideo.onloadedmetadata=r;});
      capStatus.textContent='Camera ready.';
      capCapture.disabled=false; capReset.disabled=false;
    }catch(e){
      capStatus.textContent='Webcam error: '+e.message;
    }
  }
  function stopCamera(){ if(capStream){ capStream.getTracks().forEach(t=>t.stop()); capStream=null; capVideo.srcObject=null; } }
  function updateCapButtons(){
    capUpload.disabled = CAPTURES.length < 3;
    capReset.disabled  = CAPTURES.length===0 && !capStream;
  }
  function captureOne(){
    const w = 640, h = 480;
    capCanvas.width=w; capCanvas.height=h;
    const ctx = capCanvas.getContext('2d');
    ctx.drawImage(capVideo, (capVideo.videoWidth-w)/2, (capVideo.videoHeight-h)/2, w, h, 0, 0, w, h);
    const dataURL = capCanvas.toDataURL('image/jpeg',0.9);
    CAPTURES.push(dataURL);
    const img = new Image(); img.src=dataURL; img.className='w-full rounded border border-[var(--border)]';
    const wrapper=document.createElement('div'); wrapper.appendChild(img); capGrid.appendChild(wrapper);
    capStatus.textContent = `Captured ${CAPTURES.length} / 5`;
    if(CAPTURES.length>=5){ capCapture.disabled=true; }
    updateCapButtons();
  }
  async function uploadCaptures(){
    const student_code = capCodeEl.textContent;
    capStatus.textContent='Uploading…';
    const res = await fetch('/api/students/enroll',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({student_code, images:CAPTURES})}).then(r=>r.json()).catch(e=>({ok:false,error:e.message}));
    if(res.ok){ capStatus.textContent=`Uploaded ${res.saved} image(s).`; toast('Enrollment images saved'); loadStudents(); }
    else { capStatus.textContent='Upload failed: '+(res.error||''); toast('Upload failed','err'); }
  }
  function resetCaptures(){
    CAPTURES=[]; capGrid.innerHTML=''; capStatus.textContent='Reset. Capture again.';
    capCapture.disabled=false; updateCapButtons();
  }
  function closeCapture(){
    stopCamera(); CAPTURES=[]; capGrid.innerHTML=''; capModal.classList.add('hidden'); capModal.classList.remove('flex');
  }
  capStart.addEventListener('click', startCamera);
  capCapture.addEventListener('click', captureOne);
  capUpload.addEventListener('click', uploadCaptures);
  capReset.addEventListener('click', resetCaptures);
  capClose.addEventListener('click', closeCapture);

  // ----- Toast -----
  function toast(msg, kind='ok'){
    const n = document.createElement('div');
    n.className = `fixed top-4 right-4 px-4 py-2 rounded shadow text-white z-50 ${kind==='ok'?'bg-green-600':'bg-red-600'}`;
    n.textContent = msg; document.body.appendChild(n);
    setTimeout(()=>{ n.style.opacity='0'; n.style.transform='translateY(-10px)'; setTimeout(()=>n.remove(), 250); }, 2000);
  }

  // ----- Boot -----
  (async function boot(){
    await fetchModel();
    await fetchTodayCount();
    await populateTopCards();
    await buildChart();
    await recentActivity();
    // attendance
    const d=new Date(); const m=String(d.getMonth()+1).padStart(2,'0'); const day=String(d.getDate()).padStart(2,'0');
    await loadAttendance(`${d.getFullYear()}-${m}-${day}`);
    // users/students
    await loadUsers();
    await loadStudents();
    // animate
    setTimeout(()=>{ barStudents.style.width = barStudents.style.width || '80%'; }, 300);
    setTimeout(()=>{ barUsers.style.width = '65%'; }, 350);
  })();
</script>
</body>
</html>
