#!/usr/bin/env python3
"""
LMS Academy Module v1.0
JvG Consultancy — HSEQ Intelligence Dashboard
Flask module: User portal, Admin portal, Quiz engine, Compliance matrix
All routes prefixed /lms/ — register via app.register_blueprint(lms_bp) or direct import.
"""

import os
import json
import uuid
import sqlite3
from datetime import datetime, date, timedelta

from flask import (
    Blueprint, request, render_template_string, redirect, url_for,
    jsonify, session
)

# ── Config ───────────────────────────────────────────────────────────────────
BASE_PATH = os.environ.get('BASE_PATH', '/hseq-dashboard')
DB_PATH = os.environ.get('LMS_DB_PATH', '/root/projects/jg/HSEQ/HSEQ-Intelligence-Monitor/app/hseq_kennisbank.db')

lms_bp = Blueprint('lms', __name__, url_prefix='/lms')

# Note: nginx strips BASE_PATH, so Flask sees /lms/ not /hseq-dashboard/lms/

@lms_bp.before_request
def _lms_admin_guard():
    """Protect all /admin/ routes — redirect non-admin users to user dashboard."""
    from flask import request as req, redirect
    if req.path.startswith(os.environ.get('BASE_PATH', '/hseq-dashboard') + '/lms/admin'):
        uid = session.get('user_id')
        if not uid:
            return redirect(os.environ.get('BASE_PATH', '/hseq-dashboard') + '/lms/')
        db = get_db()
        try:
            user = db.execute('SELECT role FROM users WHERE id = ?', (uid,)).fetchone()
            if not user or user['role'] not in ('admin', 'hseq_manager'):
                return redirect(os.environ.get('BASE_PATH', '/hseq-dashboard') + '/lms/')
        finally:
            db.close()

# Try to use existing get_db from search module; fallback to direct connection
try:
    import sys, importlib
    _app_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)))
    if _app_dir not in sys.path:
        sys.path.insert(0, _app_dir)
    from search import get_db as _get_db
    def get_db():
        return _get_db()
except Exception:
    def get_db():
        conn = sqlite3.connect(DB_PATH)
        conn.row_factory = sqlite3.Row
        return conn

# ── Helpers ──────────────────────────────────────────────────────────────────

def _current_employee_id():
    """Stub: returns Jorick's employee ID. Replace with real session auth."""
    return 7


def _current_employee_name():
    """Stub: returns Jorick's full name. Replace with real session auth."""
    conn = get_db()
    try:
        r = conn.execute("SELECT first_name, last_name FROM employees WHERE id=7").fetchone()
        return f"{r['first_name']} {r['last_name']}" if r else 'Medewerker'
    finally:
        conn.close()


def _base_css():
    return """
    :root{--primary:#003366;--primary-light:#1a5276;--success:#00A859;--warning:#F59E0B;--danger:#EF4444;--bg:#F3F4F6;--card:#fff;--text:#1F2937;--text-muted:#6B7280;--border:#E5E7EB}
    *{box-sizing:border-box;margin:0;padding:0}
    body{font-family:'Segoe UI',system-ui,-apple-system,sans-serif;background:var(--bg);color:var(--text);line-height:1.6}
    .container{max-width:1200px;margin:0 auto;padding:20px}
    h1{font-size:1.5rem;font-weight:700;color:var(--primary);margin-bottom:16px}
    h2{font-size:1.2rem;font-weight:600;color:var(--primary);margin:20px 0 12px}
    .cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;margin-bottom:24px}
    .card{background:var(--card);border-radius:10px;padding:20px;box-shadow:0 1px 3px rgba(0,0,0,.08)}
    .card .label{font-size:.75rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px}
    .card .value{font-size:1.8rem;font-weight:700;color:var(--primary)}
    .card.success .value{color:var(--success)}
    .card.warning .value{color:var(--warning)}
    .card.danger .value{color:var(--danger)}
    table{width:100%;border-collapse:collapse;background:var(--card);border-radius:8px;overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,.08)}
    th,td{padding:10px 14px;text-align:left;font-size:.85rem;border-bottom:1px solid var(--border)}
    th{background:var(--primary);color:#fff;font-weight:600;font-size:.75rem;text-transform:uppercase;letter-spacing:.5px}
    tr:hover{background:#f0f4ff}
    .badge{display:inline-block;padding:2px 10px;border-radius:12px;font-size:.7rem;font-weight:600}
    .badge-success{background:#d1fae5;color:#065f46}
    .badge-warning{background:#fef3c7;color:#92400e}
    .badge-danger{background:#fee2e2;color:#991b1b}
    .badge-info{background:#dbeafe;color:#1e40af}
    .badge-muted{background:#e5e7eb;color:#4b5563}
    .progress-bar{background:#e5e7eb;border-radius:6px;height:8px;overflow:hidden}
    .progress-fill{height:100%;border-radius:6px;background:var(--success);transition:width .3s}
    .btn{display:inline-block;padding:8px 18px;border-radius:6px;font-size:.85rem;font-weight:600;text-decoration:none;border:none;cursor:pointer;transition:all .15s}
    .btn-primary{background:var(--primary);color:#fff}
    .btn-primary:hover{background:var(--primary-light)}
    .btn-success{background:var(--success);color:#fff}
    .btn-danger{background:var(--danger);color:#fff}
    .btn-warning{background:var(--warning);color:#fff}
    .btn-sm{padding:5px 12px;font-size:.75rem}
    .tabs{display:flex;gap:4px;margin-bottom:20px;border-bottom:2px solid var(--border);padding-bottom:0}
    .tabs a{padding:10px 20px;text-decoration:none;color:var(--text-muted);font-size:.85rem;font-weight:600;border-bottom:3px solid transparent;margin-bottom:-2px}
    .tabs a.active{color:var(--primary);border-bottom-color:var(--primary)}
    .tabs a:hover{color:var(--primary)}
    .heatmap{border-collapse:collapse;font-size:.75rem}
    .heatmap th,.heatmap td{padding:6px 10px;text-align:center;border:1px solid var(--border)}
    .heatmap .green{background:#d1fae5}.heatmap .amber{background:#fef3c7}.heatmap .red{background:#fee2e2}
    .iframe-wrap{position:relative;width:100%;padding-bottom:65%;height:0;overflow:hidden;border-radius:8px;box-shadow:0 2px 8px rgba(0,0,0,.1)}
    .iframe-wrap iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:none}
    @media(max-width:768px){.cards{grid-template-columns:1fr 1fr}.container{padding:12px}table{font-size:.75rem}th,td{padding:6px 8px}}
    """


def _is_admin():
    """Check if current user has admin role. Plant Managers and HSEQ Officers are admin."""
    conn = get_db()
    try:
        emp = conn.execute("SELECT role_id FROM employees WHERE id=?", (_current_employee_id(),)).fetchone()
        if not emp:
            return False
        return emp['role_id'] in (6, 10)  # HSEQ Officer=6, Plant Manager=10
    finally:
        conn.close()


def _deadline_html(due_date_str):
    """Return deadline with color-coded badge."""
    if not due_date_str or due_date_str in ('None', '', 'null'):
        return '<span style="color:var(--text-muted)">—</span>'
    try:
        due = datetime.strptime(due_date_str, '%Y-%m-%d').date()
    except:
        return due_date_str
    today = date.today()
    days_left = (due - today).days
    if days_left < 0:
        return f'<span style="display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:4px;font-size:.8rem;font-weight:600;background:#EF444415;color:#EF4444">Verlopen ({abs(days_left)}d)</span>'
    elif days_left <= 7:
        return f'<span style="display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:4px;font-size:.8rem;font-weight:600;background:#EF444415;color:#EF4444">⚠️ {days_left}d</span>'
    elif days_left <= 14:
        return f'<span style="display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:4px;font-size:.8rem;font-weight:600;background:#F59E0B15;color:#92400E">{days_left}d</span>'
    elif days_left <= 30:
        return f'<span style="display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:4px;font-size:.8rem;font-weight:600;background:#F59E0B15;color:#92400E">{days_left}d</span>'
    else:
        return f'<span style="display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:4px;font-size:.8rem;font-weight:600;background:#00A85915;color:#065F46">✅ {due_date_str}</span>'
    uid = session.get('user_id')
    if not uid:
        return False
    db = get_db()
    try:
        user = db.execute('SELECT role FROM users WHERE id = ?', (uid,)).fetchone()
        return user and user['role'] in ('admin', 'hseq_manager')
    finally:
        db.close()


_page_fn = None

def _page(title, body_html, active_tab='dashboard'):
    global _page_fn
    if _page_fn is not None:
        is_admin_view = active_tab.startswith('admin')
        tabs_user = f'''<div class="tabs">
            <a href="{BASE_PATH}/lms/" class="{{'active' if active_tab=='dashboard' else ''}}">📊 Dashboard</a>
            <a href="{BASE_PATH}/lms/my-courses" class="{{'active' if active_tab=='courses' else ''}}">📚 Mijn Trainingen</a>
            <a href="{BASE_PATH}/lms/my-certificates" class="{{'active' if active_tab=='certs' else ''}}">🏆 Certificaten</a>
        </div>'''
        tabs_admin = f'''<div class="tabs">
            <a href="{BASE_PATH}/lms/admin/courses" class="{{'active' if active_tab=='admin-courses' else ''}}">📖 Cursussen</a>
            <a href="{BASE_PATH}/lms/admin/enrollments" class="{{'active' if active_tab=='admin-enroll' else ''}}">👥 Inschrijvingen</a>
            <a href="{BASE_PATH}/lms/admin/compliance" class="{{'active' if active_tab=='admin-compliance' else ''}}">🛡️ Compliance</a>
            <a href="{BASE_PATH}/lms/admin/analytics" class="{{'active' if active_tab=='admin-analytics' else ''}}">📈 Analytics</a>
        </div>'''
        tabs = tabs_admin if is_admin_view else tabs_user
        # Build action buttons for the main header area
        user_btn_class = 'btn-active-portal' if not is_admin_view else 'btn btn-sm btn-outline'
        admin_btn_html = ''
        if _is_admin():
            admin_btn_class = 'btn-active-portal' if is_admin_view else 'btn btn-sm btn-outline'
            admin_btn_html = f'<a href="{BASE_PATH}/lms/admin/courses" class="{admin_btn_class}">⚙️ Admin</a>'
        action_btns = '<div style="display:flex;gap:6px;margin-bottom:12px"><a href="' + os.environ.get('BASE_PATH', '/hseq-dashboard') + '/lms/" class="' + user_btn_class + '">🏠 User Portal</a>' + admin_btn_html + '</div>'
        full_body = action_btns + tabs + '<div class="lms-body">' + body_html + '</div>'
        return _page_fn(full_body, active='lms', page_title=title)


# ═══════════════════════════════════════════════════════════════════════════════
# USER PORTAL
# ═══════════════════════════════════════════════════════════════════════════════

