// Split from public/app.js v1.7.7. Loaded by public/index.html.
const app = document.querySelector('#app');

let state = {
  user: null,
  institute: null,
  data: null,
  view: 'overview',
  editingQuiz: null,
  savedQuizSnapshot: '',
  pendingQuizClose: false,
  takingQuiz: null,
  reviewingAttemptId: '',
  viewingQuizResultsId: '',
  editingStudentCoursesId: '',
  studentSection: 'add',
  editingStudentId: '',
  viewingStudentId: '',
  managerSection: 'managers',
  paymentSection: 'overview',
  coursesSection: 'courses',
  instituteSection: 'profile',
  resultSection: 'quiz',
  studentExamSection: 'live',
  studentResultSection: 'submissions',
  reportFilters: {},
  dashboardSearch: '',
  studentFormDraft: {},
  progressStudentId: '',
  progressSearch: '',
  editingRoleId: '',
  editingManagerId: '',
  editingTeacherId: '',
  editingEmployeeId: '',
  editingTeacherPaymentId: '',
  editingEmployeePaymentId: '',
  editingShareholderId: '',
  editingCourseId: '',
  deletingCourseId: '',
  editingSubjectId: '',
  editingBatchId: '',
  deletingBatchId: '',
  managingBatchId: '',
  analyticsCourseId: '',
  analyticsMonth: '',
  quizEditorTab: 'general',
  examWarnings: 0,
  examSavedAt: '',
  csrfToken: '',
  loginOtpToken: '',
  loginOtpMobile: '',
  loginDevOtp: '',
  loginOtpSeconds: 0,
  loginOtpTimer: null,
  loginOtpCredentials: null,
  showResetModal: false,
  resetOtpToken: '',
  resetOtpHint: '',
  resetDevOtp: '',
  equationModal: null,
  message: '',
  error: '',
};

