// Split from public/app.js v1.7.7. Loaded by public/index.html.
async function saveQuizForm(form, closeAfterSave = false) {
  const formData = new FormData(form);
  const id = formData.get('id');
  const payload = collectQuizForm(form);
  if (!payload.assignedCourseIds.length) {
    state.editingQuiz = { id: id || state.editingQuiz?.id || '', ...payload };
    state.quizEditorTab = 'settings';
    throw new Error('Select at least one course before saving the quiz.');
  }
  const { quiz } = await api(id ? `/api/quizzes/${id}` : '/api/quizzes', {
    method: id ? 'PUT' : 'POST',
    body: JSON.stringify(payload),
  });
  await refreshDashboard();
  state.editingQuiz = closeAfterSave ? null : JSON.parse(JSON.stringify(quiz));
  state.savedQuizSnapshot = closeAfterSave ? '' : snapshotQuiz(quiz);
  state.pendingQuizClose = false;
  if (!closeAfterSave) state.quizEditorTab = state.quizEditorTab || 'general';
  setMessage('Quiz saved.');
}

async function handleSubmit(event) {
  const form = event.target.closest('form');
  if (!form) return;
  const action = form.dataset.action;
  if (!action) return;
  event.preventDefault();
  state.error = '';
  state.message = '';
  const submitter = event.submitter?.matches?.('button') ? event.submitter : form.querySelector('button[type="submit"], .btn');
  setBusy(submitter, true);

  try {
    if (action === 'login') {
      const formData = new FormData(form);
      const result = await api('/api/login', {
        method: 'POST',
        body: JSON.stringify({
          email: formData.get('email'),
          password: formData.get('password'),
        }),
      });
      if (result.requiresOtp) {
        state.loginOtpToken = result.otpToken || '';
        state.loginOtpMobile = result.maskedMobile || '';
        state.loginDevOtp = result.devOtp || '';
        state.loginOtpCredentials = { email: formData.get('email'), password: formData.get('password') };
        startLoginOtpTimer(60);
        setMessage(result.message || 'Enter OTP to continue.');
        return;
      }
      state.user = result.user;
      state.institute = result.institute || state.institute;
      state.csrfToken = result.csrfToken || '';
      state.view = 'overview';
      await refreshDashboard();
      setMessage('Logged in successfully.');
      return;
    }

    if (action === 'verify-login-otp') {
      const formData = new FormData(form);
      const { user, institute, csrfToken } = await api('/api/login/verify-otp', {
        method: 'POST',
        body: JSON.stringify({ otpToken: state.loginOtpToken, otp: formData.get('otp') }),
      });
      state.user = user;
      state.institute = institute || state.institute;
      state.csrfToken = csrfToken || '';
      state.loginOtpToken = '';
      state.loginOtpMobile = '';
      state.loginDevOtp = '';
      state.loginOtpCredentials = null;
      if (state.loginOtpTimer) clearInterval(state.loginOtpTimer);
      state.loginOtpSeconds = 0;
      state.view = 'overview';
      await refreshDashboard();
      setMessage('Logged in successfully.');
      return;
    }

    if (action === 'request-reset') {
      const formData = new FormData(form);
      const result = await api('/api/password-reset/request', {
        method: 'POST',
        body: JSON.stringify({ email: formData.get('email') }),
      });
      if (result.resetToken) {
        state.resetOtpToken = result.resetToken;
        state.resetOtpHint = `${result.emailSent ? 'Email sent. ' : ''}${result.maskedMobile ? `OTP sent to ${result.maskedMobile}.` : 'Enter the OTP sent to your account.'}`;
        state.resetDevOtp = result.devOtp || '';
        setMessage('Enter OTP and new password.');
        return;
      }
      state.showResetModal = false;
      setMessage(result.message || 'If the account exists, reset instructions have been sent.');
      return;
    }

    if (action === 'confirm-reset-otp') {
      const formData = new FormData(form);
      await api('/api/password-reset/confirm', {
        method: 'POST',
        body: JSON.stringify({ token: formData.get('token'), otp: formData.get('otp'), password: formData.get('password') }),
      });
      state.showResetModal = false;
      state.resetOtpToken = '';
      state.resetOtpHint = '';
      state.resetDevOtp = '';
      setMessage('Password reset. You can login now.');
      return;
    }

    if (action === 'confirm-reset') {
      const formData = new FormData(form);
      await api('/api/password-reset/confirm', {
        method: 'POST',
        body: JSON.stringify({ token: formData.get('token'), otp: formData.get('otp'), password: formData.get('password') }),
      });
      history.replaceState({}, '', location.pathname);
      state.message = 'Password reset. You can login now.';
      state.error = '';
      render();
      return;
    }

    if (action === 'save-institute-profile') {
      const formData = new FormData(form);
      const { institute } = await api('/api/institute-profile', {
        method: 'PATCH',
        body: JSON.stringify({
          name: formData.get('name'),
          tagline: formData.get('tagline'),
          registrationNo: formData.get('registrationNo'),
          phone: formData.get('phone'),
          email: formData.get('email'),
          website: formData.get('website'),
          address: formData.get('address'),
          logoDataUrl: formData.get('logoDataUrl'),
          faviconDataUrl: formData.get('faviconDataUrl'),
          primaryColor: formData.get('primaryColor'),
          secondaryColor: formData.get('secondaryColor'),
          receiptNote: formData.get('receiptNote'),
          admissionTerms: formData.get('admissionTerms'),
          supportContact: formData.get('supportContact'),
          smsSettings: collectSmsSettings(formData),
        }),
      });
      state.institute = institute;
      await refreshDashboard();
      setMessage('Institute profile updated.');
      return;
    }

    if (action === 'save-sms-settings') {
      const formData = new FormData(form);
      const { institute } = await api('/api/institute-profile', {
        method: 'PATCH',
        body: JSON.stringify(institutePayloadFromCurrent({
          smsSettings: collectSmsSettings(formData),
        })),
      });
      state.institute = institute;
      await refreshDashboard();
      setMessage('SMS settings updated.');
      return;
    }

    if (action === 'test-sms-settings') {
      const smsForm = document.querySelector('[data-action="save-sms-settings"]');
      const settingsData = new FormData(smsForm || form);
      const testData = new FormData(form);
      const { institute } = await api('/api/institute-profile', {
        method: 'PATCH',
        body: JSON.stringify(institutePayloadFromCurrent({
          smsSettings: collectSmsSettings(settingsData),
        })),
      });
      state.institute = institute;
      const result = await api('/api/sms/test', {
        method: 'POST',
        body: JSON.stringify({
          mobile: testData.get('testMobile'),
          message: testData.get('testMessage'),
        }),
      });
      await refreshDashboard();
      setMessage(result.log?.status === 'sent' ? 'Test SMS sent successfully.' : `Test SMS ${result.log?.status || 'logged'}: ${result.log?.error || result.log?.providerResponse || 'Check SMS logs.'}`);
      return;
    }

    if (action === 'add-session') {
      const formData = new FormData(form);
      await api('/api/sessions', {
        method: 'POST',
        body: JSON.stringify({ name: formData.get('name') }),
      });
      await refreshDashboard();
      state.view = 'sessions';
      setMessage('Session created and activated.');
      return;
    }

    if (action === 'restore-backup') {
      const formData = new FormData(form);
      const backupJson = String(formData.get('backupJson') || '').trim();
      if (!backupJson) throw new Error('Paste backup JSON first.');
      const backup = parseBackupJson(backupJson);
      const summary = summarizeBackup(backup);
      if (!confirmSensitive({
        title: 'Restore backup',
        body: `${summary}\n\nThis can replace current session or software data. Continue only with a trusted backup file.`,
        phrase: 'RESTORE',
      })) return;
      await api('/api/backup/restore', {
        method: 'POST',
        body: JSON.stringify({ backup }),
      });
      await refreshDashboard();
      setMessage('Backup restored.');
      return;
    }

    if (action === 'add-manager') {
      const formData = new FormData(form);
      await api('/api/managers', {
        method: 'POST',
        body: JSON.stringify({
          name: formData.get('name'),
          mobile: formData.get('mobile'),
          email: formData.get('email'),
          password: formData.get('password'),
          roleId: formData.get('roleId'),
        }),
      });
      await refreshDashboard();
      setMessage('Manager added.');
      return;
    }

    if (action === 'edit-manager') {
      const formData = new FormData(form);
      await api(`/api/managers/${form.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({
          name: formData.get('name'),
          mobile: formData.get('mobile'),
          email: formData.get('email'),
          roleId: formData.get('roleId'),
        }),
      });
      state.editingManagerId = '';
      await refreshDashboard();
      setMessage('Manager updated.');
      return;
    }

    if (action === 'add-role' || action === 'edit-role') {
      const formData = new FormData(form);
      await api(action === 'add-role' ? '/api/roles' : `/api/roles/${form.dataset.id}`, {
        method: action === 'add-role' ? 'POST' : 'PATCH',
        body: JSON.stringify({
          name: formData.get('name'),
          description: formData.get('description'),
          menuAccess: formData.getAll('menuAccess'),
        }),
      });
      state.editingRoleId = '';
      await refreshDashboard();
      setMessage(action === 'add-role' ? 'Role created.' : 'Role updated.');
      return;
    }

    if (action === 'add-teacher' || action === 'edit-teacher') {
      const formData = new FormData(form);
      const payload = {
        name: formData.get('name'),
        mobile: formData.get('mobile'),
        email: formData.get('email'),
        subject: formData.get('subject'),
        rate: formData.get('rate'),
        note: formData.get('note'),
      };
      await api(action === 'add-teacher' ? '/api/teachers' : `/api/teachers/${form.dataset.id}`, {
        method: action === 'add-teacher' ? 'POST' : 'PATCH',
        body: JSON.stringify(payload),
      });
      state.editingTeacherId = '';
      await refreshDashboard();
      setMessage(action === 'add-teacher' ? 'Teacher added.' : 'Teacher updated.');
      return;
    }

    if (action === 'add-employee' || action === 'edit-employee') {
      const formData = new FormData(form);
      const payload = {
        name: formData.get('name'),
        mobile: formData.get('mobile'),
        email: formData.get('email'),
        designation: formData.get('designation'),
        salary: formData.get('salary'),
        note: formData.get('note'),
      };
      await api(action === 'add-employee' ? '/api/employees' : `/api/employees/${form.dataset.id}`, {
        method: action === 'add-employee' ? 'POST' : 'PATCH',
        body: JSON.stringify(payload),
      });
      state.editingEmployeeId = '';
      await refreshDashboard();
      setMessage(action === 'add-employee' ? 'Employee added.' : 'Employee updated.');
      return;
    }

    if (action === 'add-student') {
      const formData = new FormData(form);
      const courseData = collectStudentCourseData(form);
      state.studentFormDraft = { ...Object.fromEntries(formData.entries()), courseIds: courseData.courseIds };
      const result = await api('/api/students', {
        method: 'POST',
        body: JSON.stringify({
          name: formData.get('name'),
          rollNumber: formData.get('rollNumber'),
          studentMobile: formData.get('studentMobile'),
          guardianMobile: formData.get('guardianMobile'),
          college: formData.get('college'),
          sscResult: formData.get('sscResult'),
          sscPassingYear: formData.get('sscPassingYear'),
          hscResult: formData.get('hscResult'),
          hscPassingYear: formData.get('hscPassingYear'),
          photoDataUrl: formData.get('photoDataUrl'),
          ...courseData,
          admissionDate: formData.get('admissionDate'),
          email: formData.get('email'),
          password: formData.get('password'),
          referenceType: formData.get('referenceType'),
          referenceName: formData.get('referenceName'),
          referenceMobile: formData.get('referenceMobile'),
          referenceCommissionAmount: formData.get('referenceCommissionAmount'),
        }),
      });
      state.studentFormDraft = {};
      await refreshDashboard();
      setMessage(result.receipts?.length ? `Student added with ${result.receipts.length} payment receipt(s).` : 'Student added.');
      return;
    }

    if (action === 'add-course') {
      const formData = new FormData(form);
      await api('/api/courses', {
        method: 'POST',
        body: JSON.stringify({
          name: formData.get('name'),
          code: formData.get('code'),
          description: formData.get('description'),
          defaultFee: formData.get('defaultFee'),
        }),
      });
      await refreshDashboard();
      setMessage('Course added.');
      return;
    }

    if (action === 'add-subject') {
      const formData = new FormData(form);
      await api('/api/subjects', {
        method: 'POST',
        body: JSON.stringify({ name: formData.get('name'), code: formData.get('code') }),
      });
      await refreshDashboard();
      setMessage('Subject added.');
      return;
    }

    if (action === 'edit-subject') {
      const formData = new FormData(form);
      await api(`/api/subjects/${form.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ name: formData.get('name'), code: formData.get('code') }),
      });
      state.editingSubjectId = '';
      await refreshDashboard();
      setMessage('Subject updated.');
      return;
    }

    if (action === 'save-roll-settings') {
      const formData = new FormData(form);
      await api('/api/roll-settings', {
        method: 'PATCH',
        body: JSON.stringify({
          year: formData.get('year'),
          rollPrefix: formData.get('rollPrefix'),
          serialPadding: formData.get('serialPadding'),
          rollLimit: formData.get('rollLimit'),
        }),
      });
      await refreshDashboard();
      setMessage('Roll settings updated.');
      return;
    }

    if (action === 'edit-course') {
      const formData = new FormData(form);
      await api(`/api/courses/${form.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({
          name: formData.get('name'),
          code: formData.get('code'),
          description: formData.get('description'),
          defaultFee: formData.get('defaultFee'),
        }),
      });
      state.editingCourseId = '';
      await refreshDashboard();
      setMessage('Course updated.');
      return;
    }

    if (action === 'add-batch' || action === 'edit-batch') {
      const formData = new FormData(form);
      const payload = {
        name: formData.get('name'),
        code: formData.get('code'),
        courseId: formData.get('courseId'),
        startDate: formData.get('startDate'),
        endDate: formData.get('endDate'),
        schedule: formData.get('schedule'),
        capacity: formData.get('capacity'),
        rollStartNumber: formData.get('rollStartNumber'),
        rollNextNumber: formData.get('rollNextNumber'),
        rollLimit: formData.get('rollLimit'),
      };
      await api(action === 'add-batch' ? '/api/batches' : `/api/batches/${form.dataset.id}`, {
        method: action === 'add-batch' ? 'POST' : 'PATCH',
        body: JSON.stringify(payload),
      });
      state.editingBatchId = '';
      await refreshDashboard();
      setMessage(action === 'add-batch' ? 'Batch created.' : 'Batch updated.');
      return;
    }

    if (action === 'send-notification') {
      const formData = new FormData(form);
      const result = await api('/api/notifications', {
        method: 'POST',
        body: JSON.stringify({
          audienceType: formData.get('audienceType'),
          courseIds: formData.getAll('courseIds'),
          batchIds: formData.getAll('batchIds'),
          studentIds: formData.getAll('studentIds'),
          title: formData.get('title'),
          body: formData.get('body'),
          sendSms: formData.has('sendSms'),
        }),
      });
      await refreshDashboard();
      setMessage(`Message sent to ${result.count} students${result.smsSent ? `, SMS sent ${result.smsSent}` : ''}.`);
      return;
    }

    if (action === 'send-due-reminders') {
      const formData = new FormData(form);
      const result = await api('/api/due-reminders', {
        method: 'POST',
        body: JSON.stringify({
          courseIds: formData.getAll('courseIds'),
          batchIds: formData.getAll('batchIds'),
          minDue: formData.get('minDue'),
          title: formData.get('title'),
          template: formData.get('template'),
          sendSms: formData.has('sendSms'),
        }),
      });
      await refreshDashboard();
      setMessage(`Due reminder sent to ${result.count} students${result.smsSent ? `, SMS sent ${result.smsSent}` : ''}.`);
      return;
    }

    if (action === 'save-batch-students') {
      const formData = new FormData(form);
      await api(`/api/batches/${form.dataset.id}/students`, {
        method: 'PATCH',
        body: JSON.stringify({ studentIds: formData.getAll('studentIds') }),
      });
      state.managingBatchId = '';
      await refreshDashboard();
      setMessage('Batch students updated.');
      return;
    }

    if (action === 'edit-student') {
      const formData = new FormData(form);
      const courseData = collectStudentCourseData(form);
      await api(`/api/students/${form.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({
          name: formData.get('name'),
          rollNumber: formData.get('rollNumber'),
          studentMobile: formData.get('studentMobile'),
          guardianMobile: formData.get('guardianMobile'),
          college: formData.get('college'),
          sscResult: formData.get('sscResult'),
          sscPassingYear: formData.get('sscPassingYear'),
          hscResult: formData.get('hscResult'),
          hscPassingYear: formData.get('hscPassingYear'),
          photoDataUrl: formData.get('photoDataUrl'),
          courseIds: courseData.courseIds,
          courseFees: courseData.courseFees,
          batchEnrollments: courseData.batchEnrollments,
          admissionDate: formData.get('admissionDate'),
          email: formData.get('email'),
        }),
      });
      state.editingStudentId = '';
      await refreshDashboard();
      setMessage('Student information updated.');
      return;
    }

    if (action === 'save-student-fees') {
      const formData = new FormData(form);
      const courseFees = formData.getAll('courseId').map((courseId) => ({
        courseId,
        discount: formData.get(`discount_${courseId}`),
      }));
      await api(`/api/students/${form.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ courseFees }),
      });
      await refreshDashboard();
      setMessage('Course fees updated.');
      return;
    }

    if (action === 'add-payment') {
      const formData = new FormData(form);
      const { payment } = await api('/api/payments', {
        method: 'POST',
        body: JSON.stringify({
          studentId: formData.get('studentId'),
          courseId: formData.get('courseId'),
          amount: formData.get('amount'),
          method: formData.get('method'),
          paidAt: formData.get('paidAt'),
          reference: formData.get('reference'),
          note: formData.get('note'),
        }),
      });
      await refreshDashboard();
      setMessage(`Payment received. Receipt: ${payment.receiptNumber}`);
      return;
    }

    if (action === 'add-teacher-payment' || action === 'edit-teacher-payment') {
      const formData = new FormData(form);
      const payload = {
        teacherId: formData.get('teacherId'),
        courseId: formData.get('courseId'),
        batchId: formData.get('batchId'),
        month: formData.get('month'),
        subject: formData.get('subject'),
        defaultRate: formData.get('defaultRate'),
        classEntries: parseTeacherClassEntries(formData.get('classEntriesText'), formData.get('subject'), formData.get('defaultRate')),
        paidAmount: formData.get('paidAmount'),
        method: formData.get('method'),
        paidAt: formData.get('paidAt'),
        reference: formData.get('reference'),
        note: formData.get('note'),
      };
      await api(action === 'add-teacher-payment' ? '/api/teacher-payments' : `/api/teacher-payments/${form.dataset.id}`, {
        method: action === 'add-teacher-payment' ? 'POST' : 'PATCH',
        body: JSON.stringify(payload),
      });
      state.editingTeacherPaymentId = '';
      await refreshDashboard();
      setMessage(action === 'add-teacher-payment' ? 'Teacher payment saved.' : 'Teacher payment updated.');
      return;
    }

    if (action === 'add-employee-payment' || action === 'edit-employee-payment') {
      const formData = new FormData(form);
      const payload = {
        employeeId: formData.get('employeeId'),
        month: formData.get('month'),
        salaryAmount: formData.get('salaryAmount'),
        allowance: formData.get('allowance'),
        bonus: formData.get('bonus'),
        deduction: formData.get('deduction'),
        advance: formData.get('advance'),
        paidAmount: formData.get('paidAmount'),
        method: formData.get('method'),
        paidAt: formData.get('paidAt'),
        reference: formData.get('reference'),
        note: formData.get('note'),
      };
      await api(action === 'add-employee-payment' ? '/api/employee-payments' : `/api/employee-payments/${form.dataset.id}`, {
        method: action === 'add-employee-payment' ? 'POST' : 'PATCH',
        body: JSON.stringify(payload),
      });
      state.editingEmployeePaymentId = '';
      await refreshDashboard();
      setMessage(action === 'add-employee-payment' ? 'Employee payment saved.' : 'Employee payment updated.');
      return;
    }

    if (action === 'add-reference-payment') {
      const formData = new FormData(form);
      await api('/api/reference-payments', {
        method: 'POST',
        body: JSON.stringify(Object.fromEntries(formData)),
      });
      await refreshDashboard();
      setMessage('Reference payment saved.');
      return;
    }

    if (action === 'add-other-payment') {
      const formData = new FormData(form);
      await api('/api/other-payments', {
        method: 'POST',
        body: JSON.stringify(Object.fromEntries(formData)),
      });
      await refreshDashboard();
      setMessage('Expense saved.');
      return;
    }

    if (action === 'add-shareholder' || action === 'edit-shareholder') {
      const formData = new FormData(form);
      await api(action === 'add-shareholder' ? '/api/shareholders' : `/api/shareholders/${form.dataset.id}`, {
        method: action === 'add-shareholder' ? 'POST' : 'PATCH',
        body: JSON.stringify(Object.fromEntries(formData)),
      });
      state.editingShareholderId = '';
      await refreshDashboard();
      setMessage(action === 'add-shareholder' ? 'Shareholder saved.' : 'Shareholder updated.');
      return;
    }

    if (action === 'add-shareholder-ledger') {
      const formData = new FormData(form);
      await api('/api/shareholder-ledger', {
        method: 'POST',
        body: JSON.stringify(Object.fromEntries(formData)),
      });
      await refreshDashboard();
      setMessage('Shareholder ledger entry saved.');
      return;
    }

    if (action === 'add-recorded-class') {
      const formData = new FormData(form);
      await api('/api/recorded-classes', {
        method: 'POST',
        body: JSON.stringify({
          title: formData.get('title'),
          subject: formData.get('subject'),
          videoUrl: formData.get('videoUrl'),
          visibility: formData.get('visibility'),
          status: formData.get('status'),
          note: formData.get('note'),
          courseIds: formData.getAll('courseIds'),
          batchIds: formData.getAll('batchIds'),
        }),
      });
      await refreshDashboard();
      setMessage('Recorded class added.');
      return;
    }

    if (action === 'upload-manual-results') {
      const formData = new FormData(form);
      const result = await api('/api/manual-results', {
        method: 'POST',
        body: JSON.stringify({
          examName: formData.get('examName'),
          courseId: formData.get('courseId'),
          batchId: formData.get('batchId'),
          subject: formData.get('subject'),
          csv: formData.get('csv'),
        }),
      });
      await refreshDashboard();
      setMessage(`Uploaded ${result.created.length} manual result record(s).${result.skipped?.length ? ` Skipped: ${result.skipped.join(', ')}` : ''}`);
      return;
    }

    if (action === 'save-student-courses') {
      const formData = new FormData(form);
      await api(`/api/students/${form.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ courseIds: formData.getAll('courseIds') }),
      });
      state.editingStudentCoursesId = '';
      await refreshDashboard();
      setMessage('Student enrollment updated.');
      return;
    }

    if (action === 'import-students') {
      const formData = new FormData(form);
      const result = await api('/api/students/import', {
        method: 'POST',
        body: JSON.stringify({ csv: formData.get('csv') }),
      });
      await refreshDashboard();
      setMessage(`Imported ${result.created.length} students. Skipped ${result.skipped.length}.`);
      return;
    }

    if (action === 'import-quizzes') {
      syncEditingQuizFromForm();
      const formData = new FormData(form);
      const result = await api('/api/quizzes/import', {
        method: 'POST',
        body: JSON.stringify({ json: formData.get('json') }),
      });
      await refreshDashboard();
      setMessage(`Imported ${result.created.length} quizzes.`);
      return;
    }

    if (action === 'save-quiz') {
      await saveQuizForm(form, false);
      return;
    }

    if (action === 'submit-exam') {
      const formData = new FormData(form);
      const answers = {};
      for (const question of state.takingQuiz.questions) {
        answers[question.id] = formData.get(question.id);
      }
      const { attempt } = await api(`/api/quizzes/${form.dataset.id}/submit`, {
        method: 'POST',
        body: JSON.stringify({ answers, warnings: state.examWarnings }),
      });
      state.takingQuiz = null;
      state.examWarnings = 0;
      state.examSavedAt = '';
      state.view = 'results';
      await refreshDashboard();
      setMessage(`Submitted. Score: ${attempt.percentage}%`);
      return;
    }

    if (action === 'profile') {
      const formData = new FormData(form);
      const { user } = await api('/api/profile', {
        method: 'PATCH',
        body: JSON.stringify({
          name: formData.get('name'),
          mobile: formData.get('mobile'),
          college: formData.get('college'),
          sscResult: formData.get('sscResult'),
          sscPassingYear: formData.get('sscPassingYear'),
          hscResult: formData.get('hscResult'),
          hscPassingYear: formData.get('hscPassingYear'),
          photoDataUrl: formData.get('photoDataUrl'),
          email: formData.get('email'),
          currentPassword: formData.get('currentPassword'),
          newPassword: formData.get('newPassword'),
        }),
      });
      state.user = user;
      await refreshDashboard();
      setMessage('Profile updated.');
    }
  } catch (error) {
    state.error = error.message;
    render();
  } finally {
    setBusy(submitter, false);
  }
}

