// Split from public/app.js v1.7.7. Loaded by public/index.html.
function adminOverview() {
  const { students, quizzes, attempts } = state.data;
  const payments = (state.data.payments || []).filter((payment) => payment.status !== 'cancelled');
  const courses = state.data.courses || [];
  const teacherPayments = state.data.teacherPayments || [];
  const employeePayments = state.data.employeePayments || [];
  const resultSmsPending = (state.data.resultSmsLogs || []).filter((item) => item.status !== 'sent').length;
  const todayKey = new Date().toISOString().slice(0, 10);
  const activeStudents = students.filter((student) => student.status === 'active').length;
  const inactiveStudents = students.length - activeStudents;
  const published = quizzes.filter((quiz) => quiz.status === 'published').length;
  const liveExams = quizzes.filter((quiz) => quiz.status === 'published' && isQuizLive(quiz)).length;
  const todayCollection = payments
    .filter((payment) => String(payment.paidAt || payment.createdAt || '').slice(0, 10) === todayKey)
    .reduce((sum, payment) => sum + Number(payment.amount || 0), 0);
  const totalCollection = payments.reduce((sum, payment) => sum + Number(payment.amount || 0), 0);
  const totalDue = students.reduce((sum, student) => sum + Number(student.finance?.totalDue || 0), 0);
  const teacherDue = teacherPayments.reduce((sum, payment) => sum + Number(payment.due ?? payment.dueAmount ?? 0), 0);
  const employeeDue = employeePayments.reduce((sum, payment) => sum + Number(payment.due ?? payment.dueAmount ?? 0), 0);
  const average = attempts.length
    ? Math.round(attempts.reduce((sum, attempt) => sum + attempt.percentage, 0) / attempts.length)
    : 0;
  const passRate = attempts.length ? Math.round((attempts.filter((attempt) => attempt.passed).length / attempts.length) * 100) : 0;
  const topCourses = courses.map((course) => ({
    name: course.name,
    students: students.filter((student) => (student.courseIds || []).includes(course.id)).length,
    due: students.reduce((sum, student) => sum + Number((student.finance?.enrollments || []).find((item) => item.courseId === course.id)?.due || 0), 0),
  })).sort((a, b) => b.students - a.students).slice(0, 5);
  const dashboardSearch = String(state.dashboardSearch || '').trim().toLowerCase();
  const quickSearchItems = dashboardQuickSearchItems(dashboardSearch).slice(0, 8);
  const qualityAlerts = dashboardQualityAlerts({ students, totalDue, liveExams, resultSmsPending });
  const warningCards = [
    totalDue > 0 ? ['Student Due', `${formatMoney(totalDue)} outstanding`, 'students'] : null,
    teacherDue > 0 ? ['Teacher Due', `${formatMoney(teacherDue)} pending`, 'payments'] : null,
    employeeDue > 0 ? ['Employee Due', `${formatMoney(employeeDue)} pending`, 'payments'] : null,
    resultSmsPending > 0 ? ['Result SMS', `${resultSmsPending} pending SMS`, 'results'] : null,
    !liveExams ? ['Live Exam', 'No live exam now', 'quizzes'] : null,
  ].filter(Boolean);

  return html`
    <section class="panel">
      <div class="panel-header">
        <div>
          <h1>Overview</h1>
          <p class="muted">Session health, collections, dues, results and shortcuts at a glance.</p>
        </div>
      </div>
      <div class="dashboard-hero-grid">
        <article class="dashboard-hero-card primary">
          <span>Today Collection</span>
          <strong>${formatMoney(todayCollection)}</strong>
          <small>Total session collection ${formatMoney(totalCollection)}</small>
        </article>
        <article class="dashboard-hero-card">
          <span>Active Students</span>
          <strong>${activeStudents}</strong>
          <small>${inactiveStudents} inactive Â· ${students.length} total</small>
        </article>
        <article class="dashboard-hero-card danger">
          <span>Total Due</span>
          <strong>${formatMoney(totalDue)}</strong>
          <small>Student course fee outstanding</small>
        </article>
        <article class="dashboard-hero-card">
          <span>Live Exams</span>
          <strong>${liveExams}</strong>
          <small>${published} published quizzes</small>
        </article>
        <article class="dashboard-hero-card success">
          <span>Pass Rate</span>
          <strong>${passRate}%</strong>
          <small>Average score ${average}%</small>
        </article>
      </div>
    </section>
    <section class="panel dashboard-search-panel">
      <div class="panel-header"><div><h2>Quick Search</h2><p class="muted">Find student, roll, mobile, receipt, course or quiz from one place.</p></div></div>
      <input class="dashboard-search-input" data-dashboard-search placeholder="Search student, roll, mobile, receipt, quiz..." value="${escapeHtml(state.dashboardSearch || '')}">
      <div class="quick-search-results">
        ${dashboardSearch ? quickSearchItems.map((item) => quickSearchResultCard(item)).join('') || '<div class="empty-state"><strong>No match found.</strong><span>Try another name, roll, mobile or receipt.</span></div>' : '<div class="empty-state"><strong>Start typing to search.</strong><span>Useful for student lookup, payment receipt and quiz shortcuts.</span></div>'}
      </div>
    </section>
    <section class="panel">
      <div class="panel-header"><div><h2>Quick Actions</h2><p class="muted">Jump to the most used workflows from one place.</p></div></div>
      <div class="quick-action-grid">
        <button class="quick-action-card" data-view="students"><strong>Add / Manage Students</strong><span>Create students, view due and print profile</span></button>
        <button class="quick-action-card" data-view="payments"><strong>Receive Payment</strong><span>Student fee collection and receipts</span></button>
        <button class="quick-action-card" data-view="quizzes"><strong>Create Quiz</strong><span>Build, duplicate and publish exams</span></button>
        <button class="quick-action-card" data-view="results"><strong>Result Reports</strong><span>Progress, result SMS and exports</span></button>
        <button class="quick-action-card" data-view="analytics"><strong>Analytics</strong><span>Course, finance and performance breakdown</span></button>
      </div>
    </section>
    <section class="dashboard-split">
      <div class="panel">
        <div class="panel-header"><div><h2>Attention Needed</h2><p class="muted">Important operational warnings.</p></div></div>
        <div class="alert-card-list">
          ${warningCards.map(([title, body, view]) => `<button class="alert-card" data-view="${view}"><strong>${escapeHtml(title)}</strong><span>${escapeHtml(body)}</span></button>`).join('') || '<div class="empty-state"><strong>Everything looks good.</strong><span>No urgent warning right now.</span></div>'}
        </div>
      </div>
      <div class="panel">
        <div class="panel-header"><div><h2>Top Courses</h2><p class="muted">Students and outstanding due by course.</p></div></div>
        <div class="course-health-list">
          ${topCourses.map((course) => `<div class="course-health-item"><div><strong>${escapeHtml(course.name)}</strong><span>${course.students} students</span></div><span class="${course.due > 0 ? 'danger' : 'success'}">${formatMoney(course.due)}</span></div>`).join('') || '<div class="empty-state"><strong>No course data yet.</strong><span>Create courses and enroll students.</span></div>'}
        </div>
      </div>
    </section>
    <section class="panel">
      <div class="panel-header"><div><h2>Notification Center</h2><p class="muted">Data quality and daily operation checks.</p></div></div>
      <div class="notification-grid">
        ${qualityAlerts.map((item) => `<button class="notification-tile ${item.tone || ''}" data-view="${item.view}"><strong>${escapeHtml(item.title)}</strong><span>${escapeHtml(item.body)}</span></button>`).join('') || '<div class="empty-state"><strong>No data quality warnings.</strong><span>Student, payment and exam data look tidy.</span></div>'}
      </div>
    </section>
    <section class="panel">
      <div class="panel-header"><h2>Recent Results</h2></div>
      ${resultsTable(attempts.slice(-6).reverse(), true)}
    </section>
  `;
}