const icons = {
  overview: '<svg viewBox="0 0 24 24"><path d="M3 11.5 12 4l9 7.5v8a1 1 0 0 1-1 1h-5v-6H9v6H4a1 1 0 0 1-1-1v-8Z"/></svg>',
  students: '<svg viewBox="0 0 24 24"><path d="M8 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm8.5 1a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7ZM2 20a6 6 0 0 1 12 0v1H2v-1Zm12.5 1v-1a8 8 0 0 0-2.1-5.4A5.5 5.5 0 0 1 22 18.5V21h-7.5Z"/></svg>',
  messages: '<svg viewBox="0 0 24 24"><path d="M4 4h16v12H7l-3 3V4Zm3 4v2h10V8H7Zm0 4v2h7v-2H7Zm11 6 3 2v-8h-1v5h-2v1Z"/></svg>',
  courses: '<svg viewBox="0 0 24 24"><path d="m12 3 10 5-10 5L2 8l10-5Zm-7 9.5 7 3.5 7-3.5V18l-7 3.5L5 18v-5.5Z"/></svg>',
  managers: '<svg viewBox="0 0 24 24"><path d="M12 12a4 4 0 1 0-4-4 4 4 0 0 0 4 4Zm0 2c-4.42 0-8 2.24-8 5v2h16v-2c0-2.76-3.58-5-8-5Zm7.5-9 1 2.1 2.3.35-1.65 1.6.4 2.28-2.05-1.08-2.05 1.08.4-2.28-1.65-1.6 2.3-.35L19.5 5Z"/></svg>',
  quizzes: '<svg viewBox="0 0 24 24"><path d="M6 2h9l5 5v14a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Zm8 1.5V8h4.5L14 3.5ZM8 12h8v2H8v-2Zm0 4h8v2H8v-2Z"/></svg>',
  results: '<svg viewBox="0 0 24 24"><path d="M4 20h16v2H4v-2Zm2-8h3v6H6v-6Zm5-6h3v12h-3V6Zm5 3h3v9h-3V9Z"/></svg>',
  activity: '<svg viewBox="0 0 24 24"><path d="M12 2a10 10 0 1 0 10 10h-2a8 8 0 1 1-2.35-5.65L15 9h7V2l-2.9 2.9A9.96 9.96 0 0 0 12 2Zm1 5h-2v6l5 3 1-1.73-4-2.27V7Z"/></svg>',
  analytics: '<svg viewBox="0 0 24 24"><path d="M4 19h17v2H3V3h2v16Zm3-2 4-5 3 3 5-8 1.7 1.05-6.35 10.15-3.2-3.2-2.6 3.25L7 17Z"/></svg>',
  payments: '<svg viewBox="0 0 24 24"><path d="M3 5h18v14H3V5Zm2 3v2h14V8H5Zm0 5v4h8v-4H5Zm10 1h3v2h-3v-2Z"/></svg>',
  teacherPayments: '<svg viewBox="0 0 24 24"><path d="M12 3a4 4 0 1 1 0 8 4 4 0 0 1 0-8Zm-7 18v-1c0-3.31 3.14-6 7-6s7 2.69 7 6v1H5Zm14-8h3v2h-3v-2Zm0 4h3v2h-3v-2Z"/></svg>',
  teachers: '<svg viewBox="0 0 24 24"><path d="M12 3 3 8l9 5 9-5-9-5Zm-6 8.5V16c0 2.2 2.7 4 6 4s6-1.8 6-4v-4.5l-6 3-6-3ZM20 10v6h2V9l-2 1Z"/></svg>',
  employees: '<svg viewBox="0 0 24 24"><path d="M12 12a4 4 0 1 0-4-4 4 4 0 0 0 4 4Zm-7 9v-1c0-3.3 3.1-6 7-6s7 2.7 7 6v1H5Zm14-9h3v2h-3v-2Zm0 4h3v2h-3v-2Z"/></svg>',
  resultSms: '<svg viewBox="0 0 24 24"><path d="M4 4h16v12H7l-3 3V4Zm3 4v2h10V8H7Zm0 4v2h7v-2H7Z"/></svg>',
  recordedClasses: '<svg viewBox="0 0 24 24"><path d="M4 5h16v14H4V5Zm6 3v8l6-4-6-4Z"/></svg>',
  lecture: '<svg viewBox="0 0 24 24"><path d="M4 5h13a3 3 0 0 1 3 3v11H7a3 3 0 0 0-3 3V5Zm3 3v8h9V8H7Zm12 2 3-2v8l-3-2v-4Z"/></svg>',
  sessions: '<svg viewBox="0 0 24 24"><path d="M4 5c0-1.1 3.6-2 8-2s8 .9 8 2-3.6 2-8 2-8-.9-8-2Zm0 4c0 1.1 3.6 2 8 2s8-.9 8-2V7c-1.7 1.2-5.1 1.8-8 1.8S5.7 8.2 4 7v2Zm0 4c0 1.1 3.6 2 8 2s8-.9 8-2v-2c-1.7 1.2-5.1 1.8-8 1.8S5.7 12.2 4 11v2Zm0 4c0 1.1 3.6 2 8 2s8-.9 8-2v-2c-1.7 1.2-5.1 1.8-8 1.8S5.7 16.2 4 15v2Z"/></svg>',
  omr: '<svg viewBox="0 0 24 24"><path d="M5 3h14v18H5V3Zm3 4h2v2H8V7Zm4 0h4v2h-4V7Zm-4 4h2v2H8v-2Zm4 0h4v2h-4v-2Zm-4 4h2v2H8v-2Zm4 0h4v2h-4v-2Z"/></svg>',
  institute: '<svg viewBox="0 0 24 24"><path d="M4 21V8l8-5 8 5v13h-6v-6h-4v6H4Zm4-9h2V9H8v3Zm6 0h2V9h-2v3Z"/></svg>',
  exams: '<svg viewBox="0 0 24 24"><path d="M12 2a10 10 0 1 0 10 10h-2a8 8 0 1 1-8-8V2Zm1 1v10l7 4 .95-1.76L15 11.86V3h-2Z"/></svg>',
  profile: '<svg viewBox="0 0 24 24"><path d="M12 12a5 5 0 1 0-5-5 5 5 0 0 0 5 5Zm0 2c-4.42 0-8 2.24-8 5v2h16v-2c0-2.76-3.58-5-8-5Z"/></svg>',
};

function isStaffUser() {
  return ['admin', 'manager'].includes(state.user?.role);
}

function canAccessMenu(key) {
  if (state.user?.role === 'admin') return true;
  if (state.user?.role !== 'manager') return false;
  return (state.user.menuAccess || []).includes(key);
}