async function handleClick(event) {
  const button = event.target.closest('button');
  if (!button) return;
  const action = button.dataset.action;
  const view = button.dataset.view;

  try {
    if (action === 'dismiss-message') {
      state.message = '';
      state.error = '';
      render();
      return;
    }

    if (action === 'set-student-section') {
      state.studentSection = button.dataset.section || 'add';
      state.editingStudentId = '';
      state.viewingStudentId = '';
      render();
      return;
    }

    if (action === 'clear-student-filters') {
      state.studentListSearch = '';
      state.reportFilters ||= {};
      state.reportFilters.students = {};
      render();
      return;
    }

    if (action === 'clear-report-filters') {
      state.reportFilters ||= {};
      state.reportFilters[button.dataset.report] = {};
      render();
      return;
    }

    if (action === 'clear-activity-filter') {
      state.activityFilters = {};
      render();
      return;
    }

    if (action === 'set-manager-section') {
      state.managerSection = button.dataset.section || 'managers';
      state.editingRoleId = '';
      state.editingManagerId = '';
      render();
      return;
    }

    if (action === 'set-message-section') {
      state.messageSection = button.dataset.section || 'general';
      render();
      return;
    }

    if (action === 'set-payment-section') {
      state.paymentSection = button.dataset.section || 'overview';
      render();
      return;
    }

    if (action === 'generate-shareholder-profit') {
      if (!confirmSensitive({ title: 'Generate profit share', body: 'This creates shareholder ledger entries for the active session.', phrase: 'GENERATE' })) return;
      const result = await api('/api/shareholder-profit-share', { method: 'POST', body: JSON.stringify({}) });
      await refreshDashboard();
      setMessage(`Profit share generated. Net profit: ${formatMoney(result.summary?.profit || 0)}`);
      return;
    }

    if (action === 'edit-shareholder') {
      state.editingShareholderId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-shareholder-edit') {
      state.editingShareholderId = '';
      render();
      return;
    }

    if (action === 'delete-shareholder') {
      const item = (state.data.shareholders || []).find((shareholder) => shareholder.id === button.dataset.id);
      if (!item || !confirmSensitive({ title: 'Delete shareholder', body: `${item.name} will be deleted/deactivated. Existing ledger will be kept.`, phrase: 'DELETE' })) return;
      await api(`/api/shareholders/${button.dataset.id}`, { method: 'DELETE' });
      await refreshDashboard();
      setMessage('Shareholder deleted or deactivated.');
      return;
    }

    if (action === 'set-courses-section') {
      state.coursesSection = button.dataset.section || 'courses';
      render();
      return;
    }

    if (action === 'set-institute-section') {
      state.instituteSection = button.dataset.section || 'profile';
      render();
      return;
    }

    if (action === 'set-result-section') {
      state.resultSection = button.dataset.section || 'quiz';
      render();
      return;
    }

    if (action === 'set-student-exam-section') {
      state.studentExamSection = button.dataset.section || 'live';
      render();
      return;
    }

    if (action === 'set-student-result-section') {
      state.studentResultSection = button.dataset.section || 'submissions';
      render();
      return;
    }

    if (action === 'switch-session') {
      if (!confirmSensitive({ title: 'Switch active session', body: 'All dashboard data will change to the selected academic session.', phrase: 'SWITCH' })) return;
      await api('/api/sessions/active', {
        method: 'PATCH',
        body: JSON.stringify({ sessionId: button.dataset.id }),
      });
      await refreshDashboard();
      setMessage('Active session changed.');
      return;
    }

    if (action === 'toggle-course-option') {
      const option = button;
      const input = option.querySelector('input[data-course-value]');
      const dropdown = option.closest('[data-course-dropdown]');
      const summary = dropdown?.querySelector('[data-course-summary]');
      if (!input || !dropdown || !summary) return;
      const selected = !option.classList.contains('selected');
      option.classList.toggle('selected', selected);
      option.setAttribute('aria-pressed', String(selected));
      input.disabled = !selected;
      const selectedNames = [...dropdown.querySelectorAll('[data-action="toggle-course-option"].selected')]
        .map((item) => item.dataset.courseName);
      summary.textContent = selectedNames.length ? selectedNames.join(', ') : 'Select courses';
      if (dropdown.matches('[data-student-course-dropdown]')) refreshStudentCourseFinance(dropdown.closest('form'));
      return;
    }

    if (action === 'toggle-course-dropdown') {
      const dropdown = button.closest('[data-course-dropdown]');
      const menu = dropdown?.querySelector('.multi-select-menu');
      if (!dropdown || !menu) return;
      const isOpen = dropdown.classList.toggle('open');
      menu.hidden = !isOpen;
      button.setAttribute('aria-expanded', String(isOpen));
      return;
    }

    if (action === 'toggle-message-dropdown') {
      const dropdown = button.closest('[data-message-dropdown]');
      const menu = dropdown?.querySelector('.multi-select-menu');
      if (!dropdown || !menu) return;
      const isOpen = dropdown.classList.toggle('open');
      menu.hidden = !isOpen;
      button.setAttribute('aria-expanded', String(isOpen));
      return;
    }

    if (action === 'toggle-message-option') {
      const option = button;
      const dropdown = option.closest('[data-message-dropdown]');
      const input = option.querySelector('input[data-message-value]');
      const summary = dropdown?.querySelector('[data-message-summary]');
      if (!dropdown || !input || !summary) return;
      const selected = !option.classList.contains('selected');
      option.classList.toggle('selected', selected);
      option.setAttribute('aria-pressed', String(selected));
      input.disabled = !selected;
      const selectedNames = [...dropdown.querySelectorAll('[data-action="toggle-message-option"].selected')].map((item) => item.dataset.name);
      summary.textContent = selectedNames.length ? (selectedNames.length > 2 ? `${selectedNames.length} selected` : selectedNames.join(', ')) : (summary.dataset.placeholder || 'Select');
      return;
    }

    if (view) {
      state.view = view;
      state.message = '';
      state.error = '';
      render();
      return;
    }

    if (action === 'logout') {
      await api('/api/logout', { method: 'POST', body: '{}' });
      state = { user: null, institute: state.institute, data: null, view: 'overview', editingQuiz: null, savedQuizSnapshot: '', pendingQuizClose: false, takingQuiz: null, reviewingAttemptId: '', viewingQuizResultsId: '', editingStudentCoursesId: '', studentSection: 'add', editingStudentId: '', viewingStudentId: '', managerSection: 'managers', messageSection: 'general', paymentSection: 'overview', instituteSection: 'profile', resultSection: 'quiz', progressStudentId: '', progressSearch: '', editingRoleId: '', editingManagerId: '', editingTeacherId: '', editingEmployeeId: '', editingTeacherPaymentId: '', editingEmployeePaymentId: '', editingShareholderId: '', editingCourseId: '', deletingCourseId: '', editingBatchId: '', deletingBatchId: '', managingBatchId: '', analyticsCourseId: '', analyticsMonth: '', quizEditorTab: 'general', examWarnings: 0, examSavedAt: '', csrfToken: '', loginOtpToken: '', loginOtpMobile: '', loginDevOtp: '', showResetModal: false, equationModal: null, message: '', error: '' };
      render();
      return;
    }

    if (action === 'open-reset-modal') {
      state.showResetModal = true;
      state.error = '';
      render();
      return;
    }

    if (action === 'close-reset-modal') {
      state.showResetModal = false;
      render();
      return;
    }

    if (action === 'cancel-login-otp') {
      state.loginOtpToken = '';
      state.loginOtpMobile = '';
      state.loginDevOtp = '';
      state.loginOtpCredentials = null;
      state.loginOtpSeconds = 0;
      if (state.loginOtpTimer) clearInterval(state.loginOtpTimer);
      state.message = '';
      state.error = '';
      render();
      return;
    }

    if (action === 'resend-login-otp') {
      if (state.loginOtpSeconds || !state.loginOtpCredentials) return;
      const result = await api('/api/login', {
        method: 'POST',
        body: JSON.stringify(state.loginOtpCredentials),
      });
      state.loginOtpToken = result.otpToken || state.loginOtpToken;
      state.loginOtpMobile = result.maskedMobile || state.loginOtpMobile;
      state.loginDevOtp = result.devOtp || '';
      startLoginOtpTimer(60);
      setMessage(result.message || 'OTP resent.');
      return;
    }

    if (action === 'open-equation-modal') {
      syncEditingQuizFromForm();
      await ensureMathLive();
      const target = button.dataset.target || '';
      const field = target ? document.querySelector(`[name="${CSS.escape(target)}"]`) : null;
      state.equationModal = {
        target,
        start: field?.selectionStart ?? field?.value?.length ?? 0,
        end: field?.selectionEnd ?? field?.selectionStart ?? field?.value?.length ?? 0,
        latex: '',
      };
      render();
      return;
    }

    if (action === 'close-equation-modal') {
      state.equationModal = null;
      render();
      return;
    }

    if (action === 'equation-template') {
      insertEquationTemplate(button.dataset.value || '');
      return;
    }

    if (action === 'apply-equation') {
      applyEquationToQuestion();
      return;
    }

    if (action === 'toggle-student') {
      await api(`/api/students/${button.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ status: button.dataset.status }),
      });
      await refreshDashboard();
      setMessage('Student status updated.');
      return;
    }

    if (action === 'toggle-manager') {
      await api(`/api/managers/${button.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ status: button.dataset.status }),
      });
      await refreshDashboard();
      setMessage('Manager status updated.');
      return;
    }

    if (action === 'edit-manager') {
      state.editingManagerId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-manager-edit') {
      state.editingManagerId = '';
      render();
      return;
    }

    if (action === 'edit-role') {
      state.editingRoleId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-role-edit') {
      state.editingRoleId = '';
      render();
      return;
    }

    if (action === 'toggle-role') {
      await api(`/api/roles/${button.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ status: button.dataset.status }),
      });
      await refreshDashboard();
      setMessage('Role status updated.');
      return;
    }

    if (action === 'delete-role') {
      if (!confirmSensitive({ title: 'Delete role', body: 'Managers using this role may lose their menu access.', phrase: 'DELETE' })) return;
      await api(`/api/roles/${button.dataset.id}`, { method: 'DELETE', body: '{}' });
      await refreshDashboard();
      setMessage('Role deleted.');
      return;
    }

    if (action === 'reset-manager-password') {
      if (!confirmSensitive({ title: 'Reset manager password', body: 'The manager will need the new password to login.', phrase: 'RESET' })) return;
      const password = prompt('New password for this manager:');
      if (!password) return;
      await api(`/api/managers/${button.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ password }),
      });
      await refreshDashboard();
      setMessage('Manager password reset.');
      return;
    }

    if (action === 'edit-teacher') {
      state.editingTeacherId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-teacher-edit') {
      state.editingTeacherId = '';
      render();
      return;
    }

    if (action === 'toggle-teacher') {
      await api(`/api/teachers/${button.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ status: button.dataset.status }),
      });
      await refreshDashboard();
      setMessage('Teacher status updated.');
      return;
    }

    if (action === 'edit-employee') {
      state.editingEmployeeId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-employee-edit') {
      state.editingEmployeeId = '';
      render();
      return;
    }

    if (action === 'toggle-employee') {
      await api(`/api/employees/${button.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ status: button.dataset.status }),
      });
      await refreshDashboard();
      setMessage('Employee status updated.');
      return;
    }

    if (action === 'edit-teacher-payment') {
      state.editingTeacherPaymentId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-teacher-payment-edit') {
      state.editingTeacherPaymentId = '';
      render();
      return;
    }

    if (action === 'edit-employee-payment') {
      state.editingEmployeePaymentId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-employee-payment-edit') {
      state.editingEmployeePaymentId = '';
      render();
      return;
    }

    if (action === 'view-attempt-answers') {
      state.reviewingAttemptId = button.dataset.id;
      state.view = 'resultReview';
      render();
      return;
    }

    if (action === 'view-quiz-submissions') {
      state.viewingQuizResultsId = button.dataset.id;
      state.reviewingAttemptId = '';
      state.view = 'quizSubmissions';
      render();
      return;
    }

    if (action === 'back-to-results') {
      state.reviewingAttemptId = '';
      state.viewingQuizResultsId = '';
      state.view = 'results';
      render();
      return;
    }

    if (action === 'back-to-quiz-submissions') {
      state.reviewingAttemptId = '';
      state.view = 'quizSubmissions';
      render();
      return;
    }

    if (action === 'reset-password') {
      if (!confirmSensitive({ title: 'Reset student password', body: 'The student will need the new password to login.', phrase: 'RESET' })) return;
      const password = prompt('New password for this student:');
      if (!password) return;
      await api(`/api/students/${button.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ password }),
      });
      await refreshDashboard();
      setMessage('Password reset.');
      return;
    }

    if (action === 'edit-student') {
      state.editingStudentId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-student-edit') {
      state.editingStudentId = '';
      render();
      return;
    }

    if (action === 'view-student') {
      state.viewingStudentId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-student-details') {
      state.viewingStudentId = '';
      render();
      return;
    }

    if (action === 'print-student') {
      const student = (state.data.students || []).find((item) => item.id === button.dataset.id);
      if (student) printStudentProfile(student);
      return;
    }

    if (action === 'print-progress-report') {
      const report = isStaffUser() ? buildProgressReport(button.dataset.id) : {
        student: state.user,
        attempts: state.data.progressReport?.attempts || [],
        manual: state.data.progressReport?.manualResults || [],
        finance: state.data.finance || {},
        summary: {
          average: state.data.progressReport?.summary?.average || 0,
          best: state.data.progressReport?.summary?.best || 0,
        },
      };
      if (report) printProgressReport(report);
      return;
    }

    if (action === 'send-result-sms') {
      const form = document.querySelector('[data-export-form="result-sms"]');
      if (!form) return;
      const formData = new FormData(form);
      const result = await api('/api/result-sms/send', {
        method: 'POST',
        body: JSON.stringify({
          quizId: formData.get('quizId'),
          examName: formData.get('examName'),
          courseId: formData.get('courseId'),
          batchId: formData.get('batchId'),
          template: formData.get('template'),
        }),
      });
      await refreshDashboard();
      setMessage(`Result SMS sent/logged: ${result.count}`);
      return;
    }

    if (action === 'download-report') {
      if (!confirmSensitive({ title: 'Export report', body: 'This file may include student, payment, or result data. Download only for authorized use.', phrase: 'EXPORT' })) return;
      const form = document.querySelector(`[data-export-form="${button.dataset.report}"]`);
      if (!form) return;
      const params = new URLSearchParams();
      for (const [key, value] of new FormData(form)) {
        if (value) params.set(key, value);
      }
      const query = params.toString();
      window.open(`/api/export/${button.dataset.report}.${button.dataset.format}${query ? `?${query}` : ''}`, '_blank');
      return;
    }

    if (action === 'print-receipt') {
      const payment = (state.data.payments || []).find((item) => item.id === button.dataset.id);
      if (payment) printPaymentReceipt(payment);
      return;
    }

    if (action === 'cancel-payment') {
      if (!confirmSensitive({ title: 'Cancel payment', body: 'This payment will be marked cancelled and audit history will record the action.', phrase: 'CANCEL' })) return;
      const cancelReason = prompt('Cancellation reason:');
      if (cancelReason === null) return;
      await api(`/api/payments/${button.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ status: 'cancelled', cancelReason }),
      });
      await refreshDashboard();
      setMessage('Payment cancelled.');
      return;
    }

    if (action === 'edit-payment') {
      const payment = (state.data.payments || []).find((item) => item.id === button.dataset.id);
      if (!payment) return;
      const amount = prompt('Payment amount:', String(payment.amount));
      if (amount === null) return;
      const reference = prompt('Reference / transaction:', payment.reference || '');
      if (reference === null) return;
      const note = prompt('Payment note:', payment.note || '');
      if (note === null) return;
      await api(`/api/payments/${payment.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ amount, reference, note }),
      });
      await refreshDashboard();
      setMessage('Payment updated.');
      return;
    }

    if (action === 'manage-student-courses') {
      state.editingStudentCoursesId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-student-courses') {
      state.editingStudentCoursesId = '';
      render();
      return;
    }

    if (action === 'open-course-edit') {
      state.editingCourseId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-course-edit') {
      state.editingCourseId = '';
      render();
      return;
    }

    if (action === 'toggle-course') {
      await api(`/api/courses/${button.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ status: button.dataset.status }),
      });
      await refreshDashboard();
      setMessage('Course status updated.');
      return;
    }

    if (action === 'toggle-subject') {
      await api(`/api/subjects/${button.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ status: button.dataset.status }),
      });
      await refreshDashboard();
      setMessage('Subject status updated.');
      return;
    }

    if (action === 'edit-subject') {
      state.editingSubjectId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-subject-edit') {
      state.editingSubjectId = '';
      render();
      return;
    }

    if (action === 'delete-course') {
      state.deletingCourseId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-course-delete') {
      state.deletingCourseId = '';
      render();
      return;
    }

    if (action === 'confirm-delete-course') {
      if (!confirmSensitive({ title: 'Delete course', body: 'This course will be removed if it has no protected dependencies.', phrase: 'DELETE' })) return;
      await api(`/api/courses/${button.dataset.id}`, { method: 'DELETE', body: '{}' });
      state.deletingCourseId = '';
      await refreshDashboard();
      setMessage('Course deleted.');
      return;
    }

    if (action === 'edit-batch') {
      state.editingBatchId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-batch-edit') {
      state.editingBatchId = '';
      render();
      return;
    }

    if (action === 'manage-batch-students') {
      state.managingBatchId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-batch-students') {
      state.managingBatchId = '';
      render();
      return;
    }

    if (action === 'toggle-batch') {
      await api(`/api/batches/${button.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ status: button.dataset.status }),
      });
      await refreshDashboard();
      setMessage('Batch status updated.');
      return;
    }

    if (action === 'delete-batch') {
      state.deletingBatchId = button.dataset.id;
      render();
      return;
    }

    if (action === 'close-batch-delete') {
      state.deletingBatchId = '';
      render();
      return;
    }

    if (action === 'confirm-delete-batch') {
      if (!confirmSensitive({ title: 'Delete batch', body: 'This batch will be removed if it is safe to delete.', phrase: 'DELETE' })) return;
      await api(`/api/batches/${button.dataset.id}`, { method: 'DELETE', body: '{}' });
      state.deletingBatchId = '';
      await refreshDashboard();
      setMessage('Batch deleted.');
      return;
    }

    if (action === 'new-quiz') {
      state.editingQuiz = emptyQuizForm();
      state.savedQuizSnapshot = snapshotQuiz(state.editingQuiz);
      state.pendingQuizClose = false;
      state.quizEditorTab = 'general';
      render();
      return;
    }

    if (action === 'edit-quiz') {
      const quiz = state.data.quizzes.find((item) => item.id === button.dataset.id);
      state.editingQuiz = JSON.parse(JSON.stringify(quiz));
      state.savedQuizSnapshot = snapshotQuiz(state.editingQuiz);
      state.pendingQuizClose = false;
      state.quizEditorTab = 'general';
      render();
      return;
    }

    if (action === 'duplicate-quiz') {
      const { quiz } = await api(`/api/quizzes/${button.dataset.id}/duplicate`, { method: 'POST', body: '{}' });
      await refreshDashboard();
      setMessage(`Quiz duplicated as "${quiz.title}" draft.`);
      return;
    }

    if (action === 'set-quiz-tab') {
      syncEditingQuizFromForm();
      state.quizEditorTab = button.dataset.tab || 'general';
      render();
      return;
    }

    if (action === 'close-quiz-editor') {
      const form = document.querySelector('[data-action="save-quiz"]');
      if (form) {
        syncEditingQuizFromForm();
        const hasChanges = snapshotQuiz(state.editingQuiz || emptyQuizForm()) !== state.savedQuizSnapshot;
        if (hasChanges) {
          state.pendingQuizClose = true;
          render();
          return;
        }
      }
      state.editingQuiz = null;
      state.savedQuizSnapshot = '';
      state.pendingQuizClose = false;
      state.quizEditorTab = 'general';
      render();
      return;
    }

    if (action === 'save-and-close-quiz') {
      const form = document.querySelector('[data-action="save-quiz"]');
      if (form) await saveQuizForm(form, true);
      return;
    }

    if (action === 'discard-and-close-quiz') {
      state.editingQuiz = null;
      state.savedQuizSnapshot = '';
      state.pendingQuizClose = false;
      state.quizEditorTab = 'general';
      render();
      return;
    }

    if (action === 'cancel-quiz-close') {
      state.pendingQuizClose = false;
      render();
      return;
    }

    if (action === 'delete-quiz') {
      if (!confirmSensitive({ title: 'Delete quiz', body: 'This quiz will be deleted. Existing result history may be affected.', phrase: 'DELETE' })) return;
      await api(`/api/quizzes/${button.dataset.id}`, { method: 'DELETE', body: '{}' });
      await refreshDashboard();
      setMessage('Quiz deleted.');
      return;
    }

    if (action === 'add-question') {
      syncEditingQuizFromForm();
      state.editingQuiz = state.editingQuiz || emptyQuizForm();
      state.editingQuiz.questions.push({ type: 'mcq', text: '', options: ['', '', '', ''], correctIndex: 0, correctText: '', points: 1, explanation: '' });
      state.quizEditorTab = 'questions';
      render();
      return;
    }

    if (action === 'remove-question') {
      syncEditingQuizFromForm();
      state.editingQuiz = state.editingQuiz || emptyQuizForm();
      state.editingQuiz.questions.splice(Number(button.dataset.index), 1);
      if (!state.editingQuiz.questions.length) state.editingQuiz.questions.push({ type: 'mcq', text: '', options: ['', '', '', ''], correctIndex: 0, correctText: '', points: 1, explanation: '' });
      render();
      return;
    }

    if (action === 'review-attempt') {
      const manualPoints = prompt('Manual points to add for written answers:', '1');
      if (manualPoints === null) return;
      const reviewNote = prompt('Review note:', 'Reviewed manually') || '';
      await api(`/api/attempts/${button.dataset.id}`, {
        method: 'PATCH',
        body: JSON.stringify({ manualPoints, reviewNote }),
      });
      await refreshDashboard();
      setMessage('Attempt reviewed.');
      return;
    }

    if (action === 'start-exam') {
      const { quiz } = await api(`/api/quizzes/${button.dataset.id}/take`);
      state.takingQuiz = quiz;
      state.examWarnings = 0;
      state.examSavedAt = '';
      render();
      return;
    }

    if (action === 'cancel-exam') {
      if (!confirm('Leave this exam? Unsaved answers will be lost.')) return;
      state.takingQuiz = null;
      state.examWarnings = 0;
      state.examSavedAt = '';
      render();
    }
  } catch (error) {
    state.error = error.message;
    render();
  }
}

