#!/usr/bin/env python3
"""Generate HTML quiz for Kwik Awareness Training — Kennistoets."""

import os

LOGO_B64 = open("/root/projects/jg/assets/branding/logo-white-base64.txt").read().strip()

QUESTIONS = [
    {
        "id": 1,
        "cat": "Kennisvraag",
        "q": "Wat is de dampdruk van elementair kwik bij 20°C?",
        "opts": ["0,00012 mmHg", "0,00185 mmHg", "0,0185 mmHg", "0,185 mmHg"],
        "ans": 1,
        "expl": "Bij 20°C bedraagt de dampdruk 0,00185 mmHg (0,246 Pa). Kwik produceert reeds bij kamertemperatuur aanzienlijke damp, wat het risico op inhalatieblootstelling benadrukt."
    },
    {
        "id": 2,
        "cat": "Kennisvraag",
        "q": "Wat is de Nederlandse MAC-waarde (TWA-8h) voor kwikdamp?",
        "opts": ["0,010 mg/m³", "0,025 mg/m³", "0,050 mg/m³", "0,100 mg/m³"],
        "ans": 1,
        "expl": "Conform het Arbobesluit (bijlage XI-A) bedraagt de MAC-waarde voor kwik en anorganische verbindingen 0,025 mg/m³ als tijdsgewogen gemiddelde over 8 uur."
    },
    {
        "id": 3,
        "cat": "Kennisvraag",
        "q": "Welke blootstellingsroute heeft de hoogste absorptie voor elementair kwik?",
        "opts": ["Orale opname (~50%)", "Dermal contact (~30%)", "Inhalatie (~80%)", "Oogcontact (~10%)"],
        "ans": 2,
        "expl": "Elementair kwikdamp wordt via de longen voor ~80% geabsorbeerd en komt direct in de bloedbaan. Hg⁰ passeert de BBB en oxideert in rode bloedcellen tot Hg²⁺."
    },
    {
        "id": 4,
        "cat": "Kennisvraag",
        "q": "Wat is de IARC-classificatie voor kwik?",
        "opts": ["Groep 1 — Bewezen carcinogeen", "Groep 2A — Waarschijnlijk carcinogeen", "Groep 2B — Mogelijk carcinogeen", "Groep 3 — Niet classificeerbaar"],
        "ans": 3,
        "expl": "IARC classificeert elementair kwik en anorganische kwikverbindingen als Groep 3 (niet classificeerbaar voor carcinogeniciteit bij de mens)."
    },
    {
        "id": 5,
        "cat": "Kennisvraag",
        "q": "Wat is de biologische halfwaardetijd van methylkwik in de hersenen?",
        "opts": ["~30 dagen", "~70 dagen", "~150 dagen", "~230 dagen"],
        "ans": 3,
        "expl": "Methylkwik heeft een biologische halfwaardetijd van ~230 dagen in de hersenen, wat de ernstige en langdurige neurologische effecten verklaart (Minamata disease)."
    },
    {
        "id": 6,
        "cat": "Toepassingsvraag",
        "q": "Een medewerker breekt een fluorescentielamp in een slecht geventileerde kelder. Wat is de eerste actie?",
        "opts": ["Direct opruimen met bezem en schop", "De kelder evacueren en ventileren", "Een standaard stofzuiger gebruiken", "De lampfragmenten in de prullenbak gooien"],
        "ans": 1,
        "expl": "Bij kwikspill in een kelder: eerst evacueren en ventileren (kwikdamp is zwaarder dan lucht en accumuleert in lage ruimtes). Daarna pas opruimen met PBM en spill-kit. NOOIT een standaard stofzuiger gebruiken."
    },
    {
        "id": 7,
        "cat": "Toepassingsvraag",
        "q": "Bij een kwikmeting wordt een concentratie van 0,018 mg/m³ gemeten (TWA-8h). Wat is correct?",
        "opts": ["Geen actie nodig — onder de MAC-waarde", "Actiewaarde overschreden — arbeidshygiënische strategie verplicht", "Direct ontruimen — MAC-waarde overschreden", "Alleen PBM dragen — voldoende"],
        "ans": 1,
        "expl": "De actiewaarde bedraagt 50% van MAC = 0,0125 mg/m³. Bij 0,018 mg/m³ is de actiewaarde overschreden. Conform Arbobesluit is dan een arbeidshygiënische strategie verplicht."
    },
    {
        "id": 8,
        "cat": "Toepassingsvraag",
        "q": "Welk PBM-combinatie is correct voor werkzaamheden met kwikdamp?",
        "opts": ["Stofmasker FFP2 + katoenen handschoenen", "Halfgezichtsmasker P3 met gasfilter type Hg + nitril handschoenen", "Volggezichtsmasker met P3-filter + latex handschoenen", "Gewoon een mondkapje + veiligheidsbril"],
        "ans": 1,
        "expl": "Voor kwikdamp is een halfgezichtsmasker P3 gecombineerd met een gasfilter type Hg (EN 371) vereist. Nitril handschoenen zijn verplicht; latex is onvoldoende."
    },
    {
        "id": 9,
        "cat": "Toepassingsvraag",
        "q": "Bij een kleine kwikspill (<25 ml) is de laatste stap vóór vrijgave van de zone:",
        "opts": ["Het afvoerbon invullen", "Een kwikdampmeting uitvoeren — <0,025 mg/m³", "De vloer dweilen met water", "Het incident rapporteren aan de pers"],
        "ans": 1,
        "expl": "Na opruiming en decontaminatie is een verificatiemeting verplicht. Pas als de kwikdampconcentratie <0,025 mg/m³ (MAC) is, mag de zone worden vrijgegeven."
    },
    {
        "id": 10,
        "cat": "Toepassingsvraag",
        "q": "In een aardgasinstallatie wordt aluminium gebruikt in cryogene heat exchangers. Wat is het risico bij aanwezigheid van kwik?",
        "opts": ["Geen risico — kwik reageert niet met aluminium", "Amalgamvorming → intergranulaire corrosie → catastrofaal falen", "Alleen oppervlakteroest — cosmetisch", "Kwik verhoogt de thermische geleidbaarheid positief"],
        "ans": 1,
        "expl": "Kwik vormt met aluminium een amalgam, wat leidt tot intergranulaire corrosie. In cryogene toepassingen resulteert dit in brittle fracture en catastrofaal falen. Case: Skikda LNG (2004)."
    },
    {
        "id": 11,
        "cat": "Analysevraag",
        "q": "Een medewerker meldt: fijn trillen handen, prikkelbaarheid, geheugenproblemen. Biomonitoring: 35 µg/g creatinine Hg in urine. Welke conclusie?",
        "opts": ["Niet werkgerelateerd — waarde is normaal", "Biologische grenswaarde overschreden (20 µg/g) — werkplek stilleggen, medische evaluatie", "Verhoogd maar acceptabel — symptomen zijn toeval", "Urine is ongeschikt — bloedmeting vereist"],
        "ans": 1,
        "expl": "De biologische grenswaarde bedraagt <20 µg/g creatinine. Bij 35 µg/g is deze overschreden. De symptomen zijn consistent met chronische kwikblootstelling. Directe actie vereist."
    },
    {
        "id": 12,
        "cat": "Analysevraag",
        "q": "Aardgasveld: kwik 10–3.000 µg/Nm³ per seizoen. MRU efficiëntie 99,5%. Resterende concentratie bij piek (3.000 µg/Nm³)?",
        "opts": ["0,15 µg/Nm³", "15 µg/Nm³", "150 µg/Nm³", "1.500 µg/Nm³"],
        "ans": 1,
        "expl": "3.000 µg/Nm³ × 0,5% (resterend na 99,5% MRU) = 15 µg/Nm³. Dit is significant — extra monitoring en mogelijk een tweede MRU-trap zijn aan te bevelen."
    },
    {
        "id": 13,
        "cat": "Analysevraag",
        "q": "Oude chloor-alkalifabriek: kwik in bodem 25 mg/kg droge stof. Interventiewaarde: 10 mg/kg. Wat is correct?",
        "opts": ["Sanering niet nodig", "Concentratie overschrijdt interventiewaarde — sanering vereist conform Wet bodembescherming", "Alleen monitoren — geen directe actie", "Fabriek mag blijven draaien"],
        "ans": 1,
        "expl": "Bij overschrijding van de interventiewaarde (10 mg/kg) is sanering verplicht conform de Wet bodembescherming."
    },
    {
        "id": 14,
        "cat": "Analysevraag",
        "q": "Zwangere medewerkster in lab met kwikverbindingen (Repr. 1B, H360Df). Wat is correct?",
        "opts": ["Geen beperkingen — minimale blootstelling", "PBM dragen is voldoende", "Zwangere vrouwen mogen niet werken met Repr. 1B-stoffen — herplaatsing vereist", "Alleen met schriftelijke toestemming bedrijfsarts"],
        "ans": 2,
        "expl": "Repr. 1B (H360Df) = vermoedelijk schadelijk voor vruchtbaarheid én ongeboren kind. Werk met deze stoffen is verboden voor zwangere vrouwen. Herplaatsing is verplicht."
    },
    {
        "id": 15,
        "cat": "Analysevraag",
        "q": "Bij een kwikspill wordt zwavelpoeder gebruikt. Wat is het reactieproduct en waarom is dit belangrijk?",
        "opts": ["HgSO₄ — oplosbaar in water", "HgS (kinzinnabar) — zeer laag oplosbaar, stabiel, niet-vluchtig", "Hg₂S — onstabiel, decomposeert", "HgO — vluchtig bij verhitting"],
        "ans": 1,
        "expl": "Zwavel reageert met kwik tot HgS (kinzinnabar), zeer laag oplosbaar, dampdruk <10⁻⁹ mmHg. Chemisch stabiel en veilig voor afvoer."
    },
]