async function api(path, options = {}) {
  const response = await fetch(path, {
    headers: {
      'content-type': 'application/json',
      ...(state.csrfToken ? { 'x-csrf-token': state.csrfToken } : {}),
      ...(options.headers || {}),
    },
    credentials: 'same-origin',
    ...options,
  });
  const payload = await response.json().catch(() => ({}));
  if (!response.ok) throw new Error(payload.error || 'Request failed');
  return payload;
}

function html(strings, ...values) {
  return strings.reduce((output, string, index) => output + string + (values[index] ?? ''), '');
}

function escapeHtml(value) {
  return String(value ?? '')
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;')
    .replaceAll("'", '&#039;');
}

function formatDate(value) {
  if (!value) return '-';
  return new Date(value).toLocaleString();
}

function setMessage(message, error = '') {
  state.message = message;
  state.error = error;
  render();
}

async function refreshDashboard() {
  state.data = await api('/api/dashboard');
  if (state.data.institute) state.institute = state.data.institute;
}

function renderMathFormula(latex, displayMode = false) {
  const formula = String(latex || '').trim();
  if (!formula) return '<span class="muted">No equation yet.</span>';
  if (window.katex?.renderToString) {
    return window.katex.renderToString(formula, {
      displayMode,
      throwOnError: false,
      strict: 'ignore',
      trust: false,
      output: 'html',
    });
  }
  return `<code>${escapeHtml(formula)}</code>`;
}

function renderMathText(value) {
  const source = String(value || '');
  if (!source) return '';
  const pattern = /(\\\[((?:.|\n)*?)\\\]|\\\(((?:.|\n)*?)\\\)|\$\$((?:.|\n)*?)\$\$|\$([^$]+)\$)/g;
  let htmlOutput = '';
  let cursor = 0;
  let match;
  while ((match = pattern.exec(source))) {
    htmlOutput += escapeHtml(source.slice(cursor, match.index)).replace(/\n/g, '<br>');
    const isDisplay = match[2] !== undefined || match[4] !== undefined;
    const formula = match[2] ?? match[3] ?? match[4] ?? match[5] ?? '';
    htmlOutput += `<span class="${isDisplay ? 'math-display-wrap' : 'math-inline-wrap'}">${renderMathFormula(formula, isDisplay)}</span>`;
    cursor = match.index + match[0].length;
  }
  htmlOutput += escapeHtml(source.slice(cursor)).replace(/\n/g, '<br>');
  return htmlOutput;
}

async function init() {
  const { user, institute, csrfToken } = await api('/api/me');
  state.user = user;
  state.institute = institute;
  state.csrfToken = csrfToken || '';
  if (user) await refreshDashboard();
  render();
}