let timerInterval = null;
let autosaveInterval = null;

function startTimerIfNeeded() {
  clearInterval(timerInterval);
  clearInterval(autosaveInterval);
  const timer = document.querySelector('#timer');
  if (!timer) return;
  let seconds = Number(timer.dataset.seconds || 0);
  const form = document.querySelector('[data-action="submit-exam"]');
  const tick = () => {
    const minutes = Math.floor(seconds / 60);
    const rest = String(seconds % 60).padStart(2, '0');
    timer.textContent = `${minutes}:${rest}`;
    if (seconds <= 0) {
      clearInterval(timerInterval);
      form?.requestSubmit();
      return;
    }
    seconds -= 1;
  };
  tick();
  timerInterval = setInterval(tick, 1000);
  autosaveInterval = setInterval(() => autosaveExam(form), 15000);
  form?.addEventListener('change', () => autosaveExam(form), { passive: true });
  form?.addEventListener('input', debounce(() => autosaveExam(form), 1200), { passive: true });
}

function collectExamAnswers(form) {
  const answers = {};
  if (!state.takingQuiz || !form) return answers;
  const formData = new FormData(form);
  for (const question of state.takingQuiz.questions) {
    answers[question.id] = formData.get(question.id);
  }
  return answers;
}

async function autosaveExam(form) {
  if (!state.takingQuiz || !form) return;
  try {
    const result = await api(`/api/quizzes/${form.dataset.id}/autosave`, {
      method: 'POST',
      body: JSON.stringify({ answers: collectExamAnswers(form), warnings: state.examWarnings }),
    });
    state.examSavedAt = result.savedAt;
    const box = document.querySelector('.warning-box span');
    if (box) box.innerHTML = `Tab switch/copy/paste à¦¸à¦¤à¦°à§à¦•à¦¤à¦¾: <b id="warning-count">${state.examWarnings}</b>. Last autosave: ${formatDate(state.examSavedAt)}`;
  } catch {
    // Keep the exam uninterrupted if an autosave request fails.
  }
}

