(() => {
  'use strict';
  const STORAGE_KEY='apu_student_performance_records_v37';
  const seed=[
    {id:'STU-2401',name:'Alya Putri',className:'10-A',attendance:94,studyHours:3.5,previousScore:86,assignments:92,predictedScore:89,risk:'low',status:'active',createdAt:'2026-06-09T08:00:00.000Z'},
    {id:'STU-2402',name:'Bima Saputra',className:'10-B',attendance:78,studyHours:1.5,previousScore:67,assignments:72,predictedScore:69,risk:'medium',status:'active',createdAt:'2026-06-09T08:10:00.000Z'},
    {id:'STU-2403',name:'Citra Lestari',className:'11-A',attendance:97,studyHours:4.2,previousScore:91,assignments:95,predictedScore:93,risk:'low',status:'active',createdAt:'2026-06-10T09:00:00.000Z'},
    {id:'STU-2404',name:'Daffa Pratama',className:'11-B',attendance:64,studyHours:.8,previousScore:55,assignments:58,predictedScore:56,risk:'high',status:'needs-support',createdAt:'2026-06-11T10:30:00.000Z'},
    {id:'STU-2405',name:'Eka Wulandari',className:'12-A',attendance:84,studyHours:2.3,previousScore:74,assignments:79,predictedScore:77,risk:'medium',status:'active',createdAt:'2026-06-12T07:40:00.000Z'}
  ];
  const $=(s,r=document)=>r.querySelector(s), $$=(s,r=document)=>[...r.querySelectorAll(s)];
  const esc=v=>String(v??'').replace(/[&<>'"]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;',"'":'&#39;','"':'&quot;'}[c]));
  const clamp=(v,min,max)=>Math.min(max,Math.max(min,Number(v)||0));
  const uid=()=>`STU-${Date.now().toString(36).toUpperCase()}${Math.random().toString(36).slice(2,5).toUpperCase()}`;
  function predict(attendance,studyHours,previousScore,assignments){
    const score=clamp(previousScore,0,100)*.46+clamp(assignments,0,100)*.24+clamp(attendance,0,100)*.20+Math.min(clamp(studyHours,0,12),8)*1.25;
    return Math.round(clamp(score,0,100));
  }
  function riskFor(score,attendance){ if(score<60||attendance<70)return'high';if(score<78||attendance<85)return'medium';return'low'; }
  function normalize(x){
    const attendance=clamp(x?.attendance,0,100),studyHours=clamp(x?.studyHours,0,12),previousScore=clamp(x?.previousScore,0,100),assignments=clamp(x?.assignments,0,100);
    const predictedScore=Number.isFinite(Number(x?.predictedScore))?clamp(x.predictedScore,0,100):predict(attendance,studyHours,previousScore,assignments);
    return {id:String(x?.id||uid()),name:String(x?.name||'').trim(),className:String(x?.className||'-').trim(),attendance,studyHours,previousScore,assignments,predictedScore,risk:riskFor(predictedScore,attendance),status:['active','needs-support','completed'].includes(x?.status)?x.status:'active',createdAt:x?.createdAt&&!Number.isNaN(Date.parse(x.createdAt))?x.createdAt:new Date().toISOString()};
  }
  const load=()=>{try{const x=JSON.parse(localStorage.getItem(STORAGE_KEY));return Array.isArray(x)?x.map(normalize).filter(r=>r.name):seed.map(normalize);}catch(_){return seed.map(normalize);}};
  let rows=load(),editingId='',sortMode='name';
  const save=()=>localStorage.setItem(STORAGE_KEY,JSON.stringify(rows));
  function toast(m){const e=$('#apuStudentToast');if(!e)return;e.textContent=m;e.classList.add('is-visible');clearTimeout(e._t);e._t=setTimeout(()=>e.classList.remove('is-visible'),1900);}
  function download(name,content,type){const b=new Blob([content],{type}),u=URL.createObjectURL(b),a=document.createElement('a');a.href=u;a.download=name;document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(u),500);}
  const csvCell=v=>`"${String(v??'').replace(/"/g,'""')}"`;
  function filtered(){const q=($('#stuSearch')?.value||'').toLowerCase().trim(),risk=$('#stuRiskFilter')?.value||'all',status=$('#stuStatusFilter')?.value||'all';const out=rows.filter(r=>(!q||[r.id,r.name,r.className].join(' ').toLowerCase().includes(q))&&(risk==='all'||r.risk===risk)&&(status==='all'||r.status===status));return out.sort((a,b)=>sortMode==='score'?b.predictedScore-a.predictedScore:sortMode==='risk'?['high','medium','low'].indexOf(a.risk)-['high','medium','low'].indexOf(b.risk):a.name.localeCompare(b.name));}
  function renderStats(){const total=rows.length,avg=total?Math.round(rows.reduce((s,r)=>s+r.predictedScore,0)/total):0,high=rows.filter(r=>r.risk==='high').length,attendance=total?Math.round(rows.reduce((s,r)=>s+r.attendance,0)/total):0;$('#stuTotal').textContent=total;$('#stuAverage').textContent=avg;$('#stuHighRisk').textContent=high;$('#stuAttendance').textContent=`${attendance}%`;const bins={low:rows.filter(r=>r.risk==='low').length,medium:rows.filter(r=>r.risk==='medium').length,high};Object.entries(bins).forEach(([k,v])=>{const p=total?Math.round(v/total*100):0;const bar=$(`[data-stu-bar="${k}"]`),val=$(`[data-stu-value="${k}"]`);if(bar)bar.style.width=`${p}%`;if(val)val.textContent=`${p}%`;});}
  function render(){renderStats();const body=$('#stuTableBody');if(!body)return;const data=filtered();body.innerHTML=data.length?data.map(r=>`<tr><td><input type="checkbox" class="stu-row-check" value="${esc(r.id)}" aria-label="Pilih ${esc(r.id)}"></td><td><code>${esc(r.id)}</code><br><small>${esc(r.className)}</small></td><td><strong>${esc(r.name)}</strong><br><small>${esc(r.status)}</small></td><td>${r.attendance}%</td><td>${r.studyHours.toFixed(1)} jam</td><td>${Math.round(r.previousScore)}</td><td>${Math.round(r.assignments)}</td><td><strong>${Math.round(r.predictedScore)}</strong></td><td><span class="apu-badge apu-badge--${r.risk}">${r.risk}</span></td><td class="apu-row-actions"><button class="apu-btn stu-edit" data-id="${esc(r.id)}">Edit</button><button class="apu-btn apu-btn--danger stu-delete" data-id="${esc(r.id)}">Hapus</button></td></tr>`).join(''):'<tr><td colspan="10" class="apu-empty">Tidak ada data yang cocok.</td></tr>';}
  function resetForm(){editingId='';$('#stuForm')?.reset();$('#stuFormTitle').textContent='Tambah profil siswa';$('#stuSubmit').textContent='Simpan & prediksi';$('#stuAttendanceInput').value='85';$('#stuStudyHours').value='2';$('#stuPreviousScore').value='75';$('#stuAssignments').value='78';}
  function edit(id){const r=rows.find(x=>x.id===id);if(!r)return;editingId=id;$('#stuName').value=r.name;$('#stuClass').value=r.className;$('#stuAttendanceInput').value=r.attendance;$('#stuStudyHours').value=r.studyHours;$('#stuPreviousScore').value=r.previousScore;$('#stuAssignments').value=r.assignments;$('#stuStatus').value=r.status;$('#stuFormTitle').textContent=`Edit ${r.id}`;$('#stuSubmit').textContent='Perbarui & hitung ulang';$('#stuName').focus();$('#apuStudentStudio').scrollIntoView({behavior:'smooth',block:'start'});}
  function submit(e){e.preventDefault();const name=$('#stuName').value.trim();if(!name){toast('Nama siswa wajib diisi.');return;}const attendance=clamp($('#stuAttendanceInput').value,0,100),studyHours=clamp($('#stuStudyHours').value,0,12),previousScore=clamp($('#stuPreviousScore').value,0,100),assignments=clamp($('#stuAssignments').value,0,100),predictedScore=predict(attendance,studyHours,previousScore,assignments);const record=normalize({id:editingId||uid(),name,className:$('#stuClass').value,attendance,studyHours,previousScore,assignments,predictedScore,status:$('#stuStatus').value,createdAt:editingId?rows.find(x=>x.id===editingId)?.createdAt:new Date().toISOString()});const wasEditing=Boolean(editingId);if(wasEditing)rows=rows.map(x=>x.id===editingId?record:x);else rows.unshift(record);save();render();resetForm();toast(`${wasEditing?'Data diperbarui':'Profil ditambahkan'} · prediksi ${predictedScore}.`);}
  function mount(){if($('#apuStudentStudio'))return;const host=document.createElement('section');host.id='apuStudentStudio';host.className='apu-data-studio';host.innerHTML=`<div class="apu-studio-shell"><div class="apu-studio-hero"><div><span class="apu-studio-kicker">Student Performance · local prediction workspace</span><h2>Student Prediction Data Studio</h2><p>CRUD profil siswa, prediksi nilai, klasifikasi risiko, pencarian, filter, penghitungan ulang, impor, ekspor, dan ringkasan data dalam satu panel.</p></div><div class="apu-actions"><button class="apu-btn" id="stuRecalculate">Hitung ulang semua</button><button class="apu-btn" id="stuExportJson">Ekspor JSON</button><button class="apu-btn" id="stuExportCsv">Ekspor CSV</button><button class="apu-btn" id="stuImportBtn">Impor JSON</button><input class="apu-file" id="stuImportFile" type="file" accept="application/json"></div></div><div class="apu-studio-grid"><article class="apu-studio-card"><h3 id="stuFormTitle">Tambah profil siswa</h3><form id="stuForm" class="apu-studio-form"><div class="apu-studio-form-grid"><div class="apu-field"><label for="stuName">Nama siswa</label><input id="stuName" required placeholder="Nama lengkap"></div><div class="apu-field"><label for="stuClass">Kelas</label><input id="stuClass" value="10-A"></div><div class="apu-field"><label for="stuAttendanceInput">Kehadiran (%)</label><input id="stuAttendanceInput" type="number" min="0" max="100" value="85"></div><div class="apu-field"><label for="stuStudyHours">Jam belajar / hari</label><input id="stuStudyHours" type="number" min="0" max="12" step="0.1" value="2"></div><div class="apu-field"><label for="stuPreviousScore">Nilai sebelumnya</label><input id="stuPreviousScore" type="number" min="0" max="100" value="75"></div><div class="apu-field"><label for="stuAssignments">Nilai tugas</label><input id="stuAssignments" type="number" min="0" max="100" value="78"></div><div class="apu-field"><label for="stuStatus">Status</label><select id="stuStatus"><option value="active">Active</option><option value="needs-support">Needs support</option><option value="completed">Completed</option></select></div></div><div class="apu-actions"><button class="apu-btn apu-btn--primary" id="stuSubmit" type="submit">Simpan & prediksi</button><button class="apu-btn apu-btn--ghost" id="stuCancel" type="button">Bersihkan</button></div></form><h4>Distribusi risiko</h4><div class="apu-bars">${['low','medium','high'].map(k=>`<div class="apu-bar"><span>${k}</span><div class="apu-bar-track"><div class="apu-bar-fill" data-stu-bar="${k}"></div></div><b data-stu-value="${k}">0%</b></div>`).join('')}</div><p class="apu-note">Prediksi memakai formula demonstrasi berbobot dari nilai sebelumnya, tugas, kehadiran, dan jam belajar. Hasil bukan keputusan final akademik.</p></article><article class="apu-studio-card"><div class="apu-stats"><div class="apu-stat"><strong id="stuTotal">0</strong><span>Total siswa</span></div><div class="apu-stat"><strong id="stuAverage">0</strong><span>Rata-rata prediksi</span></div><div class="apu-stat"><strong id="stuHighRisk">0</strong><span>Risiko tinggi</span></div><div class="apu-stat"><strong id="stuAttendance">0%</strong><span>Avg. attendance</span></div></div><div class="apu-toolbar"><input id="stuSearch" type="search" placeholder="Cari ID, nama, atau kelas..."><select id="stuRiskFilter"><option value="all">Semua risiko</option><option value="low">Low</option><option value="medium">Medium</option><option value="high">High</option></select><select id="stuStatusFilter"><option value="all">Semua status</option><option value="active">Active</option><option value="needs-support">Needs support</option><option value="completed">Completed</option></select></div><div class="apu-actions" style="margin-bottom:12px"><select id="stuSort" class="apu-btn"><option value="name">Nama A–Z</option><option value="score">Prediksi tertinggi</option><option value="risk">Risiko tertinggi</option></select><button class="apu-btn apu-btn--danger" id="stuBulkDelete">Hapus terpilih</button><button class="apu-btn" id="stuReset">Pulihkan data demo</button></div><div class="apu-table-wrap"><table class="apu-table"><thead><tr><th>✓</th><th>ID / kelas</th><th>Siswa</th><th>Hadir</th><th>Belajar</th><th>Nilai lama</th><th>Tugas</th><th>Prediksi</th><th>Risiko</th><th>Operasi</th></tr></thead><tbody id="stuTableBody"></tbody></table></div></article></div></div><div class="apu-toast" id="apuStudentToast" role="status"></div>`;document.body.appendChild(host);const jump=document.createElement('button');jump.className='apu-studio-jump';jump.type='button';jump.textContent='Student Data ↓';jump.addEventListener('click',()=>host.scrollIntoView({behavior:'smooth'}));document.body.appendChild(jump);
    $('#stuForm').addEventListener('submit',submit);$('#stuCancel').addEventListener('click',resetForm);['#stuSearch','#stuRiskFilter','#stuStatusFilter'].forEach(s=>$(s).addEventListener('input',render));$('#stuSort').addEventListener('change',e=>{sortMode=e.target.value;render();});$('#stuTableBody').addEventListener('click',async e=>{const eb=e.target.closest('.stu-edit'),db=e.target.closest('.stu-delete');if(eb)edit(eb.dataset.id);if(db&&await APUDialog.confirm('Hapus profil ini?',{intent:'danger'})){rows=rows.filter(x=>x.id!==db.dataset.id);save();render();toast('Profil dihapus.');}});$('#stuBulkDelete').addEventListener('click',async()=>{const ids=$$('.stu-row-check:checked').map(x=>x.value);if(!ids.length){toast('Pilih profil terlebih dahulu.');return;}if(await APUDialog.confirm(`Hapus ${ids.length} profil?`,{intent:'danger'})){rows=rows.filter(x=>!ids.includes(x.id));save();render();toast('Profil terpilih dihapus.');}});$('#stuRecalculate').addEventListener('click',()=>{rows=rows.map(r=>normalize({...r,predictedScore:predict(r.attendance,r.studyHours,r.previousScore,r.assignments)}));save();render();toast('Semua prediksi dihitung ulang.');});$('#stuReset').addEventListener('click',async()=>{if(await APUDialog.confirm('Pulihkan data demo?',{intent:'danger'})){rows=seed.map(normalize);save();render();resetForm();toast('Data demo dipulihkan.');}});$('#stuExportJson').addEventListener('click',()=>download('student-performance-data.json',JSON.stringify(rows,null,2),'application/json'));$('#stuExportCsv').addEventListener('click',()=>download('student-performance-data.csv',[['id','name','className','attendance','studyHours','previousScore','assignments','predictedScore','risk','status','createdAt'].join(','),...rows.map(r=>[r.id,r.name,r.className,r.attendance,r.studyHours,r.previousScore,r.assignments,r.predictedScore,r.risk,r.status,r.createdAt].map(csvCell).join(','))].join('\n'),'text/csv;charset=utf-8'));$('#stuImportBtn').addEventListener('click',()=>$('#stuImportFile').click());$('#stuImportFile').addEventListener('change',async e=>{const f=e.target.files?.[0];if(!f)return;try{const d=JSON.parse(await f.text());if(!Array.isArray(d))throw new Error();rows=d.map(normalize).filter(x=>x.name);save();render();toast(`${rows.length} profil diimpor.`);}catch(_){toast('File JSON tidak valid.');}e.target.value='';});render();
  }
  if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',()=>setTimeout(mount,450),{once:true});else setTimeout(mount,450);
})();