@lms_bp.route('/')
def user_dashboard():
    emp_id = _current_employee_id()
    conn = get_db()
    try:
        enrollments = conn.execute("""
            SELECT e.*, m.title, m.duration_minutes, m.category
            FROM lms_enrollments e
            JOIN elearning_modules m ON m.id = e.elearning_module_id
            WHERE e.employee_id = ?
            ORDER BY e.due_date ASC
        """, (emp_id,)).fetchall()

        completed = sum(1 for e in enrollments if e['status'] == 'completed')
        in_progress = sum(1 for e in enrollments if e['status'] == 'in_progress')
        not_started = sum(1 for e in enrollments if e['status'] == 'not_started')
        expiring = sum(1 for e in enrollments if e['due_date'] and e['due_date'] < str(date.today() + timedelta(days=30)) and e['status'] != 'completed')

        certs = conn.execute("""
            SELECT c.*, m.title
            FROM trn_certificates c
            JOIN elearning_modules m ON m.id = c.module_id
            WHERE c.employee_id = ?
            ORDER BY c.id DESC
        """, (emp_id,)).fetchall()
    finally:
        conn.close()

    open_rows = ""
    completed_rows = ""
    for e in enrollments:
        badge = {'not_started':'badge-muted','in_progress':'badge-info','completed':'badge-success','failed':'badge-danger','expired':'badge-warning'}.get(e['status'],'badge-muted')
        status_label = e['status'].replace('_',' ').title()
        pct = e['progress_percent'] or 0
        deadline = _deadline_html(e['due_date'] if 'due_date' in e.keys() else None)
        row = f"""<tr>
            <td><strong>{e['title']}</strong><br><small style="color:var(--text-muted)">{e['category'] or ''}</small></td>
            <td><div class="progress-bar"><div class="progress-fill" style="width:{pct}%"></div></div><small>{pct}%</small></td>
            <td><span class="badge {badge}">{status_label}</span></td>
            <td>{deadline}</td>
            <td><a href="{BASE_PATH}/lms/course/{e['elearning_module_id']}" class="btn btn-sm btn-primary">Openen</a></td>
        </tr>"""
        if e['status'] in ('completed', 'failed', 'expired', 'withdrawn'):
            completed_rows += row
        else:
            open_rows += row

    body = f"""
    <div class="cards">
        <div class="card"><div class="card-icon">📚</div><div><div class="label">Totaal Trainingen</div><div class="value">{len(enrollments)}</div></div></div>
        <div class="card success"><div class="card-icon">✅</div><div><div class="label">Voltooid</div><div class="value">{completed}</div></div></div>
        <div class="card warning"><div class="card-icon">⏳</div><div><div class="label">In Uitvoering</div><div class="value">{in_progress}</div></div></div>
        <div class="card danger"><div class="card-icon">⚠️</div><div><div class="label">Nakomend / Verlopen</div><div class="value">{expiring}</div></div></div>
    </div>
    <h2>📋 Openstaande Trainingen</h2>
    <table><tr><th>Cursus</th><th>Voortgang</th><th>Status</th><th>Deadline</th><th></th></tr>
    {open_rows or '<tr><td colspan="5" style="text-align:center;color:var(--text-muted)">Geen openstaande trainingen 🎉</td></tr>'}
    </table>
    <h2>✅ Afgeronde Trainingen</h2>
    <table><tr><th>Cursus</th><th>Score</th><th>Status</th><th>Deadline</th></tr>
    {completed_rows or '<tr><td colspan="4" style="text-align:center;color:var(--text-muted)">Geen afgeronde trainingen</td></tr>'}
    </table>
    <h2>Recente Certificaten</h2>
    <table><tr><th>Training</th><th>Score</th><th>Geldig</th><th>Ref</th><th></th></tr>
    {"".join(f'<tr><td>{c["title"]}</td><td>{c["quiz_score"]}%</td><td>{c["valid_until"] or "—"}</td><td><code style="font-size:.8rem">{c["certificate_ref"]}</code></td><td><a href="{BASE_PATH}/lms/certificate/{c["id"]}" class="btn btn-sm btn-primary">📄</a></td></tr>' for c in certs) or '<tr><td colspan="5" style="text-align:center;color:var(--text-muted)">Nog geen certificaten</td></tr>'}
    </table>"""
    return _page('Dashboard', body, 'dashboard')


@lms_bp.route('/my-courses')
def my_courses():
    emp_id = _current_employee_id()
    conn = get_db()
    try:
        enrollments = conn.execute("""
            SELECT e.*, m.title, m.duration_minutes, m.category, m.status as module_status
            FROM lms_enrollments e
            JOIN elearning_modules m ON m.id = e.elearning_module_id
            WHERE e.employee_id = ?
            ORDER BY e.status, e.due_date
        """, (emp_id,)).fetchall()
    finally:
        conn.close()

    rows = ""
    for e in enrollments:
        badge = {'not_started':'badge-muted','in_progress':'badge-info','completed':'badge-success','failed':'badge-danger','expired':'badge-warning'}.get(e['status'],'badge-muted')
        pct = e['progress_percent'] or 0
        rows += f"""<tr>
            <td><strong>{e['title']}</strong></td>
            <td>{e['category'] or '—'}</td>
            <td><div class="progress-bar"><div class="progress-fill" style="width:{pct}%"></div></div><small>{pct}%</small></td>
            <td><span class="badge {badge}">{e['status'].replace('_',' ').title()}</span></td>
            <td>{_deadline_html(e['due_date'] if 'due_date' in e.keys() else None)}</td>
            <td><a href="{BASE_PATH}/lms/course/{e['elearning_module_id']}" class="btn btn-sm btn-primary">Openen</a></td>
        </tr>"""

    body = f"""<h2>Alle Toegewezen Trainingen</h2>
    <table><tr><th>Cursus</th><th>Categorie</th><th>Voortgang</th><th>Status</th><th>Deadline</th><th>Actie</th></tr>
    {rows or '<tr><td colspan="6" style="text-align:center;color:var(--text-muted)">Geen trainingen</td></tr>'}
    </table>"""
    return _page('Mijn Trainingen', body, 'courses')


@lms_bp.route('/my-certificates')
def my_certificates():
    emp_id = _current_employee_id()
    conn = get_db()
    try:
        certs = conn.execute("""
            SELECT c.*, m.title
            FROM trn_certificates c
            JOIN elearning_modules m ON m.id = c.module_id
            WHERE c.employee_id = ?
            ORDER BY c.id DESC
        """, (emp_id,)).fetchall()
    finally:
        conn.close()

    rows = ""
    for c in certs:
        valid_badge = ''
        if c['valid_until'] and c['valid_until'] not in ('None', '', 'null'):
            try:
                vdate = datetime.strptime(c['valid_until'], '%Y-%m-%d').date()
                if vdate < date.today():
                    valid_badge = '<span style="font-size:.7rem;color:#EF4444;font-weight:600">Verlopen</span>'
                elif vdate < date.today() + timedelta(days=30):
                    valid_badge = f'<span style="font-size:.7rem;color:#F59E0B;font-weight:600">Geldig t/m {c["valid_until"]}</span>'
                else:
                    valid_badge = f'<span style="font-size:.7rem;color:#065F46;font-weight:600">Geldig t/m {c["valid_until"]}</span>'
            except:
                pass
        rows += f"""<tr>
            <td><strong>{c['title']}</strong><br>{valid_badge}</td>
            <td>{c['quiz_score']}%</td>
            <td><span class="badge {'badge-success' if c['passed'] else 'badge-danger'}">{'✅ Behaald' if c['passed'] else '❌ Niet behaald'}</span></td>
            <td><code style="font-size:.8rem">{c['certificate_ref'] or '—'}</code></td>
            <td><a href="{BASE_PATH}/lms/certificate/{c['id']}" class="btn btn-sm btn-primary">📄 Bekijk</a></td>
        </tr>"""

    body = f"""<h2>🏆 Mijn Certificaten</h2>
    <table><tr><th>Training</th><th>Score</th><th>Status</th><th>Referentie</th><th></th></tr>
    {rows or '<tr><td colspan="5" style="text-align:center;color:var(--text-muted)">Nog geen certificaten behaald. Voltooi een training om een certificaat te ontvangen.</td></tr>'}
    </table>"""
    return _page('Certificaten', body, 'certs')


@lms_bp.route('/certificate/<int:cert_id>')
def certificate_view(cert_id):
    emp_id = _current_employee_id()
    conn = get_db()
    try:
        c = conn.execute("""
            SELECT c.*, m.title, m.category, e.first_name, e.last_name
            FROM trn_certificates c
            JOIN elearning_modules m ON m.id = c.module_id
            JOIN employees e ON e.id = c.employee_id
            WHERE c.id = ? AND c.employee_id = ?
        """, (cert_id, emp_id)).fetchone()
    finally:
        conn.close()
    if not c:
        return _page('Certificaat', '<p>Certificaat niet gevonden.</p>')

    body = f"""
    <div style="max-width:700px;margin:20px auto;padding:40px;background:#fff;border:3px solid #003366;border-radius:12px;text-align:center;box-shadow:0 4px 20px rgba(0,51,102,.15)">
        <div style="font-size:.8rem;text-transform:uppercase;letter-spacing:3px;color:var(--text-muted);margin-bottom:8px">JvG HSEQ Academy</div>
        <div style="font-size:.7rem;color:var(--text-muted);margin-bottom:24px">Certificaat van Voltooiing</div>
        <h1 style="font-size:1.6rem;color:#003366;border-bottom:2px solid #003366;padding-bottom:12px;margin-bottom:24px">🏆 {c['title']}</h1>
        <p style="font-size:1.1rem;margin-bottom:8px">Dit certificaat wordt uitgereikt aan</p>
        <p style="font-size:1.5rem;font-weight:700;color:#003366;margin-bottom:24px">{c['first_name']} {c['last_name']}</p>
        <div style="display:flex;justify-content:center;gap:40px;margin-bottom:24px">
            <div><div style="font-size:.75rem;color:var(--text-muted)">Score</div><div style="font-size:1.3rem;font-weight:700">{c['quiz_score']}%</div></div>
            <div><div style="font-size:.75rem;color:var(--text-muted)">Status</div><div style="font-size:1.3rem;font-weight:700;color:#00A859">Behaald ✅</div></div>
            <div><div style="font-size:.75rem;color:var(--text-muted)">Geldig tot</div><div style="font-size:1.3rem;font-weight:700">{c['valid_until'] or 'Onbeperkt'}</div></div>
        </div>
        <div style="font-size:.8rem;color:var(--text-muted);border-top:1px solid var(--border);padding-top:12px">
            Referentie: <code>{c['certificate_ref']}</code> | Uitgegeven: {c['issued_at']}
        </div>
    </div>
    <div style="text-align:center;margin-top:16px">
        <button class="btn btn-primary" onclick="window.print()">🖨️ Afdrukken</button>
        <a href="{BASE_PATH}/lms/my-certificates" class="btn btn-outline">← Terug</a>
    </div>"""
    return _page('Certificaat', body, 'certs')


# ═══════════════════════════════════════════════════════════════════════════════
# COURSE PLAYER
# ═══════════════════════════════════════════════════════════════════════════════