function debounce(callback, delay) {
  let timer = null;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => callback(...args), delay);
  };
}

function setBusy(element, busy) {
  if (!element) return;
  if (busy) {
    element.dataset.originalText ||= element.textContent.trim();
    element.disabled = true;
    element.classList.add('is-busy');
    element.textContent = 'Processing...';
    return;
  }
  element.disabled = false;
  element.classList.remove('is-busy');
  if (element.dataset.originalText) {
    element.textContent = element.dataset.originalText;
    delete element.dataset.originalText;
  }
}

function confirmSensitive({ title, body, phrase }) {
  const suffix = phrase ? `\n\nGuard keyword: ${phrase}` : '';
  return window.confirm(`${title}\n\n${body}${suffix}\n\nDo you want to continue?`);
}

function parseBackupJson(backupJson) {
  let backup;
  try {
    backup = JSON.parse(backupJson);
  } catch {
    throw new Error('Backup JSON is not valid. Please paste a complete .json backup file.');
  }
  const type = backup?.type;
  if (!['session', 'full'].includes(type)) {
    throw new Error('Invalid backup type. Only session or full software backup is supported.');
  }
  if (type === 'session' && (!backup.session || !backup.data)) {
    throw new Error('Session backup is missing session data.');
  }
  if (type === 'full' && !backup.data?.users) {
    throw new Error('Full backup is missing software data.');
  }
  return backup;
}