function dashboardQuickSearchItems(query) {
  if (!query) return [];
  const students = (state.data.students || []).map((student) => ({
    type: 'Student',
    title: student.name,
    meta: `${student.rollNumber || '-'} · ${student.studentMobile || '-'} · Due ${formatMoney(student.finance?.totalDue || 0)}`,
    action: 'view-student',
    id: student.id,
    haystack: [student.name, student.rollNumber, student.studentMobile, student.guardianMobile, student.email, student.college, courseNames(student.courseIds)].join(' '),
  }));
  const payments = (state.data.payments || []).map((payment) => ({
    type: 'Payment',
    title: payment.receiptNumber || 'Payment',
    meta: `${payment.studentName || '-'} · ${formatMoney(payment.amount)} · ${formatDate(payment.paidAt || payment.createdAt)}`,
    view: 'payments',
    haystack: [payment.receiptNumber, payment.studentName, payment.studentRoll, payment.courseName, payment.reference].join(' '),
  }));
  const quizzes = (state.data.quizzes || []).map((quiz) => ({
    type: 'Quiz',
    title: quiz.title,
    meta: `${quiz.status || 'draft'} · ${quiz.questions?.length || 0} questions`,
    view: 'quizzes',
    haystack: [quiz.title, quiz.category, quiz.status].join(' '),
  }));
  const courses = (state.data.courses || []).map((course) => ({
    type: 'Course',
    title: course.name,
    meta: `${formatMoney(course.defaultFee || 0)} · ${course.status || 'active'}`,
    view: 'courses',
    haystack: [course.name, course.description, course.status].join(' '),
  }));
  return [...students, ...payments, ...quizzes, ...courses].filter((item) => item.haystack.toLowerCase().includes(query));
}

function quickSearchResultCard(item) {
  const attrs = item.action ? `data-action="${item.action}" data-id="${item.id}"` : `data-view="${item.view}"`;
  return `<button class="quick-search-card" ${attrs}><span>${escapeHtml(item.type)}</span><strong>${escapeHtml(item.title || '-')}</strong><small>${escapeHtml(item.meta || '')}</small></button>`;
}