@lms_bp.route('/course/<int:module_id>')
def course_player(module_id):
    emp_id = _current_employee_id()
    conn = get_db()
    try:
        module = conn.execute("SELECT * FROM elearning_modules WHERE id=?", (module_id,)).fetchone()
        if not module:
            return _page('Fout', '<p>Cursus niet gevonden.</p>', 'courses')
        content = conn.execute("SELECT * FROM lms_course_content WHERE elearning_module_id=? ORDER BY display_order", (module_id,)).fetchall()
        enrollment = conn.execute("SELECT * FROM lms_enrollments WHERE employee_id=? AND elearning_module_id=?", (emp_id, module_id)).fetchone()

        # Auto-create enrollment if missing
        if not enrollment:
            conn.execute("INSERT OR IGNORE INTO lms_enrollments (employee_id, elearning_module_id, status) VALUES (?,?, 'not_started')", (emp_id, module_id))
            conn.commit()
            enrollment = conn.execute("SELECT * FROM lms_enrollments WHERE employee_id=? AND elearning_module_id=?", (emp_id, module_id)).fetchone()

        # Mark as in_progress
        if enrollment and enrollment['status'] == 'not_started':
            conn.execute("UPDATE lms_enrollments SET status='in_progress', started_at=datetime('now'), last_accessed_at=datetime('now') WHERE id=?", (enrollment['id'],))
            conn.commit()

        # Update last accessed
        if enrollment:
            conn.execute("UPDATE lms_enrollments SET last_accessed_at=datetime('now') WHERE id=?", (enrollment['id'],))
            conn.commit()
    finally:
        conn.close()

    # Build content tabs
    content_tabs = ""
    iframe_src = ""
    for i, c in enumerate(content):
        active = 'btn-primary' if i == 0 else 'btn-sm'
        fname = c['file_name'] or os.path.basename(c['file_path'])
        content_tabs += f'<a href="#" class="btn {active} content-tab" data-src="{BASE_PATH}/lms/serve-content/{c["id"]}">{fname}</a>\n'
        if i == 0:
            iframe_src = f"{BASE_PATH}/lms/serve-content/{c['id']}"

    # If no linked content, check if module has content_html
    if not content and module['content_html']:
        iframe_src = f"{BASE_PATH}/lms/serve-content-inline/{module_id}"
        content_tabs = '<span class="badge badge-info">Inline content</span>'

    pct = enrollment['progress_percent'] or 0 if enrollment else 0
    quiz_url = f"{BASE_PATH}/lms/course/{module_id}/quiz"
    complete_url = f"{BASE_PATH}/lms/course/{module_id}/complete"

    body = f"""
    <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">
        <h2>{module['title']}</h2>
        <span class="badge badge-info">{module['duration_minutes'] or 0} min</span>
    </div>
    <div class="progress-bar" style="margin-bottom:12px"><div class="progress-fill" style="width:{pct}%"></div></div>
    <div style="margin-bottom:12px">{content_tabs}</div>
    <div class="iframe-wrap"><iframe id="courseFrame" src="{iframe_src}"></iframe></div>
    <div style="display:flex;gap:8px;margin-top:16px;justify-content:flex-end">
        <a href="{quiz_url}" class="btn btn-warning">📝 Quiz Starten</a>
        <form method="POST" action="{complete_url}" style="display:inline"><button class="btn btn-success" type="submit">✅ Afronden</button></form>
    </div>
    <script>
    document.querySelectorAll('.content-tab').forEach(function(tab){{
        tab.addEventListener('click',function(e){{
            e.preventDefault();
            document.getElementById('courseFrame').src=this.dataset.src;
            document.querySelectorAll('.content-tab').forEach(function(t){{t.classList.remove('btn-primary');t.classList.add('btn-sm')}});
            this.classList.add('btn-primary');
        }});
    }});
    // PostMessage listener for quiz integration (SST §9)
    window.addEventListener('message', function(event) {{
        if (event.data && event.data.type === 'lms_quiz_complete') {{
            fetch('{BASE_PATH}/api/lms/score', {{
                method: 'POST',
                headers: {{'Content-Type': 'application/json'}},
                body: JSON.stringify({{
                    employee_id: {emp_id},
                    module_id: event.data.data.module_id || {module_id},
                    answers: event.data.data.answers || {{}},
                    score: event.data.data.score,
                    total_questions: event.data.data.total_questions,
                    correct_answers: event.data.data.correct_answers,
                    time_spent: event.data.data.time_spent || 0
                }})
            }}).then(function(r){{return r.json()}}).then(function(result){{
                if(result.success){{ location.href='{BASE_PATH}/lms/'; }}
                else{{ alert('Fout bij opslaan quiz-resultaat: '+result.error); }}
            }});
        }}
    }});
    </script>"""
    return _page(module['title'], body, 'courses')


@lms_bp.route('/serve-content/<int:content_id>')
def serve_content(content_id):
    """Serve linked HTML content file."""
    conn = get_db()
    try:
        c = conn.execute("SELECT * FROM lms_course_content WHERE id=?", (content_id,)).fetchone()
    finally:
        conn.close()
    if not c:
        return "<p>Content niet gevonden.</p>", 404
    fpath = c['file_path']
    if os.path.exists(fpath):
        with open(fpath, 'r', encoding='utf-8') as f:
            return f.read()
    return f"<p>Bestand niet gevonden op server: {fpath}</p>", 404


@lms_bp.route('/serve-content-inline/<int:module_id>')
def serve_content_inline(module_id):
    """Serve inline content_html from elearning_modules."""
    conn = get_db()
    try:
        m = conn.execute("SELECT content_html FROM elearning_modules WHERE id=?", (module_id,)).fetchone()
    finally:
        conn.close()
    if m and m['content_html']:
        return m['content_html']
    return "<p>Geen content beschikbaar.</p>", 404


@lms_bp.route('/course/<int:module_id>/start', methods=['POST'])
def course_start(module_id):
    emp_id = _current_employee_id()
    conn = get_db()
    try:
        conn.execute("""UPDATE lms_enrollments SET status='in_progress', started_at=datetime('now'), last_accessed_at=datetime('now')
                        WHERE employee_id=? AND elearning_module_id=?""", (emp_id, module_id))
        conn.commit()
    finally:
        conn.close()
    return redirect(f"{BASE_PATH}/lms/course/{module_id}")


@lms_bp.route('/course/<int:module_id>/progress', methods=['POST'])
def course_progress(module_id):
    emp_id = _current_employee_id()
    data = request.get_json(silent=True) or {}
    pct = data.get('progress_percent', 0)
    ts = data.get('time_spent_seconds', 0)
    conn = get_db()
    try:
        conn.execute("""UPDATE lms_enrollments SET progress_percent=?, time_spent_seconds=time_spent_seconds+?, last_accessed_at=datetime('now')
                        WHERE employee_id=? AND elearning_module_id=?""", (pct, ts, emp_id, module_id))
        conn.commit()
    finally:
        conn.close()
    return jsonify(success=True)


@lms_bp.route('/course/<int:module_id>/complete', methods=['POST'])
def course_complete(module_id):
    emp_id = _current_employee_id()
    conn = get_db()
    try:
        # Check if there are quiz questions for this module
        module = conn.execute("SELECT quiz_questions, passing_score FROM elearning_modules WHERE id=?", (module_id,)).fetchone()
        has_quiz = False
        if module and module['quiz_questions']:
            try:
                questions = json.loads(module['quiz_questions'])
                has_quiz = len(questions) > 0
            except:
                pass
        # Also check if there's a linked quiz in lms_course_content
        if not has_quiz:
            quiz_content = conn.execute("SELECT id FROM lms_course_content WHERE elearning_module_id=? AND (file_name LIKE '%quiz%' OR content_type='quiz')", (module_id,)).fetchone()
            has_quiz = bool(quiz_content)

        if has_quiz:
            # Has quiz — user clicked complete, mark as completed (quiz was done via iframe)
            conn.execute("""UPDATE lms_enrollments SET progress_percent=100, final_score=100, final_passed=1,
                            status='completed', completed_at=datetime('now'), last_accessed_at=datetime('now')
                            WHERE employee_id=? AND elearning_module_id=? AND status IN ('in_progress','not_started')""", (emp_id, module_id))
            # Generate certificate
            enrollment = conn.execute("SELECT id FROM lms_enrollments WHERE employee_id=? AND elearning_module_id=?", (emp_id, module_id)).fetchone()
            if enrollment:
                existing_cert = conn.execute("SELECT id FROM trn_certificates WHERE employee_id=? AND module_id=?", (emp_id, module_id)).fetchone()
                if not existing_cert:
                    cert_ref = f"JvG-LMS-{module_id:03d}-{emp_id:04d}-{uuid.uuid4().hex[:6].upper()}"
                    conn.execute("""INSERT INTO trn_certificates (employee_id, module_id, quiz_score, passed, certificate_ref)
                                    VALUES (?,?,100,1,?)""", (emp_id, module_id, cert_ref))
        else:
            # No quiz — mark as completed with full score
            conn.execute("""UPDATE lms_enrollments SET progress_percent=100, final_score=100, final_passed=1, 
                            status='completed', completed_at=datetime('now'), last_accessed_at=datetime('now')
                            WHERE employee_id=? AND elearning_module_id=? AND status IN ('in_progress','not_started')""", (emp_id, module_id))
            # Generate certificate
            enrollment = conn.execute("SELECT id FROM lms_enrollments WHERE employee_id=? AND elearning_module_id=?", (emp_id, module_id)).fetchone()
            if enrollment:
                existing_cert = conn.execute("SELECT id FROM trn_certificates WHERE employee_id=? AND module_id=?", (emp_id, module_id)).fetchone()
                if not existing_cert:
                    cert_ref = f"JvG-LMS-{module_id:03d}-{emp_id:04d}-{uuid.uuid4().hex[:6].upper()}"
                    conn.execute("""INSERT INTO trn_certificates (employee_id, module_id, quiz_score, passed, certificate_ref)
                                    VALUES (?,?,100,1,?)""", (emp_id, module_id, cert_ref))
        conn.commit()
    finally:
        conn.close()
    return redirect(f"{BASE_PATH}/lms/course/{module_id}")


# ═══════════════════════════════════════════════════════════════════════════════
# QUIZ ENGINE
# ═══════════════════════════════════════════════════════════════════════════════