function summarizeBackup(backup) {
  if (backup.type === 'full') {
    const data = backup.data || {};
    return [
      'Backup summary:',
      `Type: Full software backup`,
      `Sessions: ${(data.sessionsList || []).length}`,
      `Users: ${(data.users || []).length}`,
      `Exported: ${backup.exportedAt || '-'}`,
    ].join('\n');
  }
  const data = backup.data || {};
  return [
    'Backup summary:',
    `Type: Session backup`,
    `Session: ${backup.session?.name || '-'}`,
    `Students: ${(data.users || []).filter((item) => item.role === 'student').length}`,
    `Payments: ${(data.payments || []).length}`,
    `Results: ${(data.results || []).length + (data.manualResults || []).length}`,
    `Exported: ${backup.exportedAt || '-'}`,
  ].join('\n');
}

function closeTopLayer() {
  if (state.takingQuiz) return false;
  if (state.pendingQuizClose) {
    state.pendingQuizClose = false;
    render();
    return true;
  }
  const modalKeys = [
    'editingStudentId',
    'viewingStudentId',
    'editingManagerId',
    'editingRoleId',
    'editingTeacherId',
    'editingEmployeeId',
    'editingTeacherPaymentId',
    'editingEmployeePaymentId',
    'editingShareholderId',
    'editingCourseId',
    'deletingCourseId',
    'editingBatchId',
    'deletingBatchId',
    'managingBatchId',
    'editingStudentCoursesId',
    'reviewingAttemptId',
    'viewingQuizResultsId',
  ];
  const activeKey = modalKeys.find((key) => state[key]);
  if (activeKey) {
    state[activeKey] = '';
    render();
    return true;
  }
  if (state.showResetModal || state.equationModal) {
    state.showResetModal = false;
    state.equationModal = null;
    render();
    return true;
  }
  return false;
}