function dashboardQualityAlerts({ students, totalDue, liveExams, resultSmsPending }) {
  const duplicateRolls = duplicateCount(students.map((student) => student.rollNumber).filter(Boolean));
  const duplicateMobiles = duplicateCount(students.map((student) => student.studentMobile).filter(Boolean));
  const missingCourse = students.filter((student) => !(student.courseIds || []).length).length;
  const missingBatch = students.filter((student) => !(student.batchEnrollments || []).length).length;
  return [
    duplicateRolls ? { title: 'Duplicate Roll', body: `${duplicateRolls} duplicate roll number found`, view: 'students', tone: 'danger' } : null,
    duplicateMobiles ? { title: 'Duplicate Mobile', body: `${duplicateMobiles} duplicate mobile number found`, view: 'students', tone: 'danger' } : null,
    missingCourse ? { title: 'Missing Course', body: `${missingCourse} students have no course`, view: 'students', tone: 'warning' } : null,
    missingBatch ? { title: 'Missing Batch', body: `${missingBatch} students have no batch`, view: 'students', tone: 'warning' } : null,
    totalDue > 0 ? { title: 'Payment Due', body: `${formatMoney(totalDue)} total student due`, view: 'payments', tone: 'warning' } : null,
    !liveExams ? { title: 'No Live Exam', body: 'No exam is currently live', view: 'quizzes', tone: '' } : null,
    resultSmsPending ? { title: 'Result SMS Pending', body: `${resultSmsPending} SMS logs not sent`, view: 'results', tone: 'warning' } : null,
  ].filter(Boolean);
}

function duplicateCount(values) {
  const seen = new Set();
  const duplicates = new Set();
  values.forEach((value) => {
    const key = String(value || '').trim().toLowerCase();
    if (!key) return;
    if (seen.has(key)) duplicates.add(key);
    seen.add(key);
  });
  return duplicates.size;
}

function managersView() {
  const managers = state.data.managers || [];
  const roles = state.data.roles || [];
  const section = state.managerSection || 'managers';
  return html`
    <section class="panel">
      <div class="panel-header">
        <div>
          <h1>Managers</h1>
          <p class="muted">Create custom menu access roles and assign them to manager profiles.</p>
        </div>
      </div>
      <div class="section-tabs">
        <button class="section-tab ${section === 'managers' ? 'active' : ''}" data-action="set-manager-section" data-section="managers">Managers</button>
        <button class="section-tab ${section === 'roles' ? 'active' : ''}" data-action="set-manager-section" data-section="roles">Roles</button>
      </div>
    </section>
    ${section === 'roles' ? rolesView(roles) : html`
    <section class="panel">
      <div class="panel-header"><div><h2>Add Manager</h2><p class="muted">Assign a custom role after creating it from Roles.</p></div></div>
      <form class="form-grid" data-action="add-manager">
        <div class="grid-3">
          <label class="field"><span>Name *</span><input name="name" placeholder="Manager name" required></label>
          <label class="field"><span>Mobile Number *</span><input name="mobile" placeholder="01XXXXXXXXX" required></label>
          <label class="field"><span>Password *</span><input name="password" placeholder="Temporary password" required></label>
        </div>
        <div class="grid-2">
          <label class="field"><span>Email</span><input name="email" type="email" placeholder="manager@example.com"></label>
          <label class="field"><span>Role *</span><select name="roleId" required>${roles.filter((role) => role.status === 'active').map((role) => `<option value="${role.id}">${escapeHtml(role.name)}</option>`).join('')}</select></label>
        </div>
        <button class="btn" type="submit">Add Manager</button>
      </form>
    </section>
    <section class="panel">
      <div class="table-wrap">
        <table>
          <thead><tr><th>Name</th><th>Mobile</th><th>Email</th><th>Role</th><th>Status</th><th>Actions</th></tr></thead>
          <tbody>
            ${managers.map((manager) => html`
              <tr>
                <td>${escapeHtml(manager.name)}</td>
                <td>${escapeHtml(manager.mobile || '-')}</td>
                <td>${escapeHtml(manager.email || '-')}</td>
                <td>${escapeHtml(manager.roleName || '-')}</td>
                <td><span class="badge ${manager.status === 'active' ? 'success' : 'danger'}">${manager.status}</span></td>
                <td>
                  <div class="actions">
                    <button class="btn secondary small" data-action="edit-manager" data-id="${manager.id}">Edit</button>
                    <button class="btn secondary small" data-action="toggle-manager" data-id="${manager.id}" data-status="${manager.status === 'active' ? 'inactive' : 'active'}">
                      ${manager.status === 'active' ? 'Deactivate' : 'Activate'}
                    </button>
                    <button class="btn secondary small" data-action="reset-manager-password" data-id="${manager.id}">Reset Password</button>
                  </div>
                </td>
              </tr>
            `).join('') || '<tr><td colspan="6">No managers yet.</td></tr>'}
          </tbody>
        </table>
      </div>
    </section>
    ${state.editingManagerId ? managerEditDialog() : ''}
    `}
  `;
}