@lms_bp.route('/course/<int:module_id>/quiz')
def quiz_view(module_id):
    emp_id = _current_employee_id()
    conn = get_db()
    try:
        module = conn.execute("SELECT * FROM elearning_modules WHERE id=?", (module_id,)).fetchone()
        enrollment = conn.execute("SELECT * FROM lms_enrollments WHERE employee_id=? AND elearning_module_id=?", (emp_id, module_id)).fetchone()
    finally:
        conn.close()

    if not module:
        return _page('Fout', '<p>Module niet gevonden.</p>', 'courses')

    # Try loading quiz questions from module
    questions = []
    if module['quiz_questions']:
        try:
            questions = json.loads(module['quiz_questions'])
        except (json.JSONDecodeError, TypeError):
            pass

    # Check if there's a linked quiz HTML file
    conn = get_db()
    try:
        quiz_content = conn.execute("SELECT * FROM lms_course_content WHERE elearning_module_id=? AND file_name LIKE '%quiz%'", (module_id,)).fetchone()
    finally:
        conn.close()

    if quiz_content and os.path.exists(quiz_content['file_path']):
        # Serve external quiz HTML in iframe
        quiz_src = f"{BASE_PATH}/lms/serve-content/{quiz_content['id']}"
        body = f"""
        <h2>Quiz: {module['title']}</h2>
        <div class="iframe-wrap"><iframe id="quizFrame" src="{quiz_src}" style="width:100%;height:600px;border:none;"></iframe></div>
        <p style="margin-top:12px;color:var(--text-muted);font-size:.85rem">De quiz wordt automatisch nagekeken. Resultaat wordt opgeslagen na afronding.</p>
        <script>
        window.addEventListener('message', function(event) {{
            if (event.data && event.data.type === 'lms_quiz_complete') {{
                fetch('{BASE_PATH}/api/lms/score', {{
                    method: 'POST',
                    headers: {{'Content-Type': 'application/json'}},
                    body: JSON.stringify({{
                        employee_id: {emp_id},
                        module_id: event.data.data.module_id || {module_id},
                        answers: event.data.data.answers || {{}},
                        score: event.data.data.score,
                        total_questions: event.data.data.total_questions,
                        correct_answers: event.data.data.correct_answers,
                        time_spent: event.data.data.time_spent || 0
                    }})
                }}).then(function(r){{return r.json()}}).then(function(result){{
                    if(result.success){{
                        document.getElementById('quizFrame').parentElement.innerHTML='<div class="card" style="text-align:center;padding:40px"><h2>'+result.score+'%</h2><p>'+(result.passed?'✅ Gehaald!':'❌ Niet gehaald')+'</p><a href="{BASE_PATH}/lms/" class="btn btn-primary">Terug naar Dashboard</a></div>';
                    }}
                }});
            }}
        }});
        </script>"""
        return _page(f'Quiz: {module["title"]}', body, 'courses')

    # Built-in quiz rendering from quiz_questions JSON
    if not questions:
        body = f"""<h2>Quiz: {module['title']}</h2>
        <div class="card" style="text-align:center;padding:40px">
            <p>Geen quiz beschikbaar voor deze module.</p>
            <a href="{BASE_PATH}/lms/course/{module_id}" class="btn btn-primary">Terug naar cursus</a>
        </div>"""
        return _page(f'Quiz: {module["title"]}', body, 'courses')

    # Render questions
    q_html = ""
    for i, q in enumerate(questions):
        opts = ""
        for j, opt in enumerate(q.get('options', [])):
            letter = chr(65 + j)
            opts += f'<label style="display:block;padding:8px 12px;margin:4px 0;border-radius:6px;cursor:pointer;border:1px solid var(--border)" class="quiz-opt" data-q="{i}" data-a="{letter}"><input type="radio" name="q{i}" value="{letter}" style="margin-right:8px">{letter}. {opt}</label>'
        q_html += f'<div class="card" style="margin-bottom:16px"><p style="font-weight:600;margin-bottom:12px">{i+1}. {q.get("question","")}</p>{opts}</div>'

    body = f"""
    <h2>Quiz: {module['title']}</h2>
    <form id="quizForm">
        {q_html}
        <div style="text-align:center;margin-top:20px">
            <button type="submit" class="btn btn-success">📋 Inleveren</button>
        </div>
    </form>
    <div id="quizResult" style="display:none"></div>
    <script>
    document.getElementById('quizForm').addEventListener('submit', function(e){{
        e.preventDefault();
        var answers={{}};
        document.querySelectorAll('input[type=radio]:checked').forEach(function(inp){{
            var qIdx=inp.name.replace('q','');
            answers[parseInt(qIdx)+1]=inp.value;
        }});
        fetch('{BASE_PATH}/lms/course/{module_id}/quiz/submit', {{
            method:'POST',
            headers:{{'Content-Type':'application/json'}},
            body:JSON.stringify({{answers:answers}})
        }}).then(function(r){{return r.json()}}).then(function(res){{
            document.getElementById('quizForm').style.display='none';
            var rd=document.getElementById('quizResult');
            rd.style.display='block';
            rd.innerHTML='<div class="card" style="text-align:center;padding:40px"><h2>'+res.score+'%</h2><p>'+res.score+'/'+res.total_questions+' correct</p><p>'+(res.passed?'✅ Gehaald!':'❌ Niet gehaald — minimum '+res.passing_score+'%')+'</p><a href="{BASE_PATH}/lms/" class="btn btn-primary">Terug naar Dashboard</a></div>';
        }});
    }});
    </script>"""
    return _page(f'Quiz: {module["title"]}', body, 'courses')


@lms_bp.route('/course/<int:module_id>/quiz/submit', methods=['POST'])
def quiz_submit(module_id):
    """Internal quiz submission — scores against quiz_questions JSON."""
    emp_id = _current_employee_id()
    data = request.get_json(silent=True) or {}
    answers = data.get('answers', {})

    conn = get_db()
    try:
        module = conn.execute("SELECT * FROM elearning_modules WHERE id=?", (module_id,)).fetchone()
        if not module:
            return jsonify(success=False, error="Module niet gevonden"), 404

        questions = []
        if module['quiz_questions']:
            try:
                questions = json.loads(module['quiz_questions'])
            except (json.JSONDecodeError, TypeError):
                pass

        correct = 0
        total = len(questions)
        for i, q in enumerate(questions):
            user_ans = answers.get(str(i + 1), '')
            if user_ans.upper() == q.get('correct', '').upper():
                correct += 1

        score = int((correct / total) * 100) if total > 0 else 0
        passing_score = module['passing_score'] or 70
        passed = 1 if score >= passing_score else 0

        # Get or create enrollment
        enrollment = conn.execute("SELECT * FROM lms_enrollments WHERE employee_id=? AND elearning_module_id=?", (emp_id, module_id)).fetchone()
        if not enrollment:
            conn.execute("INSERT OR IGNORE INTO lms_enrollments (employee_id, elearning_module_id, status) VALUES (?,?, 'in_progress')", (emp_id, module_id))
            conn.commit()
            enrollment = conn.execute("SELECT * FROM lms_enrollments WHERE employee_id=? AND elearning_module_id=?", (emp_id, module_id)).fetchone()

        # Determine attempt number
        attempt = conn.execute("SELECT MAX(attempt_number) as m FROM lms_quiz_results WHERE enrollment_id=?", (enrollment['id'],)).fetchone()
        attempt_num = (attempt['m'] or 0) + 1

        # Insert quiz result
        conn.execute("""INSERT INTO lms_quiz_results (enrollment_id, attempt_number, answers_json, total_questions, correct_answers, score, passed, submitted_at)
                        VALUES (?,?,?,?,?,?,?,datetime('now'))""",
                     (enrollment['id'], attempt_num, json.dumps(answers), total, correct, score, passed))

        # Update enrollment
        new_status = 'completed' if passed else 'failed'
        conn.execute("""UPDATE lms_enrollments SET progress_percent=100, final_score=?, final_passed=?, completed_at=datetime('now'), status=?, last_accessed_at=datetime('now')
                        WHERE id=?""", (score, passed, new_status, enrollment['id']))

        # Generate certificate if passed
        cert_ref = None
        if passed:
            cert_ref = f"JvG-LMS-{module_id:03d}-{emp_id:04d}-{uuid.uuid4().hex[:6].upper()}"
            conn.execute("""INSERT INTO trn_certificates (employee_id, module_id, quiz_score, passed, certificate_ref)
                            VALUES (?,?,?,?,?)""", (emp_id, module_id, score, 1, cert_ref))

            # Update certifications table if training_program linked
            compliance_rule = conn.execute("SELECT training_program_id FROM lms_compliance_rules WHERE elearning_module_id=?", (module_id,)).fetchone()
            if compliance_rule and compliance_rule['training_program_id']:
                tp_id = compliance_rule['training_program_id']
                # Get valid_period from training_programs
                tp = conn.execute("SELECT valid_period_days FROM training_programs WHERE id=?", (tp_id,)).fetchone()
                vdays = tp['valid_period_days'] if tp else 365
                expiry = str(date.today() + timedelta(days=vdays))
                existing = conn.execute("SELECT id FROM certifications WHERE employee_id=? AND training_program_id=?", (emp_id, tp_id)).fetchone()
                if existing:
                    conn.execute("UPDATE certifications SET expiry_date=?, status='active', score=?, updated_at=datetime('now') WHERE id=?",
                                 (expiry, score, existing['id']))
                else:
                    conn.execute("INSERT INTO certifications (employee_id, training_program_id, expiry_date, status, score) VALUES (?,?,?,?,?)",
                                 (emp_id, tp_id, expiry, 'active', score))

        conn.commit()
    finally:
        conn.close()

    return jsonify(success=True, score=score, total_questions=total, correct_answers=correct,
                   passed=bool(passed), passing_score=passing_score, certificate_ref=cert_ref)


# ═══════════════════════════════════════════════════════════════════════════════
# EXTERNAL SCORE API (for existing HTML quiz files)
# ═══════════════════════════════════════════════════════════════════════════════

@lms_bp.route('/api/score', methods=['POST'])
def api_score():
    """External score endpoint — called by existing HTML quiz files via fetch/XHR."""
    data = request.get_json(silent=True) or {}
    emp_id = data.get('employee_id', _current_employee_id())
    module_id = data.get('module_id')
    score = data.get('score', 0)
    total_q = data.get('total_questions', 0)
    correct = data.get('correct_answers', 0)
    answers = data.get('answers', {})
    time_spent = data.get('time_spent', 0)

    if not module_id:
        return jsonify(success=False, error="module_id verplicht"), 400

    conn = get_db()
    try:
        module = conn.execute("SELECT id, passing_score FROM elearning_modules WHERE id=?", (module_id,)).fetchone()
        if not module:
            return jsonify(success=False, error="Module niet gevonden"), 404

        passing_score = module['passing_score'] or 70
        passed = 1 if score >= passing_score else 0

        # Get or create enrollment
        conn.execute("INSERT OR IGNORE INTO lms_enrollments (employee_id, elearning_module_id, status) VALUES (?,?, 'in_progress')", (emp_id, module_id))
        conn.commit()
        enrollment = conn.execute("SELECT * FROM lms_enrollments WHERE employee_id=? AND elearning_module_id=?", (emp_id, module_id)).fetchone()

        # Attempt number
        attempt = conn.execute("SELECT MAX(attempt_number) as m FROM lms_quiz_results WHERE enrollment_id=?", (enrollment['id'],)).fetchone()
        attempt_num = (attempt['m'] or 0) + 1

        # Insert quiz result
        conn.execute("""INSERT INTO lms_quiz_results (enrollment_id, attempt_number, answers_json, total_questions, correct_answers, score, passed, time_spent_seconds, submitted_at)
                        VALUES (?,?,?,?,?,?,?,?,datetime('now'))""",
                     (enrollment['id'], attempt_num, json.dumps(answers), total_q, correct, score, passed, time_spent))

        # Update enrollment
        new_status = 'completed' if passed else 'failed'
        conn.execute("""UPDATE lms_enrollments SET progress_percent=100, final_score=?, final_passed=?, completed_at=datetime('now'), status=?, time_spent_seconds=time_spent_seconds+?, last_accessed_at=datetime('now')
                        WHERE id=?""", (score, passed, new_status, time_spent, enrollment['id']))

        # Certificate
        cert_ref = None
        if passed:
            cert_ref = f"JvG-LMS-{module_id:03d}-{emp_id:04d}-{uuid.uuid4().hex[:6].upper()}"
            conn.execute("""INSERT INTO trn_certificates (employee_id, module_id, quiz_score, passed, certificate_ref)
                            VALUES (?,?,?,?,?)""", (emp_id, module_id, score, 1, cert_ref))

            # Compliance link
            cr = conn.execute("SELECT training_program_id FROM lms_compliance_rules WHERE elearning_module_id=?", (module_id,)).fetchone()
            if cr and cr['training_program_id']:
                tp_id = cr['training_program_id']
                tp = conn.execute("SELECT valid_period_days FROM training_programs WHERE id=?", (tp_id,)).fetchone()
                vdays = tp['valid_period_days'] if tp else 365
                expiry = str(date.today() + timedelta(days=vdays))
                existing = conn.execute("SELECT id FROM certifications WHERE employee_id=? AND training_program_id=?", (emp_id, tp_id)).fetchone()
                if existing:
                    conn.execute("UPDATE certifications SET expiry_date=?, status='active', score=? WHERE id=?", (expiry, score, existing['id']))
                else:
                    conn.execute("INSERT INTO certifications (employee_id, training_program_id, expiry_date, status, score) VALUES (?,?,?,?,?)",
                                 (emp_id, tp_id, expiry, 'active', score))

        conn.commit()
    finally:
        conn.close()

    return jsonify(success=True, score=score, passed=bool(passed), certificate_ref=cert_ref)