function loginView() {
  const institute = state.institute || {};
  const resetToken = new URLSearchParams(location.search).get('reset');
  if (resetToken) {
    return html`
      <main class="login-page">
        <section class="login-card">
          <div class="brand" style="margin-bottom: 22px;">
            <strong>Set New Password</strong>
            <span>Enter a new password for your account.</span>
          </div>
          ${state.message ? `<div class="message">${escapeHtml(state.message)}</div>` : ''}
          ${state.error ? `<div class="message error">${escapeHtml(state.error)}</div>` : ''}
          <form class="form-grid" data-action="confirm-reset">
            <input type="hidden" name="token" value="${escapeHtml(resetToken)}">
            <label class="field"><span>OTP Code</span><input name="otp" inputmode="numeric" autocomplete="one-time-code" required></label>
            <label class="field"><span>New Password</span><input name="password" type="password" minlength="6" required></label>
            <button class="btn" type="submit">Reset Password</button>
          </form>
        </section>
      </main>
    `;
  }
  if (state.loginOtpToken) {
    return html`
      <main class="login-page">
        <section class="login-card">
          <div class="brand" style="margin-bottom: 22px;">
            <strong>Login OTP</strong>
            <span>${escapeHtml(state.loginOtpMobile ? `OTP sent to ${state.loginOtpMobile}` : 'Enter the OTP from SMS')}</span>
          </div>
          ${state.error ? `<div class="message error">${escapeHtml(state.error)}</div>` : ''}
          ${state.message ? `<div class="message">${escapeHtml(state.message)}</div>` : ''}
          <form class="form-grid" data-action="verify-login-otp">
            <label class="field"><span>OTP Code</span><input name="otp" inputmode="numeric" autocomplete="one-time-code" value="${escapeHtml(state.loginDevOtp || '')}" required autofocus></label>
            <button class="btn" type="submit">Verify OTP</button>
          </form>
          <p class="muted">${state.loginOtpSeconds ? `Resend available in ${state.loginOtpSeconds}s` : 'You can request a new OTP now.'}</p>
          <button class="btn secondary reset-link" type="button" data-action="resend-login-otp" ${state.loginOtpSeconds ? 'disabled' : ''}>Resend OTP</button>
          <button class="btn secondary reset-link" type="button" data-action="cancel-login-otp">Back to login</button>
        </section>
      </main>
    `;
  }
  return html`
    <main class="login-page">
      <section class="login-card">
        <div class="brand" style="margin-bottom: 22px;">
          <strong>${escapeHtml(institute.name || 'Student Management System')}</strong>
          <span>${escapeHtml(institute.tagline || 'Admin and Student quiz exam app')}</span>
        </div>
        ${state.error ? `<div class="message error">${escapeHtml(state.error)}</div>` : ''}
        ${state.message ? `<div class="message">${escapeHtml(state.message)}</div>` : ''}
        <form class="form-grid" data-action="login">
          <label class="field">
            <span>Mobile Number / Student ID</span>
            <input name="email" value="01796997871" autocomplete="username" required>
          </label>
          <label class="field">
            <span>Password</span>
            <input name="password" type="password" value="admin123" autocomplete="current-password" required>
          </label>
          <button class="btn" type="submit">Login</button>
          <p class="muted">Demo Admin: 01796997871 / admin123<br>Demo Student: DEMO-001 অথবা 01700000000 / student123</p>
        </form>
        <button class="btn secondary reset-link" type="button" data-action="open-reset-modal">Forgot password?</button>
      </section>
      ${state.showResetModal ? resetPasswordModal() : ''}
    </main>
  `;
}

function startLoginOtpTimer(seconds = 60) {
  if (state.loginOtpTimer) clearInterval(state.loginOtpTimer);
  state.loginOtpSeconds = seconds;
  state.loginOtpTimer = setInterval(() => {
    state.loginOtpSeconds = Math.max(0, Number(state.loginOtpSeconds || 0) - 1);
    if (!state.loginOtpSeconds) clearInterval(state.loginOtpTimer);
    render();
  }, 1000);
}

function resetPasswordModal() {
  if (state.resetOtpToken) {
    return html`
      <div class="modal-backdrop">
        <section class="modal-card">
          <div class="panel-header"><div><h2>Password Reset OTP</h2><p class="muted">${escapeHtml(state.resetOtpHint || 'Enter OTP and new password.')}</p></div><button class="btn secondary small" type="button" data-action="close-reset-modal">Close</button></div>
          <form class="form-grid" data-action="confirm-reset-otp">
            <input type="hidden" name="token" value="${escapeHtml(state.resetOtpToken)}">
            <label class="field"><span>OTP Code</span><input name="otp" inputmode="numeric" autocomplete="one-time-code" value="${escapeHtml(state.resetDevOtp || '')}" required></label>
            <label class="field"><span>New Password</span><input name="password" type="password" minlength="6" required></label>
            <button class="btn" type="submit">Reset Password</button>
          </form>
        </section>
      </div>
    `;
  }
  return html`
    <div class="modal-backdrop">
      <section class="modal-card">
        <div class="panel-header">
          <div>
            <h2>Password Reset</h2>
            <p class="muted">Enter your email address. If it exists, a reset link will be sent or logged.</p>
          </div>
          <button class="btn secondary small" type="button" data-action="close-reset-modal">Close</button>
        </div>
        <form class="form-grid" data-action="request-reset">
          <label class="field"><span>Email / Mobile</span><input name="email" placeholder="email@example.com or 01XXXXXXXXX" required></label>
          <button class="btn" type="submit">Send OTP / Reset Link</button>
        </form>
      </section>
    </div>
  `;
}