function handleKeydown(event) {
  if (event.key !== 'Escape') return;
  if (closeTopLayer()) event.preventDefault();
}

function recordExamWarning() {
  if (!state.takingQuiz) return;
  state.examWarnings += 1;
  const counter = document.querySelector('#warning-count');
  if (counter) counter.textContent = state.examWarnings;
}

function handleChange(event) {
  const activityForm = event.target.closest('[data-activity-filter]');
  if (activityForm) {
    state.activityFilters = Object.fromEntries([...new FormData(activityForm)].filter(([, value]) => value));
    render();
    return;
  }
  const exportForm = event.target.closest('[data-export-form]');
  if (exportForm) {
    state.reportFilters ||= {};
    state.reportFilters[exportForm.dataset.exportForm] = Object.fromEntries([...new FormData(exportForm)].filter(([, value]) => value));
    render();
    return;
  }
  if (event.target.matches('[data-image-input]')) {
    const input = event.target;
    readImageFile(input.files?.[0])
      .then((dataUrl) => {
        const hidden = input.closest('form')?.elements[input.dataset.imageInput];
        if (hidden) hidden.value = dataUrl;
      })
      .catch((error) => {
        state.error = error.message;
        render();
      });
    return;
  }
  if (event.target.matches('[data-analytics-course]')) {
    state.analyticsCourseId = event.target.value;
    render();
    return;
  }
  if (event.target.matches('[data-analytics-month]')) {
    state.analyticsMonth = event.target.value;
    render();
    return;
  }
  if (event.target.matches('[data-payment-student]')) {
    const student = (state.data.students || []).find((item) => item.id === event.target.value);
    const courseSelect = document.querySelector('[data-payment-course]');
    const dueHint = document.querySelector('[data-payment-due]');
    if (!courseSelect || !dueHint) return;
    courseSelect.innerHTML = '<option value="">Select course</option>' + (student?.finance?.enrollments || [])
      .map((item) => `<option value="${item.courseId}" data-due="${item.due}">${escapeHtml(item.courseName)} — Due ${formatMoney(item.due)}</option>`)
      .join('');
    dueHint.textContent = student ? `Total due: ${formatMoney(student.finance?.totalDue)}` : 'Select a student and course to see due.';
    return;
  }
  if (event.target.matches('[data-payment-course]')) {
    const option = event.target.options[event.target.selectedIndex];
    const due = Number(option?.dataset.due || 0);
    const amountInput = document.querySelector('[data-action="add-payment"] input[name="amount"]');
    const dueHint = document.querySelector('[data-payment-due]');
    if (amountInput) amountInput.max = due || '';
    if (dueHint) dueHint.textContent = `Current course due: ${formatMoney(due)}`;
    return;
  }
  if (event.target.matches('[data-progress-student]')) {
    state.progressStudentId = event.target.value;
    render();
    return;
  }
  if (event.target.matches('[data-progress-search]')) {
    state.progressSearch = event.target.value;
    state.progressStudentId = '';
    render();
    return;
  }
  if (!event.target.matches('[data-question-type-index]')) return;
  syncEditingQuizFromForm();
  state.quizEditorTab = 'questions';
  render();
}