# ═══════════════════════════════════════════════════════════════════════════════
# JSON API ENDPOINTS
# ═══════════════════════════════════════════════════════════════════════════════

@lms_bp.route('/api/modules')
def api_modules():
    conn = get_db()
    try:
        rows = conn.execute("SELECT * FROM elearning_modules WHERE status='published' ORDER BY id").fetchall()
    finally:
        conn.close()
    return jsonify([dict(r) for r in rows])


@lms_bp.route('/api/modules/<int:module_id>')
def api_module_detail(module_id):
    conn = get_db()
    try:
        m = conn.execute("SELECT * FROM elearning_modules WHERE id=?", (module_id,)).fetchone()
        if not m:
            return jsonify(error="Not found"), 404
        content = conn.execute("SELECT * FROM lms_course_content WHERE elearning_module_id=?", (module_id,)).fetchall()
    finally:
        conn.close()
    result = dict(m)
    result['content_files'] = [dict(c) for c in content]
    return jsonify(result)


@lms_bp.route('/api/enrollments/<int:employee_id>')
def api_enrollments(employee_id):
    conn = get_db()
    try:
        rows = conn.execute("""
            SELECT e.*, m.title, m.category
            FROM lms_enrollments e
            JOIN elearning_modules m ON m.id = e.elearning_module_id
            WHERE e.employee_id=?
            ORDER BY e.status
        """, (employee_id,)).fetchall()
    finally:
        conn.close()
    return jsonify([dict(r) for r in rows])


@lms_bp.route('/api/compliance/summary')
def api_compliance_summary():
    conn = get_db()
    try:
        employees = conn.execute("SELECT id, first_name, last_name, role_id FROM employees WHERE status='active'").fetchall()
        total = len(employees)
        compliant = 0
        for emp in employees:
            rules = conn.execute("""
                SELECT cr.elearning_module_id, cr.valid_period_days, cr.is_mandatory
                FROM lms_compliance_rules cr WHERE cr.is_mandatory=1
            """).fetchall()
            if not rules:
                compliant += 1
                continue
            all_ok = True
            for rule in rules:
                enr = conn.execute("""SELECT final_passed, completed_at FROM lms_enrollments
                                      WHERE employee_id=? AND elearning_module_id=? ORDER BY completed_at DESC LIMIT 1""",
                                   (emp['id'], rule['elearning_module_id'])).fetchone()
                if not enr or not enr['final_passed']:
                    all_ok = False
                    break
                expiry = datetime.strptime(enr['completed_at'], '%Y-%m-%d %H:%M:%S') + timedelta(days=rule['valid_period_days'])
                if expiry.date() < date.today():
                    all_ok = False
                    break
            if all_ok:
                compliant += 1
    finally:
        conn.close()
    pct = int((compliant / total) * 100) if total > 0 else 0
    return jsonify(total_employees=total, compliant=compliant, non_compliant=total - compliant, compliance_pct=pct)


@lms_bp.route('/api/certificates/<int:employee_id>')
def api_certificates(employee_id):
    conn = get_db()
    try:
        rows = conn.execute("""
            SELECT c.*, m.title FROM trn_certificates c
            JOIN elearning_modules m ON m.id = c.module_id
            WHERE c.employee_id=?
        """, (employee_id,)).fetchall()
    finally:
        conn.close()
    return jsonify([dict(r) for r in rows])


# ═══════════════════════════════════════════════════════════════════════════════
# ADMIN PORTAL — COURSES
# ═══════════════════════════════════════════════════════════════════════════════

@lms_bp.route('/admin/courses')
def admin_courses():
    # Scan projects for deliverables
    import os
    projects_dir = '/root/projects/jg'
    projects = []
    if os.path.isdir(projects_dir):
        for d in sorted(os.listdir(projects_dir)):
            full = os.path.join(projects_dir, d)
            if not os.path.isdir(full) or d.startswith('.'):
                continue
            deliv_dir = os.path.join(full, 'deliverables')
            if os.path.isdir(deliv_dir):
                files = []
                for ext, label in [('.html','HTML'),('.pptx','PPTX'),('.zip','SCORM')]:
                    for root, dirs, fnames in os.walk(deliv_dir):
                        if '/archive/' in root:
                            continue
                        for f in fnames:
                            if f.endswith(ext):
                                rel = os.path.relpath(os.path.join(root, f), deliv_dir)
                                files.append({'file': rel, 'type': label, 'name': f})
                if files:
                    projects.append({'dir': d, 'files': files})
    proj_opts = ''.join(f'<option value="{p["dir"]}">{p["dir"]} ({len(p["files"])} files)</option>' for p in projects)
    proj_json = json.dumps(projects)

    conn = get_db()
    try:
        modules = conn.execute("""
            SELECT m.*, 
                (SELECT COUNT(*) FROM lms_enrollments WHERE elearning_module_id=m.id) as enroll_count,
                (SELECT ROUND(AVG(final_score)) FROM lms_enrollments WHERE elearning_module_id=m.id AND final_score IS NOT NULL) as avg_score
            FROM elearning_modules m ORDER BY m.id
        """).fetchall()
    finally:
        conn.close()

    rows = ""
    for m in modules:
        badge = {'published':'badge-success','draft':'badge-muted','archived':'badge-warning'}.get(m['status'], 'badge-muted')
        rows += f"""<tr>
            <td>{m['id']}</td>
            <td><strong>{m['title']}</strong></td>
            <td>{m['category'] or '—'}</td>
            <td><span class="badge {badge}">{m['status']}</span></td>
            <td>{m['enroll_count']}</td>
            <td>{m['avg_score'] or '—'}%</td>
            <td>{m['passing_score'] or 70}%</td>
            <td>
                <a href="{BASE_PATH}/lms/admin/courses/{m['id']}/content" class="btn btn-sm btn-primary">📎 Content</a>
                <form method="POST" action="{BASE_PATH}/lms/admin/courses/{m['id']}/publish" style="display:inline"><button class="btn btn-sm btn-success" type="submit">📢 Publiceren</button></form>
                <form method="POST" action="{BASE_PATH}/lms/admin/courses/{m['id']}/delete" style="display:inline" onsubmit="return confirm('Weet je zeker dat je deze cursus wilt verwijderen? Alle inschrijvingen en quiz-resultaten worden ook verwijderd.')"><button class="btn btn-sm btn-danger" type="submit">🗑️ Verwijder</button></form>
            </td>
        </tr>"""

    body = f"""
    <h2>Cursusbeheer</h2>
    <details style="margin-bottom:20px" id="new-course-form"><summary style="cursor:pointer;font-weight:600;color:var(--primary);margin-bottom:12px">➕ Nieuwe Cursus Toevoegen</summary>
    <div class="card" style="padding:16px">
        <form method="POST" action="{BASE_PATH}/lms/admin/courses/new" id="course-form">
            <div style="margin-bottom:12px;padding:12px;background:#f0f9ff;border-radius:8px;border:1px solid #bae6fd">
                <div style="font-size:.8rem;font-weight:600;color:#0369a1;margin-bottom:8px">📂 Stap 1: Kies een bestaand project (optioneel)</div>
                <select id="project-select" onchange="loadDeliverables(this.value)" style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px;margin-bottom:8px">
                    <option value="">— Handmatig invoeren —</option>
                    {proj_opts}
                </select>
                <div id="deliverables-area" style="display:none">
                    <div style="font-size:.75rem;color:var(--text-muted);margin-bottom:4px">Beschikbare deliverables:</div>
                    <div id="deliverables-list" style="max-height:200px;overflow-y:auto;border:1px solid var(--border);border-radius:6px;padding:8px;background:#fff"></div>
                </div>
            </div>
            <div style="display:grid;grid-template-columns:1fr 1fr 1fr auto;gap:12px;align-items:end">
                <div><label style="font-size:.75rem;color:var(--text-muted)">Titel *</label><input type="text" name="title" id="course-title" required placeholder="bijv. Veilig Werken op Hoogte" style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px"></div>
                <div><label style="font-size:.75rem;color:var(--text-muted)">Categorie *</label>
                    <select name="category" required style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px">
                        <option value="Veiligheid">Veiligheid</option>
                        <option value="Milieu">Milieu</option>
                        <option value="Kwaliteit">Kwaliteit</option>
                        <option value="Procesveiligheid">Procesveiligheid</option>
                        <option value="BHV">BHV</option>
                        <option value="NEN">NEN</option>
                        <option value="ARBO">ARBO</option>
                        <option value="Overig">Overig</option>
                    </select>
                </div>
                <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px">
                    <div><label style="font-size:.75rem;color:var(--text-muted)">Duur (min)</label><input type="number" name="duration" value="30" min="5" style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px"></div>
                    <div><label style="font-size:.75rem;color:var(--text-muted)">Slagings%</label><input type="number" name="passing_score" value="70" min="1" max="100" style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px"></div>
                </div>
                <button class="btn btn-success" type="submit">➕ Aanmaken</button>
            </div>
            <input type="hidden" name="content_path" id="content-path" value="">
        </form>
    </div>
    </details>
    <table><tr><th>ID</th><th>Titel</th><th>Categorie</th><th>Status</th><th>Inschrijvingen</th><th>Gem. Score</th><th>Slagings%</th><th>Acties</th></tr>
    {rows or '<tr><td colspan="8" style="text-align:center;color:var(--text-muted)">Geen cursussen</td></tr>'}
    </table>
    <script>
    const PROJECTS = {proj_json};
    function loadDeliverables(projDir) {{
        const area = document.getElementById('deliverables-area');
        const list = document.getElementById('deliverables-list');
        const titleInput = document.getElementById('course-title');
        if (!projDir) {{ area.style.display='none'; return; }}
        const proj = PROJECTS.find(p => p.dir === projDir);
        if (!proj || !proj.files.length) {{ area.style.display='none'; return; }}
        area.style.display='block';
        list.innerHTML = proj.files.map(f =>
            '<label style="display:flex;align-items:center;gap:6px;padding:4px 0;cursor:pointer;font-size:.8rem">' +
            '<input type="radio" name="deliv-pick" value="' + f.file + '" onchange="pickDeliverable(\'' + projDir + '\',\'' + f.file + '\')">' +
            '<span style="display:inline-block;padding:1px 6px;border-radius:3px;font-size:.65rem;font-weight:700;background:' +
            (f.type==='HTML'?'#d1fae5;color:#065f46':f.type==='PPTX'?'#dbeafe;color:#1e40af':'#fef3c7;color:#92400e') + '">' + f.type + '</span>' +
            f.name + '</label>'
        ).join('');
        if (!titleInput.value) {{
            const name = projDir.replace(/^\\d{{4}}-/, '').replace(/-/g, ' ').replace(/pbm|aimeet|consult|pgs/gi, '').trim();
            titleInput.value = name.charAt(0).toUpperCase() + name.slice(1);
        }}
    }}
    function pickDeliverable(projDir, filePath) {{
        document.getElementById('content-path').value = '/root/projects/jg/' + projDir + '/deliverables/' + filePath;
    }}
    </script>"""
    return _page('Cursusbeheer', body, 'admin-courses')