function sessionsView() {
  const sessions = state.data.sessions || [];
  const active = state.data.activeSession || {};
  return html`
    <section class="panel">
      <div class="panel-header"><div><h1>Sessions</h1><p class="muted">Create academic sessions, switch active data, and backup or restore data.</p></div></div>
      <div class="stats-grid">
        <div class="stat"><span class="muted">Active Session</span><strong>${escapeHtml(active.name || '-')}</strong></div>
        <div class="stat"><span class="muted">Sessions</span><strong>${sessions.length}</strong></div>
        <div class="stat"><span class="muted">Version</span><strong>v${escapeHtml(state.data.version || '1.3.2')}</strong></div>
      </div>
    </section>
    <section class="panel">
      <div class="panel-header"><h2>Create Session</h2></div>
      <form class="form-grid" data-action="add-session">
        <div class="grid-2">
          <label class="field"><span>Session Name *</span><input name="name" placeholder="2026-2027" required></label>
          <button class="btn" type="submit">Create & Switch</button>
        </div>
      </form>
    </section>
    <section class="panel">
      <div class="panel-header"><h2>Session List</h2></div>
      <div class="table-wrap"><table><thead><tr><th>Session</th><th>Status</th><th>Created</th><th>Actions</th></tr></thead><tbody>
        ${sessions.map((session) => `<tr><td><strong>${escapeHtml(session.name)}</strong>${session.id === active.id ? '<br><span class="badge success">active now</span>' : ''}</td><td>${escapeHtml(session.status || 'active')}</td><td>${formatDate(session.createdAt)}</td><td><div class="actions"><button class="btn secondary small" data-action="switch-session" data-id="${session.id}">Switch</button><a class="btn secondary small" href="/api/backup/session.json?sessionId=${session.id}" target="_blank">Download Session</a></div></td></tr>`).join('') || '<tr><td colspan="4">No sessions yet.</td></tr>'}
      </tbody></table></div>
    </section>
    <section class="panel">
      <div class="panel-header"><div><h2>Backup & Restore</h2><p class="muted">Download current session or full software backup. Restore only trusted backup JSON.</p></div></div>
      <div class="backup-safety">
        <strong>Restore safety checklist</strong>
        <span>Use only JSON generated from this software. Keep a full backup before restoring. Review the confirmation summary before final restore.</span>
      </div>
      <div class="actions">
        <a class="btn secondary small" href="/api/backup/session.json" target="_blank">Download Current Session</a>
        <a class="btn secondary small" href="/api/backup/full.json" target="_blank">Download Full Backup</a>
      </div>
      <form class="form-grid" data-action="restore-backup">
        <label class="field"><span>Restore Backup JSON</span><textarea name="backupJson" rows="6" placeholder="Paste backup JSON here"></textarea></label>
        <button class="btn danger" type="submit">Restore Backup</button>
      </form>
    </section>
    <section class="panel">
      <div class="panel-header"><div><h2>Export Center</h2><p class="muted">Quick downloads for session data, finance, students, payments and results.</p></div></div>
      <div class="export-center-grid">
        ${exportCenterCard('Session Backup', 'Current session data JSON', [['JSON', '/api/backup/session.json']])}
        ${exportCenterCard('Full Backup', 'Complete software backup JSON', [['JSON', '/api/backup/full.json']])}
        ${exportCenterCard('Session Finance', 'Income, expense, due and summary', [['Excel', '/api/export/session-finance.xlsx'], ['PDF', '/api/export/session-finance.pdf'], ['CSV', '/api/export/session-finance.csv']])}
        ${exportCenterCard('Students', 'Student list with filters from report screen', [['CSV', '/api/export/students.csv'], ['PDF', '/api/export/students.pdf']])}
        ${exportCenterCard('Payments', 'Student payment history', [['CSV', '/api/export/payments.csv'], ['PDF', '/api/export/payments.pdf']])}
        ${exportCenterCard('Results', 'Quiz result exports', [['Excel', '/api/export/results.xlsx'], ['CSV', '/api/export/results.csv']])}
      </div>
    </section>
  `;
}

function exportCenterCard(title, description, links) {
  return `<div class="export-center-card"><div><strong>${escapeHtml(title)}</strong><span>${escapeHtml(description)}</span></div><div class="actions">${links.map(([label, href]) => `<a class="btn secondary small" href="${href}" target="_blank">${escapeHtml(label)}</a>`).join('')}</div></div>`;
}