function shell(content) {
  const institute = state.institute || state.data?.institute || {};
  const paymentPermissions = ['payments', 'studentPayments', 'teacherPayments', 'employeePayments', 'referencePayments', 'otherPayments'];
  const canShowNav = (key) => key !== 'payments' ? canAccessMenu(key) : paymentPermissions.some((permission) => canAccessMenu(permission));
  const staffNavSections = [
    { title: 'Dashboard', items: [['overview', 'Overview'], ['analytics', 'Analytics']] },
    { title: 'Academic', items: [['sessions', 'Sessions'], ['courses', 'Courses'], ['students', 'Students'], ['recordedClasses', 'Recorded Classes']] },
    { title: 'Exam', items: [['quizzes', 'Quizzes'], ['results', 'Results'], ['messages', 'Messages']] },
    { title: 'Finance', items: [['payments', 'Payments']] },
    { title: 'People', items: [['teachers', 'Teachers'], ['employees', 'Employees'], ['managers', 'Managers']] },
    { title: 'System', items: [['institute', 'Institute'], ['activity', 'Activity'], ['profile', 'Profile']] },
  ].map((section) => ({
    ...section,
    items: section.items.filter(([key]) => (key !== 'managers' && key !== 'sessions' && key !== 'activity') || state.user.role === 'admin').filter(([key]) => canShowNav(key)),
  })).filter((section) => section.items.length);
  const studentNavSections = [
    {
      title: 'Student',
      items: [
        ['overview', 'Dashboard'],
        ['exams', 'My Exams'],
        ['results', 'My Results'],
        ['lecture', 'Lecture'],
        ['payments', 'My Payment'],
        ['profile', 'Profile'],
      ],
    },
  ];
  const navSections = isStaffUser() ? staffNavSections : studentNavSections;

  return html`
    <div class="shell" style="--brand:${escapeHtml(institute.primaryColor || '#2563eb')};--brand-strong:${escapeHtml(institute.primaryColor || '#1d4ed8')};--brand-secondary:${escapeHtml(institute.secondaryColor || '#38bdf8')};">
      <header class="topbar">
        <div class="brand">
          ${institute.logoDataUrl ? `<img class="brand-logo" src="${escapeHtml(institute.logoDataUrl)}" alt="">` : ''}
          <strong>${escapeHtml(institute.name || (state.user.role === 'admin' ? 'Admin Panel' : state.user.role === 'manager' ? 'Exam Manager Panel' : 'Student Panel'))}</strong>
          <span>${escapeHtml(institute.tagline || 'Student quiz and exam management')}</span>
        </div>
        <div class="userbar">
          ${isStaffUser() && state.data?.activeSession?.name ? `<span class="session-pill">${escapeHtml(state.data.activeSession.name)}</span>` : ''}
          <span class="user-avatar">${escapeHtml(String(state.user.name || 'U').trim().slice(0, 1).toUpperCase())}</span>
          <div class="userbar-name">
            <strong>${escapeHtml(state.user.name)}</strong>
          </div>
          <button class="btn secondary small" data-action="logout">Logout</button>
        </div>
      </header>
      <div class="layout">
        <aside class="sidebar">
          ${navSections.map((section) => html`
            <div class="nav-group">
              <div class="nav-group-title">${escapeHtml(section.title)}</div>
              ${section.items.map(([key, label]) => html`
                <button class="nav-button ${state.view === key ? 'active' : ''}" data-view="${key}">
                  <span class="nav-icon">${icons[key] || ''}</span>
                  <span>${label}</span>
                </button>
              `).join('')}
            </div>
          `).join('')}
        </aside>
        <main class="main">
          ${(state.message || state.error) ? html`
            <div class="toast-stack" role="status" aria-live="polite">
              ${state.message ? `<div class="message"><strong>Success</strong><span>${escapeHtml(state.message)}</span><button class="toast-close" type="button" data-action="dismiss-message" aria-label="Dismiss message">×</button></div>` : ''}
              ${state.error ? `<div class="message error"><strong>Attention</strong><span>${escapeHtml(state.error)}</span><button class="toast-close" type="button" data-action="dismiss-message" aria-label="Dismiss message">×</button></div>` : ''}
            </div>
          ` : ''}
          ${content}
          <footer class="app-footer">Software version v${escapeHtml(state.data?.version || '1.4.0')}</footer>
        </main>
      </div>
    </div>
  `;
}