@lms_bp.route('/admin/courses/new', methods=['POST'])
def admin_course_create():
    data = request.form
    title = data.get('title', '').strip()
    category = data.get('category', '').strip()
    duration = data.get('duration', 30, type=int)
    passing_score = data.get('passing_score', 70, type=int)
    content_path = data.get('content_path', '').strip()
    if not title or not category:
        return redirect(f"{BASE_PATH}/lms/admin/courses")
    conn = get_db()
    try:
        cur = conn.execute("""INSERT INTO elearning_modules (title, category, duration_minutes, passing_score, status, created_by)
                       VALUES (?, ?, ?, ?, 'draft', 'admin')""", (title, category, duration, passing_score))
        mod_id = cur.lastrowid
        conn.commit()
        # If content_path is an HTML file, read and store
        import os
        if content_path and content_path.endswith('.html') and os.path.isfile(content_path):
            with open(content_path, 'r', encoding='utf-8') as f:
                html_content = f.read()
            conn.execute("UPDATE elearning_modules SET content_html=? WHERE id=?", (html_content, mod_id))
            conn.commit()
    finally:
        conn.close()
    return redirect(f"{BASE_PATH}/lms/admin/courses")


@lms_bp.route('/admin/courses/<int:course_id>/content')
def admin_course_content(course_id):
    # Scan projects for deliverables (same logic as course creation)
    projects_dir = '/root/projects/jg'
    projects = []
    if os.path.isdir(projects_dir):
        for d in sorted(os.listdir(projects_dir)):
            full = os.path.join(projects_dir, d)
            if not os.path.isdir(full) or d.startswith('.'):
                continue
            deliv_dir = os.path.join(full, 'deliverables')
            if os.path.isdir(deliv_dir):
                files = []
                for ext, label in [('.html','HTML'),('.pptx','PPTX'),('.zip','SCORM')]:
                    for root, dirs, fnames in os.walk(deliv_dir):
                        if '/archive/' in root:
                            continue
                        for f in fnames:
                            if f.endswith(ext):
                                rel = os.path.relpath(os.path.join(root, f), deliv_dir)
                                files.append({'file': rel, 'type': label, 'name': f})
                if files:
                    projects.append({'dir': d, 'files': files})
    proj_opts = ''.join(f'<option value="{p["dir"]}">{p["dir"]} ({len(p["files"])} files)</option>' for p in projects)
    proj_json = json.dumps(projects)

    conn = get_db()
    try:
        module = conn.execute("SELECT * FROM elearning_modules WHERE id=?", (course_id,)).fetchone()
        content = conn.execute("SELECT * FROM lms_course_content WHERE elearning_module_id=? ORDER BY display_order", (course_id,)).fetchall()
    finally:
        conn.close()

    rows = ""
    for c in content:
        ctype_badge = {'html':'badge-success','pdf':'badge-danger','video':'badge-info','scorm':'badge-warning'}.get(c['content_type'],'badge-muted')
        rows += f"""<tr>
            <td>{c['id']}</td>
            <td><span class="badge {ctype_badge}">{c['content_type'].upper()}</span></td>
            <td>{c['file_name'] or '—'}</td>
            <td><small style="color:var(--text-muted)">{c['file_path'][:60]}{'...' if len(c['file_path'] or '')>60 else ''}</small></td>
            <td>{'✅' if c['is_primary'] else '—'}</td>
            <td><form method="POST" action="{BASE_PATH}/lms/admin/courses/{course_id}/content/{c['id']}" style="display:inline" onsubmit="return confirm('Content verwijderen?')"><input type="hidden" name="_method" value="DELETE"><button class="btn btn-sm btn-danger" type="submit">🗑️</button></form></td>
        </tr>"""

    body = f"""
    <h2>📎 Content: {module['title'] if module else 'Onbekend'}</h2>
    <div class="card" style="padding:16px;margin-bottom:16px">
        <div style="font-size:.8rem;font-weight:600;color:var(--primary);margin-bottom:8px">📂 Kies een deliverable uit een bestaand project</div>
        <form method="POST" action="{BASE_PATH}/lms/admin/courses/{course_id}/content" id="content-form">
            <div style="display:grid;grid-template-columns:1fr auto;gap:8px;margin-bottom:8px">
                <select id="content-proj-select" onchange="loadContentDeliverables(this.value)" style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px">
                    <option value="">— Selecteer project —</option>
                    {proj_opts}
                </select>
                <select name="content_type" style="padding:8px;border:1px solid var(--border);border-radius:6px">
                    <option value="html">HTML</option>
                    <option value="pdf">PDF</option>
                    <option value="video">Video</option>
                    <option value="scorm">SCORM</option>
                </select>
            </div>
            <div id="content-deliverables-area" style="display:none;margin-bottom:8px">
                <div style="font-size:.75rem;color:var(--text-muted);margin-bottom:4px">Beschikbare bestanden:</div>
                <select id="content-file-select" name="file_path" style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px">
                    <option value="">— Selecteer bestand —</option>
                </select>
            </div>
            <input type="hidden" name="file_name" id="content-file-name" value="">
            <button class="btn btn-primary" type="submit">📎 Content Koppelen</button>
        </form>
    </div>
    <table><tr><th>ID</th><th>Type</th><th>Bestand</th><th>Pad</th><th>Primair</th><th></th></tr>
    {rows or '<tr><td colspan="6" style="text-align:center;color:var(--text-muted)">Geen content gekoppeld — selecteer hierboven een bestand</td></tr>'}
    </table>
    <div style="margin-top:16px">
        <a href="{BASE_PATH}/lms/admin/courses" class="btn btn-outline">← Terug naar Cursussen</a>
    </div>
    <script>
    const CPROJ = {proj_json};
    function loadContentDeliverables(projDir) {{
        const area = document.getElementById('content-deliverables-area');
        const sel = document.getElementById('content-file-select');
        const nameInput = document.getElementById('content-file-name');
        if (!projDir) {{ area.style.display='none'; return; }}
        const proj = CPROJ.find(p => p.dir === projDir);
        if (!proj || !proj.files.length) {{ area.style.display='none'; return; }}
        area.style.display='block';
        sel.innerHTML = '<option value="">— Selecteer bestand —</option>' +
            proj.files.map(f => '<option value="/root/projects/jg/' + projDir + '/deliverables/' + f.file + '">' + f.name + ' (' + f.type + ')</option>').join('');
        sel.onchange = function() {{ nameInput.value = this.options[this.selectedIndex].text.split(' (')[0]; }};
    }}
    </script>"""
    return _page(f'Content: {module["title"] if module else "?"}', body, 'admin-courses')


@lms_bp.route('/admin/courses/<int:course_id>/content', methods=['POST'])
def admin_course_content_add(course_id):
    data = request.form
    fpath = data.get('file_path', '')
    fname = data.get('file_name', '') or os.path.basename(fpath)
    ctype = data.get('content_type', 'html')
    conn = get_db()
    try:
        conn.execute("""INSERT INTO lms_course_content (elearning_module_id, content_type, file_path, file_name, is_primary)
                        VALUES (?,?,?,?, (SELECT CASE WHEN (SELECT COUNT(*) FROM lms_course_content WHERE elearning_module_id=? AND is_primary=1)=0 THEN 1 ELSE 0 END))""",
                     (course_id, ctype, fpath, fname, course_id))
        conn.commit()
    finally:
        conn.close()
    return redirect(f"{BASE_PATH}/lms/admin/courses/{course_id}/content")


@lms_bp.route('/admin/courses/<int:course_id>/content/<int:content_id>', methods=['POST'])
def admin_course_content_delete(course_id, content_id):
    conn = get_db()
    try:
        conn.execute("DELETE FROM lms_course_content WHERE id=? AND elearning_module_id=?", (content_id, course_id))
        conn.commit()
    finally:
        conn.close()
    return redirect(f"{BASE_PATH}/lms/admin/courses/{course_id}/content")


@lms_bp.route('/admin/courses/<int:course_id>/publish', methods=['POST'])
def admin_course_publish(course_id):
    conn = get_db()
    try:
        conn.execute("UPDATE elearning_modules SET status='published' WHERE id=?", (course_id,))
        conn.commit()
    finally:
        conn.close()
    return redirect(f"{BASE_PATH}/lms/admin/courses")


@lms_bp.route('/admin/courses/<int:course_id>/delete', methods=['POST'])
def admin_course_delete(course_id):
    conn = get_db()
    try:
        conn.execute("DELETE FROM lms_quiz_results WHERE enrollment_id IN (SELECT id FROM lms_enrollments WHERE elearning_module_id=?)", (course_id,))
        conn.execute("DELETE FROM lms_enrollments WHERE elearning_module_id=?", (course_id,))
        conn.execute("DELETE FROM lms_course_content WHERE elearning_module_id=?", (course_id,))
        conn.execute("DELETE FROM lms_compliance_rules WHERE elearning_module_id=?", (course_id,))
        conn.execute("DELETE FROM elearning_modules WHERE id=?", (course_id,))
        conn.commit()
    finally:
        conn.close()
    return redirect(f"{BASE_PATH}/lms/admin/courses")


# ═══════════════════════════════════════════════════════════════════════════════
# ADMIN PORTAL — ENROLLMENTS
# ═══════════════════════════════════════════════════════════════════════════════

@lms_bp.route('/admin/enrollments')
def admin_enrollments():
    conn = get_db()
    try:
        enrollments = conn.execute("""
            SELECT e.*, em.first_name, em.last_name, em.employee_number, m.title as module_title
            FROM lms_enrollments e
            JOIN employees em ON em.id = e.employee_id
            JOIN elearning_modules m ON m.id = e.elearning_module_id
            ORDER BY e.status, e.due_date
        """).fetchall()
        modules = conn.execute("SELECT id, title FROM elearning_modules ORDER BY id").fetchall()
        employees = conn.execute("SELECT id, first_name, last_name FROM employees WHERE status='active' ORDER BY id").fetchall()
        roles = conn.execute("SELECT id, role_name FROM roles ORDER BY id").fetchall()
    finally:
        conn.close()

    rows = ""
    for e in enrollments:
        badge = {'not_started':'badge-muted','in_progress':'badge-info','completed':'badge-success','failed':'badge-danger','expired':'badge-warning','withdrawn':'badge-muted'}.get(e['status'],'badge-muted')
        rows += f"""<tr>
            <td>{e['employee_number'] or e['employee_id']}</td>
            <td>{e['first_name']} {e['last_name']}</td>
            <td>{e['module_title']}</td>
            <td><span class="badge {badge}">{e['status'].replace('_',' ').title()}</span></td>
            <td>{e['final_score'] or '—'}</td>
            <td>{_deadline_html(e['due_date'] if 'due_date' in e.keys() else None)}</td>
            <td>
                <form method="POST" action="{BASE_PATH}/lms/admin/enrollments/{e['id']}" style="display:inline"><input type="hidden" name="_method" value="DELETE"><button class="btn btn-sm btn-danger" type="submit">🗑️</button></form>
            </td>
        </tr>"""

    emp_opts = "".join(f'<option value="{e["id"]}">{e["first_name"]} {e["last_name"]}</option>' for e in employees)
    mod_opts = "".join(f'<option value="{m["id"]}">{m["title"]}</option>' for m in modules)
    role_opts = "".join(f'<option value="{r["id"]}">{r["role_name"]}</option>' for r in roles)

    body = f"""
    <h2>Inschrijvingen</h2>
    <div class="card" style="margin-bottom:20px;padding:16px">
        <h2 style="margin-top:0">Training Toewijzen</h2>
        <form method="POST" action="{BASE_PATH}/lms/admin/enrollments">
            <div style="display:grid;grid-template-columns:1fr 1fr 1fr auto;gap:8px;align-items:end">
                <div><label style="font-size:.75rem;color:var(--text-muted)">Medewerker(s)</label><select name="employee_id" multiple style="width:100%;height:80px;padding:8px;border:1px solid var(--border);border-radius:6px">{emp_opts}</select><small>Ctrl+klik voor meerdere</small></div>
                <div><label style="font-size:.75rem;color:var(--text-muted)">Cursus</label><select name="module_id" style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px">{mod_opts}</select></div>
                <div><label style="font-size:.75rem;color:var(--text-muted)">Deadline</label><input type="date" name="due_date" value="{(date.today() + timedelta(days=30)).isoformat()}" style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px"></div>
                <button class="btn btn-success" type="submit">Toewijzen</button>
            </div>
        </form>
        <form method="POST" action="{BASE_PATH}/lms/admin/enrollments/bulk" style="margin-top:12px">
            <div style="display:grid;grid-template-columns:1fr 1fr 1fr auto;gap:8px;align-items:end">
                <div><label style="font-size:.75rem;color:var(--text-muted)">Functie (bulk)</label><select name="role_id" style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px">{role_opts}</select></div>
                <div><label style="font-size:.75rem;color:var(--text-muted)">Cursus</label><select name="module_id" style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px">{mod_opts}</select></div>
                <div><label style="font-size:.75rem;color:var(--text-muted)">Deadline</label><input type="date" name="due_date" value="{(date.today() + timedelta(days=30)).isoformat()}" style="width:100%;padding:8px;border:1px solid var(--border);border-radius:6px"></div>
                <button class="btn btn-warning" type="submit">Bulk Toewijzen</button>
            </div>
        </form>
    </div>
    <table><tr><th>Medew.</th><th>Naam</th><th>Cursus</th><th>Status</th><th>Score</th><th>Deadline</th><th>Actie</th></tr>
    {rows or '<tr><td colspan="7" style="text-align:center;color:var(--text-muted)">Geen inschrijvingen</td></tr>'}
    </table>"""
    return _page('Inschrijvingen', body, 'admin-enroll')