function readImageFile(file) {
  return new Promise((resolve, reject) => {
    if (!file) {
      resolve('');
      return;
    }
    if (!['image/png', 'image/jpeg', 'image/svg+xml'].includes(file.type)) {
      reject(new Error('Only PNG, JPG, or SVG images are supported.'));
      return;
    }
    if (file.size > 180000) {
      reject(new Error('Image must be 180KB or smaller.'));
      return;
    }
    const reader = new FileReader();
    reader.onload = () => resolve(String(reader.result || ''));
    reader.onerror = () => reject(new Error('Could not read image file.'));
    reader.readAsDataURL(file);
  });
}

let mathLiveReadyPromise = null;

function waitForMathFieldElement(timeoutMs = 5000) {
  return new Promise((resolve, reject) => {
    const started = Date.now();
    const timer = setInterval(() => {
      if (window.customElements?.get('math-field')) {
        clearInterval(timer);
        resolve();
      } else if (Date.now() - started > timeoutMs) {
        clearInterval(timer);
        reject(new Error('Equation editor could not be loaded.'));
      }
    }, 50);
  });
}

function loadMathLiveClassicScript() {
  return new Promise((resolve, reject) => {
    const existing = document.querySelector('script[data-mathlive-fallback]');
    if (existing) {
      existing.addEventListener('load', () => resolve(), { once: true });
      existing.addEventListener('error', () => reject(new Error('Equation editor fallback could not be loaded.')), { once: true });
      return;
    }
    const script = document.createElement('script');
    script.src = '/vendor/mathlive/mathlive.min.js';
    script.defer = true;
    script.dataset.mathliveFallback = 'true';
    script.onload = () => resolve();
    script.onerror = () => reject(new Error('Equation editor fallback could not be loaded.'));
    document.head.appendChild(script);
  });
}