function rolesView(roles) {
  return html`
    <section class="panel">
      <div class="panel-header"><div><h2>Create Role</h2><p class="muted">Select menu names that this role can access.</p></div></div>
      <form class="form-grid" data-action="add-role">
        <div class="grid-2">
          <label class="field"><span>Role Name *</span><input name="name" placeholder="Account Manager" required></label>
          <label class="field"><span>Description</span><input name="description" placeholder="Short role note"></label>
        </div>
        ${rolePermissionChecks([])}
        <button class="btn" type="submit">Create Role</button>
      </form>
    </section>
    <section class="panel">
      <div class="table-wrap"><table>
        <thead><tr><th>Role</th><th>Menus</th><th>Status</th><th>Actions</th></tr></thead>
        <tbody>${roles.map((role) => `<tr><td><strong>${escapeHtml(role.name)}</strong><br><span class="muted">${escapeHtml(role.description || '')}</span></td><td>${escapeHtml((role.menuAccess || []).join(', '))}</td><td><span class="badge ${role.status === 'active' ? 'success' : 'danger'}">${role.status}</span></td><td><div class="actions"><button class="btn secondary small" data-action="edit-role" data-id="${role.id}">Edit</button><button class="btn secondary small" data-action="toggle-role" data-id="${role.id}" data-status="${role.status === 'active' ? 'inactive' : 'active'}">${role.status === 'active' ? 'Deactivate' : 'Activate'}</button><button class="btn danger small" data-action="delete-role" data-id="${role.id}">Delete</button></div></td></tr>`).join('') || '<tr><td colspan="4">No roles yet.</td></tr>'}</tbody>
      </table></div>
    </section>
    ${state.editingRoleId ? roleEditDialog() : ''}
  `;
}

function rolePermissionChecks(selected = []) {
  const labels = { overview: 'Overview', managers: 'Managers', sessions: 'Sessions', institute: 'Institute', courses: 'Courses', students: 'Students', messages: 'Messages', teachers: 'Teachers', employees: 'Employees', payments: 'Payments Overview', studentPayments: 'Student Payments', teacherPayments: 'Teacher Payments', employeePayments: 'Employee Payments', referencePayments: 'Reference Payments', otherPayments: 'Other Payments', resultSms: 'Result SMS', recordedClasses: 'Recorded Classes', quizzes: 'Quizzes', results: 'Results', analytics: 'Analytics', activity: 'Activity', profile: 'Profile' };
  const sensitive = new Set(['managers', 'sessions', 'institute', 'payments', 'studentPayments', 'teacherPayments', 'employeePayments', 'referencePayments', 'otherPayments', 'resultSms', 'activity']);
  return `<div class="permission-note"><strong>Action note:</strong> Sensitive menus can export, restore, payment, SMS, or audit data. Give access only to trusted staff.</div><div class="permission-grid">${(state.data.menuPermissions || []).map((key) => `<label class="check-card ${sensitive.has(key) ? 'sensitive' : ''}"><input type="checkbox" name="menuAccess" value="${key}" ${selected.includes(key) ? 'checked' : ''}><span><strong>${escapeHtml(labels[key] || key)}</strong><small>${escapeHtml(key)}${sensitive.has(key) ? ' · sensitive' : ''}</small></span></label>`).join('')}</div>`;
}

function roleEditDialog() {
  const role = (state.data.roles || []).find((item) => item.id === state.editingRoleId);
  if (!role) return '';
  return `<div class="modal-backdrop"><section class="modal-card modal-wide"><div class="panel-header"><div><h2>Edit Role</h2><p class="muted">${escapeHtml(role.name)}</p></div><button class="btn secondary small" data-action="close-role-edit">Close</button></div><form class="form-grid" data-action="edit-role" data-id="${role.id}"><div class="grid-2"><label class="field"><span>Role Name *</span><input name="name" value="${escapeHtml(role.name)}" required></label><label class="field"><span>Description</span><input name="description" value="${escapeHtml(role.description || '')}"></label></div>${rolePermissionChecks(role.menuAccess || [])}<button class="btn" type="submit">Save Role</button></form></section></div>`;
}

function managerEditDialog() {
  const manager = (state.data.managers || []).find((item) => item.id === state.editingManagerId);
  const roles = (state.data.roles || []).filter((role) => role.status === 'active');
  if (!manager) return '';
  return `<div class="modal-backdrop"><section class="modal-card"><div class="panel-header"><div><h2>Edit Manager</h2><p class="muted">${escapeHtml(manager.mobile || '')}</p></div><button class="btn secondary small" data-action="close-manager-edit">Close</button></div><form class="form-grid" data-action="edit-manager" data-id="${manager.id}"><label class="field"><span>Name *</span><input name="name" value="${escapeHtml(manager.name)}" required></label><label class="field"><span>Mobile *</span><input name="mobile" value="${escapeHtml(manager.mobile || '')}" required></label><label class="field"><span>Email</span><input name="email" type="email" value="${escapeHtml(manager.email || '')}"></label><label class="field"><span>Role *</span><select name="roleId">${roles.map((role) => `<option value="${role.id}" ${role.id === manager.roleId ? 'selected' : ''}>${escapeHtml(role.name)}</option>`).join('')}</select></label><button class="btn" type="submit">Save Manager</button></form></section></div>`;
}

function isQuizLive(quiz) {
  const currentTime = Date.now();
  const start = quiz.scheduleStart ? new Date(quiz.scheduleStart).getTime() : 0;
  const end = quiz.scheduleEnd ? new Date(quiz.scheduleEnd).getTime() : 0;
  if (start && currentTime < start) return false;
  if (end && currentTime > end) return false;
  return quiz.status === 'published';
}