@lms_bp.route('/admin/enrollments', methods=['POST'])
def admin_enrollment_create():
    data = request.form
    module_id = data.get('module_id', type=int)
    emp_id = data.getlist('employee_id')
    due_date = data.get('due_date') or (date.today() + timedelta(days=30)).isoformat()
    if not module_id or not emp_id:
        return redirect(f"{BASE_PATH}/lms/admin/enrollments")
    conn = get_db()
    try:
        for eid in emp_id:
            conn.execute("INSERT OR IGNORE INTO lms_enrollments (employee_id, elearning_module_id, status, due_date) VALUES (?,?, 'not_started', ?)",
                         (int(eid), module_id, due_date))
        conn.commit()
    finally:
        conn.close()
    return redirect(f"{BASE_PATH}/lms/admin/enrollments")


@lms_bp.route('/admin/enrollments/bulk', methods=['POST'])
def admin_enrollment_bulk():
    data = request.form
    module_id = data.get('module_id', type=int)
    role_id = data.get('role_id', type=int)
    due_date = data.get('due_date') or (date.today() + timedelta(days=30)).isoformat()
    if not module_id or not role_id:
        return redirect(f"{BASE_PATH}/lms/admin/enrollments")
    conn = get_db()
    try:
        emps = conn.execute("SELECT id FROM employees WHERE role_id=? AND status='active'", (role_id,)).fetchall()
        for e in emps:
            conn.execute("INSERT OR IGNORE INTO lms_enrollments (employee_id, elearning_module_id, status, due_date) VALUES (?,?, 'not_started', ?)",
                         (e['id'], module_id, due_date))
        conn.commit()
    finally:
        conn.close()
    return redirect(f"{BASE_PATH}/lms/admin/enrollments")


@lms_bp.route('/admin/enrollments/<int:enrollment_id>', methods=['POST'])
def admin_enrollment_delete(enrollment_id):
    conn = get_db()
    try:
        conn.execute("DELETE FROM lms_quiz_results WHERE enrollment_id=?", (enrollment_id,))
        conn.execute("DELETE FROM lms_enrollments WHERE id=?", (enrollment_id,))
        conn.commit()
    finally:
        conn.close()
    return redirect(f"{BASE_PATH}/lms/admin/enrollments")


# ═══════════════════════════════════════════════════════════════════════════════
# ADMIN PORTAL — COMPLIANCE
# ═══════════════════════════════════════════════════════════════════════════════

@lms_bp.route('/admin/compliance')
def admin_compliance():
    conn = get_db()
    try:
        employees = conn.execute("SELECT e.id, e.first_name, e.last_name, e.role_id, r.role_name FROM employees e LEFT JOIN roles r ON r.id=e.role_id WHERE e.status='active' ORDER BY e.id").fetchall()
        modules = conn.execute("SELECT id, title FROM elearning_modules WHERE status='published' ORDER BY id").fetchall()
        rules = conn.execute("SELECT * FROM lms_compliance_rules").fetchall()
        rules_map = {r['elearning_module_id']: r for r in rules}
    finally:
        conn.close()

    # Build heatmap matrix: role × module
    role_modules = {}
    for m in modules:
        for e in employees:
            rid = e['role_id'] or 0
            if rid not in role_modules:
                role_modules[rid] = {'role_name': e['role_name'] or f'Rol {rid}', 'cells': {}}

    # Calculate compliance per employee
    conn = get_db()
    try:
        emp_status = {}
        for e in employees:
            emp_status[e['id']] = {}
            for m in modules:
                rule = rules_map.get(m['id'])
                is_mandatory = rule and rule['is_mandatory']
                enr = conn.execute("SELECT final_passed, completed_at FROM lms_enrollments WHERE employee_id=? AND elearning_module_id=? ORDER BY completed_at DESC LIMIT 1",
                                   (e['id'], m['id'])).fetchone()
                if not is_mandatory:
                    status = 'na'
                elif not enr or not enr['final_passed']:
                    status = 'red'
                elif enr['completed_at']:
                    vdays = rule['valid_period_days'] if rule else 365
                    try:
                        comp_date = datetime.strptime(enr['completed_at'], '%Y-%m-%d %H:%M:%S')
                    except ValueError:
                        comp_date = datetime.strptime(enr['completed_at'][:10], '%Y-%m-%d')
                    expiry = comp_date + timedelta(days=vdays)
                    if expiry.date() < date.today():
                        status = 'red'
                    elif expiry.date() < date.today() + timedelta(days=30):
                        status = 'amber'
                    else:
                        status = 'green'
                else:
                    status = 'red'
                emp_status[e['id']][m['id']] = status
    finally:
        conn.close()

    # Compliance summary cards
    total_mandatory = 0
    compliant_count = 0
    for e in employees:
        for m in modules:
            rule = rules_map.get(m['id'])
            if rule and rule['is_mandatory']:
                total_mandatory += 1
                if emp_status[e['id']][m['id']] == 'green':
                    compliant_count += 1
    pct = int((compliant_count / total_mandatory) * 100) if total_mandatory > 0 else 100

    # Build employee detail table
    emp_rows = ""
    for e in employees:
        cells = ""
        for m in modules:
            s = emp_status[e['id']].get(m['id'], 'na')
            color = {'green':'green','amber':'amber','red':'red','na':''}.get(s, '')
            label = {'green':'✅','amber':'⚠️','red':'❌','na':'—'}.get(s, '—')
            cells += f'<td class="{color}">{label}</td>'
        emp_rows += f'<tr><td>{e["first_name"]} {e["last_name"]}</td><td>{e["role_name"] or "—"}</td>{cells}</tr>'

    mod_headers = "".join(f'<th style="font-size:.65rem;max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap" title="{m["title"]}">{m["title"][:20]}</th>' for m in modules)

    body = f"""
    <div class="cards">
        <div class="card"><div class="card-icon">🛡️</div><div><div class="label">Compliance</div><div class="value">{pct}%</div></div></div>
        <div class="card {'success' if pct >= 80 else 'danger'}"><div class="card-icon">📋</div><div><div class="label">Verplichte Trainingen</div><div class="value">{compliant_count}/{total_mandatory}</div></div></div>
    </div>
    <h2>Compliance Matrix (Medewerker × Training)</h2>
    <div style="overflow-x:auto">
    <table class="heatmap"><tr><th>Medewerker</th><th>Functie</th>{mod_headers}</tr>
    {emp_rows}
    </table>
    </div>
    <p style="margin-top:12px;font-size:.75rem;color:var(--text-muted)">✅ Actief &nbsp; ⚠️ Vervalt binnen 30 dagen &nbsp; ❌ Verlopen/Ontbreekt &nbsp; — Niet verplicht</p>"""
    return _page('Compliance', body, 'admin-compliance')


@lms_bp.route('/admin/compliance/matrix')
def admin_compliance_matrix():
    return redirect(f"{BASE_PATH}/lms/admin/compliance")


@lms_bp.route('/admin/compliance/expired')
def admin_compliance_expired():
    conn = get_db()
    try:
        expired = conn.execute("""
            SELECT e.first_name, e.last_name, e.employee_number, m.title,
                   enr.completed_at, cr.valid_period_days,
                   date(enr.completed_at, '+' || cr.valid_period_days || ' days') as expiry_date
            FROM lms_enrollments enr
            JOIN employees e ON e.id=enr.employee_id
            JOIN elearning_modules m ON m.id=enr.elearning_module_id
            LEFT JOIN lms_compliance_rules cr ON cr.elearning_module_id=enr.elearning_module_id
            WHERE enr.final_passed=1 AND cr.is_mandatory=1
            AND date(enr.completed_at, '+' || cr.valid_period_days || ' days') < date('now')
            ORDER BY expiry_date
        """).fetchall()
    finally:
        conn.close()

    rows = "".join(f"""<tr>
        <td>{e['employee_number'] or ''}</td>
        <td>{e['first_name']} {e['last_name']}</td>
        <td>{e['title']}</td>
        <td><span class="badge badge-danger">Verlopen</span></td>
        <td>{e['expiry_date']}</td>
    </tr>""" for e in expired)

    body = f"""<h2>Verlopen Trainingen</h2>
    <table><tr><th>Nr</th><th>Naam</th><th>Training</th><th>Status</th><th>Vervaldatum</th></tr>
    {rows or '<tr><td colspan="5" style="text-align:center;color:var(--text-muted)">Geen verlopen trainingen</td></tr>'}
    </table>"""
    return _page('Verlopen Trainingen', body, 'admin-compliance')


@lms_bp.route('/admin/compliance/alerts')
def admin_compliance_alerts():
    conn = get_db()
    try:
        alerts = conn.execute("""
            SELECT e.first_name, e.last_name, e.employee_number, m.title,
                   enr.completed_at, cr.valid_period_days,
                   date(enr.completed_at, '+' || cr.valid_period_days || ' days') as expiry_date
            FROM lms_enrollments enr
            JOIN employees e ON e.id=enr.employee_id
            JOIN elearning_modules m ON m.id=enr.elearning_module_id
            LEFT JOIN lms_compliance_rules cr ON cr.elearning_module_id=enr.elearning_module_id
            WHERE enr.final_passed=1 AND cr.is_mandatory=1
            AND date(enr.completed_at, '+' || cr.valid_period_days || ' days') BETWEEN date('now') AND date('now','+30 days')
            ORDER BY expiry_date
        """).fetchall()
    finally:
        conn.close()

    rows = "".join(f"""<tr>
        <td>{a['employee_number'] or ''}</td>
        <td>{a['first_name']} {a['last_name']}</td>
        <td>{a['title']}</td>
        <td><span class="badge badge-warning">Vervalt binnen 30 dagen</span></td>
        <td>{a['expiry_date']}</td>
    </tr>""" for a in alerts)

    body = f"""<h2>Compliance Alerts — Nakomend</h2>
    <table><tr><th>Nr</th><th>Naam</th><th>Training</th><th>Status</th><th>Vervaldatum</th></tr>
    {rows or '<tr><td colspan="5" style="text-align:center;color:var(--text-muted)">Geen nakomende vervallen</td></tr>'}
    </table>"""
    return _page('Compliance Alerts', body, 'admin-compliance')