function ensureMathLive() {
  if (window.customElements?.get('math-field')) return Promise.resolve();
  if (!mathLiveReadyPromise) {
    mathLiveReadyPromise = import('/vendor/mathlive/mathlive.min.mjs')
      .catch(() => loadMathLiveClassicScript())
      .then(() => waitForMathFieldElement())
      .catch((error) => {
      mathLiveReadyPromise = null;
      throw error;
    });
  }
  return mathLiveReadyPromise;
}

function equationField() {
  return document.querySelector('[data-equation-field]');
}

function currentEquationLatex() {
  const field = equationField();
  const mathValue = typeof field?.getValue === 'function' ? String(field.getValue('latex') || '').trim() : '';
  return mathValue || String(field?.value || field?.getAttribute?.('value') || field?.textContent || '').trim();
}

function refreshEquationPreview() {
  const latex = currentEquationLatex();
  if (state.equationModal) state.equationModal.latex = latex;
  const preview = document.querySelector('[data-equation-preview]');
  if (preview) preview.innerHTML = renderMathFormula(latex, true);
}

function insertEquationTemplate(value) {
  const field = equationField();
  if (!field || !value) return;
  const templates = {
    '\\frac{}{}': '\\frac{\\placeholder{a}}{\\placeholder{b}}',
    '\\sqrt{}': '\\sqrt{\\placeholder{x}}',
    '\\sqrt[]{}': '\\sqrt[\\placeholder{n}]{\\placeholder{x}}',
    '^{}': '^{\\placeholder{2}}',
    '_{}': '_{\\placeholder{1}}',
    '^{}_{}': '^{\\placeholder{2}}_{\\placeholder{1}}',
    '\\sum_{}^{}': '\\sum_{\\placeholder{i=1}}^{\\placeholder{n}}',
    '\\int_{}^{}': '\\int_{\\placeholder{a}}^{\\placeholder{b}}',
    '\\lim_{}': '\\lim_{\\placeholder{x\\to0}}',
  };
  const template = templates[value] || value;
  if (typeof field.executeCommand === 'function') {
    field.executeCommand(['insert', template, { selectionMode: 'placeholder', insertionMode: 'replaceSelection' }]);
  } else if (typeof field.insert === 'function') {
    field.insert(template, { selectionMode: 'placeholder', insertionMode: 'replaceSelection' });
  } else {
    const nextValue = `${currentEquationLatex()}${template}`;
    field.value = nextValue;
    field.textContent = nextValue;
  }
  field.focus();
  refreshEquationPreview();
}

function applyEquationToQuestion() {
  const modal = state.equationModal;
  const latex = currentEquationLatex();
  if (!modal?.target || !latex) return;
  const field = document.querySelector(`[name="${CSS.escape(modal.target)}"]`);
  if (!field) return;
  const token = `\\(${latex}\\)`;
  const start = Number.isFinite(modal.start) ? modal.start : field.value.length;
  const end = Number.isFinite(modal.end) ? modal.end : start;
  field.value = `${field.value.slice(0, start)}${token}${field.value.slice(end)}`;
  state.equationModal = null;
  syncEditingQuizFromForm();
  render();
}

function handleInput(event) {
  if (event.target.matches('[data-roll-setting-input]')) {
    updateRollPreview();
    return;
  }
  if (event.target.matches('[data-fee-input], [data-discount-input], [data-deposit-input]')) {
    updateStudentFinanceCalculation(event.target);
    return;
  }
  if (event.target.matches('[data-student-search]')) {
    state.studentListSearch = event.target.value;
    const query = event.target.value.trim().toLowerCase();
    document.querySelectorAll('[data-student-row]').forEach((row) => {
      row.hidden = query && !String(row.dataset.search || '').includes(query);
    });
    return;
  }
  if (event.target.matches('[data-dashboard-search]')) {
    const cursor = event.target.selectionStart || event.target.value.length;
    state.dashboardSearch = event.target.value;
    render();
    requestAnimationFrame(() => {
      const field = document.querySelector('[data-dashboard-search]');
      if (!field) return;
      field.focus();
      field.setSelectionRange(cursor, cursor);
    });
    return;
  }
  if (event.target.matches('[data-math-input]')) {
    syncEditingQuizFromForm();
    const preview = event.target.closest('.field')?.nextElementSibling;
    if (preview?.classList.contains('math-preview')) {
      preview.classList.toggle('is-empty', !event.target.value.trim());
      preview.innerHTML = `<span class="preview-label">Student Preview</span><div>${renderMathText(event.target.value) || '<span class="muted">Preview will appear here.</span>'}</div>`;
    }
    return;
  }
  if (event.target.matches('[data-equation-field]')) {
    refreshEquationPreview();
  }
}

document.addEventListener('submit', handleSubmit);
document.addEventListener('click', handleClick);
document.addEventListener('change', handleChange);
document.addEventListener('input', handleInput);
document.addEventListener('keydown', handleKeydown);
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') recordExamWarning();
});
window.addEventListener('blur', recordExamWarning);
document.addEventListener('copy', recordExamWarning);
document.addEventListener('paste', recordExamWarning);

init().catch((error) => {
  state.error = error.message;
  render();
});