JS_QUESTIONS = ""
for i, q in enumerate(QUESTIONS):
    comma = "," if i < len(QUESTIONS) - 1 else ""
    JS_QUESTIONS += (
        '  {"id":' + str(q["id"]) +
        ',"cat":"' + q["cat"] +
        '","q":' + repr(q["q"]) +
        ',"opts":' + repr(q["opts"]) +
        ',"ans":' + str(q["ans"]) +
        ',"expl":' + repr(q["expl"]) + '}' + comma + "\n"
    )

HTML = """<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Awareness Training Kwik — Kennistoets</title>
<style>
:root {{
  --primary: #003366;
  --success: #00A859;
  --error: #EF4444;
  --bg-card: #F8F9FA;
}}
* {{ margin:0; padding:0; box-sizing:border-box; }}
body {{
  font-family: 'Segoe UI', Roboto, Arial, sans-serif;
  font-size: 16px;
  background: #EEF2F7;
  color: #1F2937;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}}
.header {{
  background: var(--primary);
  color: #fff;
  padding: 20px 24px;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}}
.header img {{ height: 40px; }}
.header-text h1 {{ font-size: 22px; font-weight: 700; }}
.header-text p {{ font-size: 14px; opacity: 0.85; margin-top: 4px; }}
.container {{
  max-width: 1200px;
  width: 100%;
  margin: 0 auto;
  padding: 24px 16px;
  flex: 1;
}}
.progress-bar {{
  width: 100%;
  height: 8px;
  background: #D1D5DB;
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 24px;
}}
.progress-fill {{
  height: 100%;
  background: var(--primary);
  border-radius: 4px;
  transition: width 0.4s ease;
}}
.question-counter {{
  font-size: 14px;
  color: #6B7280;
  margin-bottom: 12px;
}}
.card {{
  background: var(--bg-card);
  border-radius: 12px;
  padding: 32px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}}
.category-badge {{
  display: inline-block;
  background: var(--primary);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  padding: 4px 12px;
  border-radius: 20px;
  margin-bottom: 16px;
}}
.question-text {{
  font-size: 18px;
  font-weight: 600;
  margin-bottom: 24px;
  line-height: 1.5;
}}
.options {{ display: flex; flex-direction: column; gap: 12px; margin-bottom: 24px; }}
.option {{
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 16px;
  border: 2px solid #D1D5DB;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.2s;
  background: #fff;
}}
.option:hover {{ border-color: var(--primary); background: #F0F4FA; }}
.option.selected {{ border-color: var(--primary); background: #E8EEF8; }}
.option.correct {{ border-color: var(--success); background: #ECFDF5; }}
.option.wrong {{ border-color: var(--error); background: #FEF2F2; }}
.option-letter {{
  min-width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 14px;
}}
.option.correct .option-letter {{ background: var(--success); }}
.option.wrong .option-letter {{ background: var(--error); }}
.option-text {{ padding-top: 4px; line-height: 1.4; }}
.btn {{
  display: inline-block;
  padding: 12px 32px;
  border: none;
  border-radius: 8px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s;
}}
.btn-check {{
  background: var(--primary);
  color: #fff;
}}
.btn-check:hover {{ background: #002244; }}
.btn-check:disabled {{ background: #9CA3AF; cursor: not-allowed; }}
.btn-restart {{
  background: var(--primary);
  color: #fff;
  margin-top: 16px;
}}
.btn-restart:hover {{ background: #002244; }}
.feedback {{
  margin-top: 20px;
  padding: 16px 20px;
  border-radius: 8px;
  font-size: 15px;
  line-height: 1.5;
  display: none;
}}
.feedback.correct {{ display: block; background: #ECFDF5; border-left: 4px solid var(--success); color: #065F46; }}
.feedback.wrong {{ display: block; background: #FEF2F2; border-left: 4px solid var(--error); color: #991B1B; }}
.feedback strong {{ display: block; margin-bottom: 6px; font-size: 16px; }}
.result {{
  text-align: center;
  padding: 48px 32px;
}}
.result h2 {{ font-size: 28px; margin-bottom: 12px; }}
.result .score {{ font-size: 48px; font-weight: 700; margin: 16px 0; }}
.result.pass {{ color: var(--success); }}
.result.fail {{ color: var(--error); }}
.result p {{ font-size: 16px; color: #4B5563; margin-bottom: 8px; }}
.footer {{
  background: #374151;
  color: #D1D5DB;
  text-align: center;
  padding: 16px;
  font-size: 13px;
  margin-top: auto;
}}
.hidden {{ display: none !important; }}
@media (max-width: 600px) {{
  .header {{ padding: 14px 12px; }}
  .header-text h1 {{ font-size: 17px; }}
  .card {{ padding: 20px 16px; }}
  .question-text {{ font-size: 16px; }}
  .result .score {{ font-size: 36px; }}
}}
</style>
</head>
<body>

<div class="header">
  <img src="""" + LOGO_B64 + """" alt="JvG Consultancy Logo">
  <div class="header-text">
    <h1>Awareness Training Kwik — Kennistoets</h1>
    <p>Gevorderd Niveau | 15 Vragen</p>
  </div>
</div>

<div class="container">
  <div class="progress-bar"><div class="progress-fill" id="progressFill" style="width:0%"></div></div>
  <div class="question-counter" id="counter">Vraag 1 van 15</div>

  <div class="card" id="quizCard">
    <div class="category-badge" id="catBadge">Kennisvraag</div>
    <div class="question-text" id="qText"></div>
    <div class="options" id="optionsDiv"></div>
    <button class="btn btn-check" id="checkBtn" disabled onclick="checkAnswer()">Controleer</button>
    <div class="feedback" id="feedback"></div>
  </div>

  <div class="card result hidden" id="resultCard">
    <h2 id="resultTitle"></h2>
    <div class="score" id="resultScore"></div>
    <p id="resultMsg"></p>
    <button class="btn btn-restart" onclick="restartQuiz()">Opnieuw starten</button>
  </div>
</div>

<div class="footer">JvG Consultancy | Safety &bull; Governance &bull; Advisory | Copyright 2026</div>

<script>
var questions = [
""" + JS_QUESTIONS + """
];
var current = 0;
var score = 0;
var answered = false;
var selected = -1;

function loadQuestion() {{
  answered = false;
  selected = -1;
  var q = questions[current];
  document.getElementById("counter").textContent = "Vraag " + (current+1) + " van " + questions.length;
  document.getElementById("progressFill").style.width = ((current)/questions.length*100) + "%";
  document.getElementById("catBadge").textContent = q.cat;
  document.getElementById("qText").textContent = q.q;
  var letters = ["A","B","C","D"];
  var html = "";
  for (var i = 0; i < q.opts.length; i++) {{
    html += '<div class="option" id="opt' + i + '" onclick="selectOption(' + i + ')">';
    html += '<div class="option-letter">' + letters[i] + '</div>';
    html += '<div class="option-text">' + q.opts[i] + '</div>';
    html += '</div>';
  }}
  document.getElementById("optionsDiv").innerHTML = html;
  document.getElementById("checkBtn").disabled = true;
  var fb = document.getElementById("feedback");
  fb.className = "feedback";
  fb.style.display = "none";
}}

function selectOption(idx) {{
  if (answered) return;
  selected = idx;
  var opts = document.querySelectorAll(".option");
  for (var i = 0; i < opts.length; i++) {{
    opts[i].classList.remove("selected");
  }}
  document.getElementById("opt" + idx).classList.add("selected");
  document.getElementById("checkBtn").disabled = false;
}}

function checkAnswer() {{
  if (answered || selected < 0) return;
  answered = true;
  var q = questions[current];
  var isCorrect = (selected === q.ans);
  if (isCorrect) score++;

  document.getElementById("opt" + selected).classList.add(isCorrect ? "correct" : "wrong");
  document.getElementById("opt" + selected).classList.remove("selected");
  if (!isCorrect) {{
    document.getElementById("opt" + q.ans).classList.add("correct");
  }}

  var fb = document.getElementById("feedback");
  fb.className = "feedback " + (isCorrect ? "correct" : "wrong");
  fb.innerHTML = "<strong>" + (isCorrect ? "&#10003; Correct!" : "&#10007; Incorrect") + "</strong>" + q.expl;
  fb.style.display = "block";

  document.getElementById("checkBtn").disabled = true;
  document.getElementById("checkBtn").textContent = current < questions.length - 1 ? "Volgende vraag →" : "Bekijk resultaat";
  document.getElementById("checkBtn").onclick = isCorrect || true ? nextQuestion : null;
  document.getElementById("checkBtn").onclick = nextQuestion;
}}

function nextQuestion() {{
  current++;
  if (current >= questions.length) {{
    showResult();
  }} else {{
    document.getElementById("checkBtn").textContent = "Controleer";
    document.getElementById("checkBtn").onclick = checkAnswer;
    loadQuestion();
  }}
}}

function showResult() {{
  document.getElementById("quizCard").classList.add("hidden");
  document.getElementById("resultCard").classList.remove("hidden");
  document.getElementById("progressFill").style.width = "100%";
  document.getElementById("counter").textContent = "Afgerond";
  var pct = Math.round(score/questions.length*100);
  var pass = score >= 11;
  document.getElementById("resultTitle").textContent = pass ? "GESLAAGD" : "NIET GESLAAGD";
  document.getElementById("resultScore").className = "score " + (pass ? "pass" : "fail");
  document.getElementById("resultScore").textContent = score + " / " + questions.length;
  document.getElementById("resultMsg").textContent = pass
    ? "Gefeliciteerd! U heeft de kennistoets met succes afgerond (score ≥ 11/15)."
    : "Helaas, u heeft " + score + " van de 15 vragen correct beantwoord. Minimaal 11 correcte antwoorden zijn vereist voor slaagresultaat. Probeer het opnieuw.";
}}

function restartQuiz() {{
  current = 0;
  score = 0;
  answered = false;
  selected = -1;
  document.getElementById("quizCard").classList.remove("hidden");
  document.getElementById("resultCard").classList.add("hidden");
  document.getElementById("checkBtn").textContent = "Controleer";
  document.getElementById("checkBtn").onclick = checkAnswer;
  loadQuestion();
}}

loadQuestion();
</script>
</body>
</html>"""

OUT = "/root/projects/jg/2026-pbm-KWIK/deliverables/html/kwik-quiz_v1.0.html"
os.makedirs(os.path.dirname(OUT), exist_ok=True)
with open(OUT, "w", encoding="utf-8") as f:
    f.write(HTML)
print("Generated: " + OUT)