@lms_bp.route('/admin/compliance/rules', methods=['POST'])
def admin_compliance_rules():
    data = request.get_json(silent=True) or request.form
    module_id = data.get('elearning_module_id', type=int) or int(data.get('elearning_module_id', 0))
    tp_id = data.get('training_program_id', type=int) or int(data.get('training_program_id', 0)) or None
    is_mandatory = data.get('is_mandatory', 0)
    auto_assign = data.get('auto_assign', 0)
    valid_days = data.get('valid_period_days', 365)

    if not module_id:
        return jsonify(success=False, error="module_id verplicht"), 400

    conn = get_db()
    try:
        conn.execute("""INSERT INTO lms_compliance_rules (elearning_module_id, training_program_id, is_mandatory, auto_assign, valid_period_days, updated_at)
                        VALUES (?,?,?,?,?,datetime('now'))""",
                     (module_id, tp_id, is_mandatory, auto_assign, valid_days))
        conn.commit()
    finally:
        conn.close()
    return jsonify(success=True)


# ═══════════════════════════════════════════════════════════════════════════════
# ADMIN PORTAL — ANALYTICS
# ═══════════════════════════════════════════════════════════════════════════════

@lms_bp.route('/admin/analytics')
def admin_analytics():
    conn = get_db()
    try:
        total_enroll = conn.execute("SELECT COUNT(*) as c FROM lms_enrollments").fetchone()['c']
        completed = conn.execute("SELECT COUNT(*) as c FROM lms_enrollments WHERE status='completed'").fetchone()['c']
        failed = conn.execute("SELECT COUNT(*) as c FROM lms_enrollments WHERE status='failed'").fetchone()['c']
        in_progress = conn.execute("SELECT COUNT(*) as c FROM lms_enrollments WHERE status='in_progress'").fetchone()['c']
        avg_score = conn.execute("SELECT ROUND(AVG(final_score),1) as s FROM lms_enrollments WHERE final_score IS NOT NULL").fetchone()['s'] or 0
        pass_rate = int((completed / total_enroll) * 100) if total_enroll > 0 else 0

        # Compliance summary
        total_emp = conn.execute("SELECT COUNT(*) as c FROM employees WHERE status='active'").fetchone()['c']
        comp_pct = 0  # placeholder until compliance rules are configured

        # Per-course stats
        course_stats = conn.execute("""
            SELECT m.id, m.title,
                COUNT(e.id) as enrollments,
                SUM(CASE WHEN e.status='completed' THEN 1 ELSE 0 END) as completed,
                SUM(CASE WHEN e.final_passed=1 THEN 1 ELSE 0 END) as passed,
                ROUND(AVG(CASE WHEN e.final_score IS NOT NULL THEN e.final_score END),1) as avg_score
            FROM elearning_modules m
            LEFT JOIN lms_enrollments e ON e.elearning_module_id=m.id
            GROUP BY m.id ORDER BY m.id
        """).fetchall()
    finally:
        conn.close()

    rows = ""
    for cs in course_stats:
        total = cs['enrollments'] or 0
        comp_count = cs['completed'] or 0
        rate = int((comp_count / total) * 100) if total > 0 else 0
        rows += f"""<tr>
            <td><strong>{cs['title']}</strong></td>
            <td>{total}</td>
            <td>{comp_count}</td>
            <td>{rate}%</td>
            <td>{cs['avg_score'] or '—'}%</td>
            <td><a href="{BASE_PATH}/lms/admin/analytics/course/{cs['id']}" class="btn btn-sm btn-primary">Details</a></td>
        </tr>"""

    body = f"""
    <div class="cards">
        <div class="card"><div class="card-icon">👥</div><div><div class="label">Totaal Inschrijvingen</div><div class="value">{total_enroll}</div></div></div>
        <div class="card success"><div class="card-icon">✅</div><div><div class="label">Voltooid</div><div class="value">{completed}</div></div></div>
        <div class="card warning"><div class="card-icon">⏳</div><div><div class="label">In Uitvoering</div><div class="value">{in_progress}</div></div></div>
        <div class="card danger"><div class="card-icon">❌</div><div><div class="label">Gezakten</div><div class="value">{failed}</div></div></div>
    </div>
    <div class="cards">
        <div class="card"><div class="card-icon">📊</div><div><div class="label">Gemiddelde Score</div><div class="value">{avg_score}%</div></div></div>
        <div class="card"><div class="card-icon">🎯</div><div><div class="label">Slagingspercentage</div><div class="value">{pass_rate}%</div></div></div>
    </div>
    <h2>Per Cursus</h2>
    <table><tr><th>Cursus</th><th>Inschrijvingen</th><th>Voltooid</th><th>Completion</th><th>Gem. Score</th><th>Details</th></tr>
    {rows or '<tr><td colspan="6" style="text-align:center;color:var(--text-muted)">Geen data</td></tr>'}
    </table>"""
    return _page('Analytics', body, 'admin-analytics')


@lms_bp.route('/admin/analytics/course/<int:course_id>')
def admin_analytics_course(course_id):
    conn = get_db()
    try:
        module = conn.execute("SELECT * FROM elearning_modules WHERE id=?", (course_id,)).fetchone()
        enrollments = conn.execute("""
            SELECT e.*, em.first_name, em.last_name, em.employee_number
            FROM lms_enrollments e
            JOIN employees em ON em.id = e.employee_id
            WHERE e.elearning_module_id=?
            ORDER BY e.status, em.last_name
        """, (course_id,)).fetchall()
        quiz_results = conn.execute("""
            SELECT qr.*, em.first_name, em.last_name
            FROM lms_quiz_results qr
            JOIN lms_enrollments enr ON enr.id = qr.enrollment_id
            JOIN employees em ON em.id = enr.employee_id
            WHERE enr.elearning_module_id=?
            ORDER BY qr.submitted_at DESC LIMIT 50
        """, (course_id,)).fetchall()
    finally:
        conn.close()

    rows = ""
    for e in enrollments:
        badge = {'not_started':'badge-muted','in_progress':'badge-info','completed':'badge-success','failed':'badge-danger'}.get(e['status'],'badge-muted')
        rows += f"""<tr>
            <td>{e['employee_number'] or ''}</td>
            <td>{e['first_name']} {e['last_name']}</td>
            <td><span class="badge {badge}">{e['status'].replace('_',' ').title()}</span></td>
            <td>{e['final_score'] or '—'}</td>
            <td>{e['progress_percent'] or 0}%</td>
        </tr>"""

    qr_rows = ""
    for qr in quiz_results:
        qr_rows += f"""<tr>
            <td>{qr['first_name']} {qr['last_name']}</td>
            <td>Poging {qr['attempt_number']}</td>
            <td>{qr['score']}%</td>
            <td>{qr['correct_answers']}/{qr['total_questions']}</td>
            <td><span class="badge {'badge-success' if qr['passed'] else 'badge-danger'}">{'✅' if qr['passed'] else '❌'}</span></td>
            <td>{qr['submitted_at'] or '—'}</td>
        </tr>"""

    title = module['title'] if module else 'Onbekend'
    body = f"""
    <h2>{title} — Cursusstatistieken</h2>
    <h2>Inschrijvingen</h2>
    <table><tr><th>Nr</th><th>Naam</th><th>Status</th><th>Score</th><th>Voortgang</th></tr>
    {rows or '<tr><td colspan="5" style="text-align:center;color:var(--text-muted)">Geen inschrijvingen</td></tr>'}
    </table>
    <h2>Recente Quiz-resultaten</h2>
    <table><tr><th>Medewerker</th><th>Poging</th><th>Score</th><th>Correct</th><th>Resultaat</th><th>Datum</th></tr>
    {qr_rows or '<tr><td colspan="6" style="text-align:center;color:var(--text-muted)">Geen quiz-resultaten</td></tr>'}
    </table>
    <a href="{BASE_PATH}/lms/admin/analytics" class="btn btn-primary" style="margin-top:16px">← Terug naar Analytics</a>"""
    return _page(f'Analytics: {title}', body, 'admin-analytics')


@lms_bp.route('/admin/analytics/employee/<int:employee_id>')
def admin_analytics_employee(employee_id):
    conn = get_db()
    try:
        emp = conn.execute("SELECT * FROM employees WHERE id=?", (employee_id,)).fetchone()
        enrollments = conn.execute("""
            SELECT e.*, m.title FROM lms_enrollments e
            JOIN elearning_modules m ON m.id = e.elearning_module_id
            WHERE e.employee_id=? ORDER BY e.status
        """, (employee_id,)).fetchall()
        certs = conn.execute("""
            SELECT c.*, m.title FROM trn_certificates c
            JOIN elearning_modules m ON m.id = c.module_id
            WHERE c.employee_id=? ORDER BY c.id DESC
        """, (employee_id,)).fetchall()
    finally:
        conn.close()

    name = f"{emp['first_name']} {emp['last_name']}" if emp else 'Onbekend'
    rows = "".join(f"""<tr>
        <td>{e['title']}</td>
        <td><span class="badge {'badge-success' if e['status']=='completed' else 'badge-info' if e['status']=='in_progress' else 'badge-muted'}">{e['status'].replace('_',' ').title()}</span></td>
        <td>{e['progress_percent'] or 0}%</td>
        <td>{e['final_score'] or '—'}</td>
    </tr>""" for e in enrollments)

    cert_rows = "".join(f"""<tr>
        <td>{c['title']}</td><td>{c['quiz_score']}%</td><td>{c['certificate_ref'] or '—'}</td>
    </tr>""" for c in certs)

    body = f"""
    <h2>{name} — Training Historie</h2>
    <h2>Inschrijvingen</h2>
    <table><tr><th>Training</th><th>Status</th><th>Voortgang</th><th>Score</th></tr>
    {rows or '<tr><td colspan="4" style="text-align:center;color:var(--text-muted)">Geen trainingen</td></tr>'}
    </table>
    <h2>Certificaten</h2>
    <table><tr><th>Training</th><th>Score</th><th>Referentie</th></tr>
    {cert_rows or '<tr><td colspan="3" style="text-align:center;color:var(--text-muted)">Geen certificaten</td></tr>'}
    </table>"""
    return _page(f'{name}', body, 'admin-analytics')


# ═══════════════════════════════════════════════════════════════════════════════
# REGISTRATION HELPER
# ═══════════════════════════════════════════════════════════════════════════════

def register_lms_routes(app, page_fn=None, BASE_PATH="/hseq-dashboard"):
    """Register LMS blueprint on Flask app. Call from app.py."""
    global _page_fn
    if page_fn:
        _page_fn = page_fn
    bp = os.environ.get('BASE_PATH', '/hseq-dashboard')
    app.register_blueprint(lms_bp, url_prefix=BASE_PATH + '/lms')
    # Also register the API score endpoint (external quiz HTML posts here)
    @app.route(BASE_PATH + '/api/lms/score', methods=['POST'])
    def api_lms_score_proxy():
        return api_score()