function analyticsView() {
  const courseId = state.analyticsCourseId || '';
  const month = state.analyticsMonth || '';
  const allQuizzes = state.data.quizzes || [];
  const quizzes = courseId ? allQuizzes.filter((quiz) => (quiz.assignedCourseIds || []).includes(courseId)) : allQuizzes;
  const quizIds = new Set(quizzes.map((quiz) => quiz.id));
  const attempts = (state.data.attempts || []).filter((attempt) => (
    (!courseId || quizIds.has(attempt.quizId))
    && (!month || String(attempt.submittedAt || '').startsWith(month))
  ));
  const students = (state.data.students || []).filter((student) => !courseId || (student.courseIds || []).includes(courseId));
  const payments = (state.data.payments || []).filter((payment) => (
    (!courseId || payment.courseId === courseId)
    && (!month || String(payment.paidAt || '').startsWith(month))
  ));
  const completedPayments = payments.filter((payment) => payment.status !== 'cancelled');
  const teacherPayments = (state.data.teacherPayments || []).filter((payment) => (
    (!courseId || payment.courseId === courseId)
    && (!month || payment.month === month)
  ));
  const employeePayments = (state.data.employeePayments || []).filter((payment) => !month || payment.month === month);
  const totalCollection = completedPayments.reduce((sum, payment) => sum + Number(payment.amount || 0), 0);
  const totalDue = students.reduce((sum, student) => sum + Number(student.finance?.totalDue || 0), 0);
  const teacherPayable = teacherPayments.reduce((sum, payment) => sum + Number(payment.payable ?? payment.payableAmount ?? 0), 0);
  const teacherPaid = teacherPayments.reduce((sum, payment) => sum + Number(payment.paid ?? payment.paidAmount ?? 0), 0);
  const teacherDue = teacherPayments.reduce((sum, payment) => sum + Number(payment.due ?? payment.dueAmount ?? 0), 0);
  const employeePaid = employeePayments.reduce((sum, payment) => sum + Number(payment.paid ?? payment.paidAmount ?? 0), 0);
  const employeeDue = employeePayments.reduce((sum, payment) => sum + Number(payment.due || 0), 0);
  const otherExpense = (state.data.otherPayments || [])
    .filter((payment) => !month || String(payment.paidAt || '').startsWith(month))
    .reduce((sum, payment) => sum + Number(payment.amount || 0), 0);
  const netBalance = totalCollection - teacherPaid - employeePaid - otherExpense;
  const activeCount = students.filter((student) => student.status === 'active').length;
  const inactiveCount = students.length - activeCount;
  const paidStudentCount = students.filter((student) => Number(student.finance?.totalDue || 0) <= 0 && Number(student.finance?.totalPayable || student.finance?.totalFee || 0) > 0).length;
  const dueStudentCount = students.filter((student) => Number(student.finance?.totalDue || 0) > 0).length;
  const passed = attempts.filter((attempt) => attempt.passed).length;
  const pending = attempts.filter((attempt) => attempt.reviewStatus === 'pending').length;
  const warnings = attempts.reduce((sum, attempt) => sum + Number(attempt.warnings || 0), 0);
  const byQuiz = quizzes.map((quiz) => {
    const quizAttempts = attempts.filter((attempt) => attempt.quizId === quiz.id);
    const average = quizAttempts.length ? Math.round(quizAttempts.reduce((sum, attempt) => sum + attempt.percentage, 0) / quizAttempts.length) : 0;
    return { title: quiz.title, attempts: quizAttempts.length, average };
  }).sort((a, b) => b.attempts - a.attempts || b.average - a.average);
  const byStudent = students.map((student) => {
    const studentAttempts = attempts.filter((attempt) => attempt.studentId === student.id);
    const average = studentAttempts.length ? Math.round(studentAttempts.reduce((sum, attempt) => sum + attempt.percentage, 0) / studentAttempts.length) : 0;
    return { name: student.name, attempts: studentAttempts.length, average };
  }).sort((a, b) => b.average - a.average);
  const byMethod = ['cash', 'bank', 'mobile_banking'].map((method) => ({
    method,
    amount: completedPayments.filter((payment) => payment.method === method).reduce((sum, payment) => sum + Number(payment.amount || 0), 0),
  }));
  const byCourseFinance = (state.data.courses || []).filter((course) => !courseId || course.id === courseId).map((course) => {
    const coursePayments = completedPayments.filter((payment) => payment.courseId === course.id);
    const courseDue = students.reduce((sum, student) => {
      const enrollment = student.finance?.enrollments?.find((item) => item.courseId === course.id);
      return sum + Number(enrollment?.due || 0);
    }, 0);
    return {
      course: course.name,
      collection: coursePayments.reduce((sum, payment) => sum + Number(payment.amount || 0), 0),
      due: courseDue,
    };
  });
  const byBatch = (state.data.batches || []).filter((batch) => !courseId || batch.courseId === courseId).map((batch) => {
    const batchStudents = students.filter((student) => (student.batchEnrollments || []).some((item) => item.batchId === batch.id));
    const batchDue = batchStudents.reduce((sum, student) => sum + Number(student.finance?.totalDue || 0), 0);
    return { name: batch.name, course: courseName(batch.courseId), students: batchStudents.length, due: batchDue };
  }).sort((a, b) => b.students - a.students).slice(0, 10);
  const bySubject = quizzes.map((quiz) => {
    const quizAttempts = attempts.filter((attempt) => attempt.quizId === quiz.id);
    const average = quizAttempts.length ? Math.round(quizAttempts.reduce((sum, attempt) => sum + attempt.percentage, 0) / quizAttempts.length) : 0;
    return { name: primaryQuizCategory(quiz) || quiz.title, attempts: quizAttempts.length, average };
  }).filter((item) => item.attempts > 0).sort((a, b) => a.average - b.average).slice(0, 8);

  return html`
    <section class="panel">
      <div class="panel-header">
        <div>
          <h1>Analytics</h1>
          <p class="muted">Students, payment collection, dues, results and exam performance.</p>
        </div>
      </div>
      <div class="analytics-filters">
        <label class="field"><span>Course</span><select data-analytics-course><option value="">All courses</option>${(state.data.courses || []).map((course) => `<option value="${course.id}" ${courseId === course.id ? 'selected' : ''}>${escapeHtml(course.name)}</option>`).join('')}</select></label>
        <label class="field"><span>Month</span><input type="month" data-analytics-month value="${escapeHtml(month)}"></label>
      </div>
      <div class="stats-grid">
        <div class="stat"><span class="muted">Students</span><strong>${students.length}</strong></div>
        <div class="stat"><span class="muted">Collection</span><strong>${formatMoney(totalCollection)}</strong></div>
        <div class="stat"><span class="muted">Due</span><strong>${formatMoney(totalDue)}</strong></div>
        <div class="stat"><span class="muted">Net Balance</span><strong>${formatMoney(netBalance)}</strong></div>
        <div class="stat"><span class="muted">Teacher Paid</span><strong>${formatMoney(teacherPaid)}</strong></div>
        <div class="stat"><span class="muted">Teacher Due</span><strong>${formatMoney(teacherDue)}</strong></div>
        <div class="stat"><span class="muted">Employee Paid</span><strong>${formatMoney(employeePaid)}</strong></div>
        <div class="stat"><span class="muted">Employee Due</span><strong>${formatMoney(employeeDue)}</strong></div>
        <div class="stat"><span class="muted">Pass Rate</span><strong>${attempts.length ? Math.round((passed / attempts.length) * 100) : 0}%</strong></div>
        <div class="stat"><span class="muted">Pending Review</span><strong>${pending}</strong></div>
        <div class="stat"><span class="muted">Integrity Warnings</span><strong>${warnings}</strong></div>
      </div>
    </section>
    <section class="dashboard-split">
      <div class="panel">
        <div class="panel-header"><div><h2>Student Analytics</h2><p class="muted">Status and fee condition for current filter.</p></div></div>
        <div class="analytics-pill-grid">
          <div class="analytics-pill"><span>Active</span><strong>${activeCount}</strong></div>
          <div class="analytics-pill"><span>Inactive</span><strong>${inactiveCount}</strong></div>
          <div class="analytics-pill success"><span>Paid</span><strong>${paidStudentCount}</strong></div>
          <div class="analytics-pill danger"><span>Due</span><strong>${dueStudentCount}</strong></div>
        </div>
      </div>
      <div class="panel">
        <div class="panel-header"><div><h2>Finance Snapshot</h2><p class="muted">Income minus staff and other expenses.</p></div></div>
        <div class="finance-summary compact-finance-summary">
          ${financeCard('Collection', totalCollection)}
          ${financeCard('Staff Paid', teacherPaid + employeePaid)}
          ${financeCard('Other Expense', otherExpense, 'danger')}
          ${financeCard('Net Balance', netBalance, netBalance < 0 ? 'danger' : 'success')}
        </div>
      </div>
    </section>
    <section class="panel">
      <div class="panel-header"><h2>Quiz Performance</h2></div>
      ${barList(byQuiz, 'title')}
    </section>
    <section class="panel">
      <div class="panel-header"><div><h2>Weak Topics / Subjects</h2><p class="muted">Lowest average areas from quiz attempts.</p></div></div>
      ${barList(bySubject, 'name', true)}
    </section>
    <section class="panel">
      <div class="panel-header"><h2>Student Performance</h2></div>
      ${barList(byStudent, 'name')}
    </section>
    <section class="panel">
      <div class="panel-header"><div><h2>Batch Breakdown</h2><p class="muted">Student count and total due by batch.</p></div></div>
      <div class="table-wrap"><table class="smart-table"><thead><tr><th>Batch</th><th>Course</th><th>Students</th><th>Due</th></tr></thead><tbody>${byBatch.map((batch) => `<tr><td>${escapeHtml(batch.name)}</td><td>${escapeHtml(batch.course)}</td><td>${batch.students}</td><td><strong>${formatMoney(batch.due)}</strong></td></tr>`).join('') || '<tr><td colspan="4">No batch data for this filter.</td></tr>'}</tbody></table></div>
    </section>
    <section class="panel">
      <div class="panel-header"><h2>Due Student List</h2></div>
      <div class="table-wrap">
        <table>
          <thead><tr><th>Student</th><th>Roll</th><th>Courses</th><th>Paid</th><th>Due</th></tr></thead>
          <tbody>${students.filter((student) => Number(student.finance?.totalDue || 0) > 0).sort((a, b) => b.finance.totalDue - a.finance.totalDue).map((student) => `<tr><td>${escapeHtml(student.name)}</td><td>${escapeHtml(student.rollNumber)}</td><td>${escapeHtml(courseNames(student.courseIds))}</td><td>${formatMoney(student.finance.totalPaid)}</td><td><strong>${formatMoney(student.finance.totalDue)}</strong></td></tr>`).join('') || '<tr><td colspan="5">No outstanding dues.</td></tr>'}</tbody>
        </table>
      </div>
    </section>
    <section class="panel">
      <div class="panel-header"><h2>Recent Payments</h2></div>
      <div class="table-wrap">
        <table>
          <thead><tr><th>Receipt</th><th>Student</th><th>Course</th><th>Amount</th><th>Date</th></tr></thead>
          <tbody>${completedPayments.slice(0, 10).map((payment) => `<tr><td>${escapeHtml(payment.receiptNumber)}</td><td>${escapeHtml(payment.studentName)}</td><td>${escapeHtml(payment.courseName)}</td><td>${formatMoney(payment.amount)}</td><td>${formatDate(payment.paidAt)}</td></tr>`).join('') || '<tr><td colspan="5">No payments yet.</td></tr>'}</tbody>
        </table>
      </div>
    </section>
    <section class="panel">
      <div class="panel-header"><h2>Payment Method Summary</h2></div>
      <div class="finance-summary">${byMethod.map((item) => financeCard(item.method.replaceAll('_', ' '), item.amount)).join('')}</div>
    </section>
    <section class="panel">
      <div class="panel-header"><h2>Teacher Payment Summary</h2></div>
      <div class="finance-summary">
        ${financeCard('Teacher Payable', teacherPayable)}
        ${financeCard('Teacher Paid', teacherPaid)}
        ${financeCard('Teacher Due', teacherDue, 'danger')}
      </div>
      <div class="table-wrap"><table><thead><tr><th>Teacher</th><th>Course / Batch</th><th>Month</th><th>Subject</th><th>Paid</th><th>Due</th></tr></thead><tbody>${teacherPayments.slice(0, 10).map((payment) => `<tr><td>${escapeHtml(payment.teacherName || managerName(payment.teacherId))}</td><td>${escapeHtml(payment.courseName || courseName(payment.courseId))}<br><span class="muted">${escapeHtml(payment.batchName || batchName(payment.batchId))}</span></td><td>${escapeHtml(payment.month)}</td><td>${escapeHtml(payment.subject)}</td><td>${formatMoney(payment.paid ?? payment.paidAmount)}</td><td><strong>${formatMoney(payment.due ?? payment.dueAmount)}</strong></td></tr>`).join('') || '<tr><td colspan="6">No teacher payment data.</td></tr>'}</tbody></table></div>
    </section>
    <section class="panel">
      <div class="panel-header"><h2>Employee Payment Summary</h2></div>
      <div class="finance-summary">
        ${financeCard('Employee Paid', employeePaid)}
        ${financeCard('Employee Due', employeeDue, 'danger')}
      </div>
      <div class="table-wrap"><table><thead><tr><th>Employee</th><th>Month</th><th>Designation</th><th>Paid</th><th>Due</th></tr></thead><tbody>${employeePayments.slice(0, 10).map((payment) => `<tr><td>${escapeHtml(payment.employeeName || '-')}</td><td>${escapeHtml(payment.month || '-')}</td><td>${escapeHtml(payment.designation || '-')}</td><td>${formatMoney(payment.paid ?? payment.paidAmount)}</td><td><strong>${formatMoney(payment.due)}</strong></td></tr>`).join('') || '<tr><td colspan="5">No employee payment data.</td></tr>'}</tbody></table></div>
    </section>
    <section class="panel">
      <div class="panel-header"><h2>Course Collection & Due</h2></div>
      <div class="table-wrap"><table><thead><tr><th>Course</th><th>Collection</th><th>Due</th></tr></thead><tbody>${byCourseFinance.map((item) => `<tr><td>${escapeHtml(item.course)}</td><td>${formatMoney(item.collection)}</td><td>${formatMoney(item.due)}</td></tr>`).join('') || '<tr><td colspan="3">No course finance data.</td></tr>'}</tbody></table></div>
    </section>
  `;
}

function barList(items, labelKey, weakMode = false) {
  if (!items.length) return '<p class="muted">No analytics data yet.</p>';
  return html`
    <div class="bar-list">
      ${items.map((item) => html`
        <div class="bar-row ${weakMode && item.average < 50 ? 'danger' : ''}">
          <div>
            <strong>${escapeHtml(item[labelKey])}</strong>
            <span class="muted">${item.attempts} attempts · ${item.average}% average</span>
          </div>
          <div class="bar"><span style="width:${Math.max(3, item.average)}%"></span></div>
        </div>
      `).join('')}
    </div>
  `;
}

