#!/usr/bin/env python3
"""
Generator voor Procedure_Voorjaarsconventie_2027_v1.0.docx
District 110AN - Voorjaarsconventie April 2027

Bronnen (alleen feiten uit Meta-Dossier):
- Handboek Lions Conventies vs 06 20240729
- Huishoudelijk Reglement MD 110 mei 2021
- Werkplan AN 2026-2027 draft v1
- Districtbegroting 110 AN 25-26
- Club Health Assessment District 110AN (sept 2025)
- Conventie Roulatieschema
- Verslag Najaarsconventie 2024
"""

from docx import Document
from docx.shared import Cm, Pt, Emu, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.enum.section import WD_ORIENT
from docx.oxml.ns import qn, nsdecls
from docx.oxml import parse_xml
import os
from datetime import date

# ── Constants & Factual Data (alleen uit Meta-Dossier) ─────────────────────
DISTRICT = "110AN"
CONVENTIE_TYPE = "Voorjaarsconventie (District Convention)"
CONVENTIE_MAAND = "April 2027"
GOVERNANCE = "Huishoudelijk Reglement MD 110 mei 2021"
STEMRECHT_REGEL = "1 stem per 10 leden per club (min 1, max 5)"
QUORUM_REGEL = ">50% van stemgerechtigden"
THEMA_2026_2027 = "Samen verder bouwen!"
VORIGE_ORGANISATOR = "LC Bussum Godelinde (FY 2025-2026)"
LOGO_PATH = "/root/projects/jg/2026-voorjaarsconventie-110an/assets/logo_jvg.png"  # verwacht: 754x676px
LOGO_WIDTH_CM = 2.0
LOGO_HEIGHT_CM = 1.8

# ── Helper functions ────────────────────────────────────────────────────────

def set_cell_shading(cell, color_hex: str):
    """Set background color of a table cell."""
    shading = parse_xml(f'<w:shd {nsdecls("w")} w:fill="{color_hex}"/>')
    cell._tc.get_or_add_tcPr().append(shading)


def add_heading_styled(doc, text: str, level: int):
    """Add heading with corporate styling."""
    heading = doc.add_heading(text, level=level)
    for run in heading.runs:
        run.font.color.rgb = RGBColor(0x00, 0x33, 0x66)  # Corporate dark blue
        run.font.name = 'Calibri'
    return heading


def add_body_text(doc, text: str, bold=False, italic=False, size=Pt(11), alignment=None):
    """Add styled body paragraph."""
    p = doc.add_paragraph()
    run = p.add_run(text)
    run.font.size = size
    run.font.name = 'Calibri'
    run.bold = bold
    run.italic = italic
    run.font.color.rgb = RGBColor(0x33, 0x33, 0x33)
    if alignment:
        p.alignment = alignment
    return p


def add_bullet(doc, text: str, level=0, bold_prefix=None):
    """Add bullet point with optional bold prefix."""
    p = doc.add_paragraph(style='List Bullet')
    p.paragraph_format.left_indent = Cm(1.27 + level * 1.27)
    if bold_prefix:
        run_b = p.add_run(bold_prefix)
        run_b.bold = True
        run_b.font.name = 'Calibri'
        run_b.font.size = Pt(11)
        run_b.font.color.rgb = RGBColor(0x33, 0x33, 0x33)
        run = p.add_run(text)
    else:
        run = p.add_run(text)
    run.font.name = 'Calibri'
    run.font.size = Pt(11)
    run.font.color.rgb = RGBColor(0x33, 0x33, 0x33)
    return p


def add_table_with_style(doc, rows, cols, data, header_row=True, col_widths=None):
    """Create a styled table."""
    table = doc.add_table(rows=rows, cols=cols, style='Table Grid')
    table.alignment = WD_TABLE_ALIGNMENT.CENTER
    if col_widths:
        for i, width in enumerate(col_widths):
            for row in table.rows:
                row.cells[i].width = Cm(width)
    # Style header
    if header_row and table.rows:
        for cell in table.rows[0].cells:
            set_cell_shading(cell, "003366")
            for paragraph in cell.paragraphs:
                paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
                for run in paragraph.runs:
                    run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
                    run.font.bold = True
                    run.font.name = 'Calibri'
                    run.font.size = Pt(10)
    # Style data rows
    for row_idx, row in enumerate(table.rows):
        if header_row and row_idx == 0:
            continue
        for cell in row.cells:
            for paragraph in cell.paragraphs:
                for run in paragraph.runs:
                    run.font.name = 'Calibri'
                    run.font.size = Pt(10)
                    run.font.color.rgb = RGBColor(0x33, 0x33, 0x33)
    # Fill data
    for r, row_data in enumerate(data):
        for c, cell_text in enumerate(row_data):
            if r < len(table.rows) and c < len(table.rows[r].cells):
                table.rows[r].cells[c].text = str(cell_text)
    return table


def insert_logo(doc, logo_path: str):
    """Insert JvG logo at top right of first section header."""
    if os.path.exists(logo_path):
        # Add to first paragraph/header area
        section = doc.sections[0]
        header = section.header
        header.is_linked_to_previous = False
        p = header.paragraphs[0] if header.paragraphs else header.add_paragraph()
        p.alignment = WD_ALIGN_PARAGRAPH.RIGHT
        run = p.add_run()
        run.add_picture(logo_path, width=Cm(LOGO_WIDTH_CM), height=Cm(LOGO_HEIGHT_CM))


def set_document_defaults(doc):
    """Set default font and margins."""
    style = doc.styles['Normal']
    font = style.font
    font.name = 'Calibri'
    font.size = Pt(11)
    font.color.rgb = RGBColor(0x33, 0x33, 0x33)
    # Margins
    for section in doc.sections:
        section.top_margin = Cm(2.54)
        section.bottom_margin = Cm(2.54)
        section.left_margin = Cm(2.54)
        section.right_margin = Cm(2.54)


# ── Document Generation ─────────────────────────────────────────────────────

def build_document():
    doc = Document()
    set_document_defaults(doc)
    insert_logo(doc, LOGO_PATH)

    # ── COVER / TITLE PAGE ────────────────────────────────────────────────
    for _ in range(4):
        doc.add_paragraph()

    title = doc.add_paragraph()
    title.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = title.add_run("PROCEDURE VOORJAARSCONVENTIE 2027")
    run.font.size = Pt(28)
    run.font.bold = True
    run.font.color.rgb = RGBColor(0x00, 0x33, 0x66)
    run.font.name = 'Calibri'

    subtitle = doc.add_paragraph()
    subtitle.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = subtitle.add_run(f"District {DISTRICT}  —  {CONVENTIE_MAAND}")
    run.font.size = Pt(16)
    run.font.color.rgb = RGBColor(0x00, 0x66, 0x99)
    run.font.name = 'Calibri'

    doc.add_paragraph()
    version = doc.add_paragraph()
    version.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = version.add_run("Versie 1.0")
    run.font.size = Pt(12)
    run.font.italic = True
    run.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
    run.font.name = 'Calibri'

    doc.add_paragraph()
    doc.add_paragraph()
    gov = doc.add_paragraph()
    gov.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = gov.add_run(f"Governance: {GOVERNANCE}")
    run.font.size = Pt(10)
    run.font.color.rgb = RGBColor(0x66, 0x66, 0x66)
    run.font.name = 'Calibri'

    thema = doc.add_paragraph()
    thema.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = thema.add_run(f"Jaarthema 2026–2027: \"{THEMA_2026_2027}\"")
    run.font.size = Pt(11)
    run.font.italic = True
    run.font.color.rgb = RGBColor(0x00, 0x66, 0x99)
    run.font.name = 'Calibri'

    doc.add_page_break()

    # ── TABLE OF CONTENTS placeholder ─────────────────────────────────────
    add_heading_styled(doc, "Inhoudsopgave", level=1)
    add_body_text(doc, "1. Doel & Scope", bold=True)
    add_body_text(doc, "2. Processtappen (Voorbereiding → Uitvoering → Evaluatie)", bold=True)
    add_body_text(doc, "3. Rollen & Verantwoordelijkheden (RACI)", bold=True)
    add_body_text(doc, "4. Documenten & Templates", bold=True)
    add_body_text(doc, "5. Kwaliteitscontroles", bold=True)
    add_body_text(doc, "6. Afwijkingen & Escalatie", bold=True)
    add_body_text(doc, "Bijlage A: Controleset Feiten", bold=True)
    add_body_text(doc, "Bijlage B: Stemrechtberekening per Club", bold=True)
    doc.add_page_break()

    # ── HOOFDSTUK 1: DOEL & SCOPE ─────────────────────────────────────────
    add_heading_styled(doc, "1. Doel & Scope", level=1)

    add_heading_styled(doc, "1.1 Doel van deze procedure", level=2)
    add_body_text(doc, (
        "Deze procedure beschrijft het volledige proces voor de organisatie en uitvoering van de "
        f"{CONVENTIE_TYPE} van District {DISTRICT} in {CONVENTIE_MAAND}. Het document fungeert als "
        "leidraad voor het organiserende comité, het districtskabinet, de ambtelijk secretaris en alle "
        "betrokken functionarissen om een zorgvuldige, tijdige en conform de regels verlopen conventie "
        "te waarborgen."
    ))

    add_heading_styled(doc, "1.2 Scope", level=2)
    add_bullet(doc, f"District: {DISTRICT}")
    add_bullet(doc, f"Conventietype: {CONVENTIE_TYPE}")
    add_bullet(doc, f"Datum: {CONVENTIE_MAAND} (exacte datum volgens roulatie-schema)")
    add_bullet(doc, "Locatie: te bepalen op basis van roulatie-schema (toerbeurt in een district in Nederland)")
    add_bullet(doc, f"Governance: {GOVERNANCE}")
    add_bullet(doc, f"Stemrechten: {STEMRECHT_REGEL}")
    add_bullet(doc, f"Quorum: {QUORUM_REGEL}")
    add_bullet(doc, f"Thema FY 2026–2027: \"{THEMA_2026_2027}\"")
    add_bullet(doc, f"Vorige organisator (FY 2025–2026): {VORIGE_ORGANISATOR}")

    add_heading_styled(doc, "1.3 Wettelijke & statutaire basis", level=2)
    add_body_text(doc, "Deze procedure is gebaseerd op de volgende leidende documenten (alleen feiten):")
    add_bullet(doc, "Handboek Lions Conventies vs 06 (2024-07-29) — primaire bron voor conventie-eisen")
    add_bullet(doc, "Huishoudelijk Reglement MD 110 mei 2021 — stemrechten, quorum, procedures, oproepingstermijnen")
    add_bullet(doc, "Werkplan AN 2026–2027 draft v1 — activiteitenkalender, budget, thematische invulling")
    add_bullet(doc, "Districtbegroting 110 AN 25-26 — financiële referentie")
    add_bullet(doc, "Club Health Assessment District 110AN (sept 2025) — ledenaantallen voor stemrechtberekening")
    add_bullet(doc, "Conventie Roulatieschema — locatiebepaling en rotatie")
    add_bullet(doc, "Verslag Najaarsconventie 17 oktober 2024 — precedent en lessen geleerd")

    add_heading_styled(doc, "1.4 Definities", level=2)
    definitions = [
        ("DG", "District Governor (voorzitter van de conventie)"),
        ("VDG", "Vice District Governor (1e en 2e)"),
        ("Ambtelijk Secretaris", "Vaste aanspreekpunt voor registratie, notulering, stukkenvoorziening"),
        ("Stembureau", "Door gouverneursraad benoemd; voorzitter + leden voor telling en verificatie quorum"),
        ("Registratiebureau", "Verantwoordelijk voor registratie stemgerechtigden, uitreiking stemkaarten/stembiljetten"),
        ("Good Standing", "Club voldoet aan contributieverplichtingen en statutaire eisen (art. 2 HR)"),
        ("Stemgerechtigde", "Lid aangewezen door clubbestuur uiterlijk 24 uur voor conventie (art. 2.2 HR)"),
    ]
    for term, defn in definitions:
        add_bullet(doc, defn, bold_prefix=f"{term}: ")

    doc.add_page_break()

    # ── HOOFDSTUK 2: PROCESSTAPPEN ────────────────────────────────────────
    add_heading_styled(doc, "2. Processtappen (Voorbereiding → Uitvoering → Evaluatie)", level=1)

    # Fase A: Voorbereiding
    add_heading_styled(doc, "Fase A — Voorbereiding (T-12 maanden tot T-1 maand)", level=2)
    prep_steps = [
        ("T-12 mnd", "Roulatie-schema raadplegen → locatie en organiserende club(s) vaststellen"),
        ("T-10 mnd", "Organiserend comité vormen (DG, VDG’s, ambtelijk secretaris, clubvertegenwoordigers)"),
        ("T-9 mnd", "Datum bevestigen + locatie boeken (in lijn met roulatie en internationale kalender)"),
        ("T-8 mnd", "Budget ontwerpen (referentie: Districtbegroting 25-26; post '1 Districtsconventie' € 3.500)"),
        ("T-7 mnd", "Ontwerp-agenda opstellen: herdenking overledenen, werkplan/begroting inkomende GR, "
                    "verkiezingen 2e VDG / 1e VDG / DG, vlaggenceremonie, eventueel internationale gasten"),
        ("T-6 mnd", "Oproeping voorbereiden: min. 30 dagen van tevoren aan clubs, Lions, Leoclubs (art. 2 HR)"),
        ("T-5 mnd", "Registratieproces opzetten (LionsBase / digitale tooling); stemkaarten & stembiljetten bestellen"),
        ("T-4 mnd", "Voorstellen, amendementen, resoluties, moties innen (deadline T-20 dagen voor digitaal versturen, art. 7 HR)"),
        ("T-3 mnd", "Stembureau benoemen via gouverneursraad (art. 15 HR); instructies vastleggen"),
        ("T-2 mnd", "Conventiestukken digitaal versturen aan clubs (art. 7.1 HR)"),
        ("T-1 mnd", "Laatste check: registratielijsten, stemgerechtigden per club (1/10, min1/max5), quorum-analyse"),
    ]
    for moment, actie in prep_steps:
        add_bullet(doc, actie, bold_prefix=f"{moment}: ")

    # Fase B: Uitvoering
    add_heading_styled(doc, "Fase B — Uitvoering (Conventiedag(en))", level=2)
    exec_steps = [
        ("Dag -1", "Aankomst DG, VDG’s, partners, gasten, ambtelijk secretaris; diner & overnachting nabij locatie"),
        ("Opening", "Registratie open vanaf 1 uur voor aanvang (art. 3.1 HR); stemkaarten & stembiljetten uitrekken"),
        ("Vlaggenceremonie", "USA → buitenlandse gasten (volgorde belangrijkheid) → Nederland; volksliederen"),
        ("Herdenking", "Herdenken overleden Lions (vaste agenda-item voorjaarsconventie)"),
        ("Agenda vaststellen", "Incl. late ingediende moties/resoluties (art. 7.2-3 HR)"),
        ("Verslag DG", "Voortgang werkplan; financiële stand"),
        ("Verkiezingen", "Presentaties kandidaten (max 5 min elk, art. 11 HR); stemming via stembiljetten (art. 17 HR); herstemmingen indien nodig (art. 13 HR)"),
        ("Werkplan & Begroting inkomende GR", "Presentatie + toelichting; stemming"),
        ("Overige agendapunten", "Resoluties, moties, adviseur raad van advies (art. 5 HR)"),
        ("Sluiting", "Gezamenlijke borrel voor alle conventiegangers (vaste traditie voorjaarsconventie)"),
    ]
    for moment, actie in exec_steps:
        add_bullet(doc, actie, bold_prefix=f"{moment}: ")

    # Fase C: Evaluatie
    add_heading_styled(doc, "Fase C — Evaluatie & Afronding (T+1 tot T+4 weken)", level=2)
    eval_steps = [
        ("T+1 wk", "Notulen finaliseren door ambtelijk secretaris; besluitenlijst opstellen"),
        ("T+2 wk", "Stemuitslagen & quorum-verificatie archiveren (stembureau-verslag)"),
        ("T+2 wk", "Financiële afsluiting conventie; vergelijking met budget"),
        ("T+3 wk", "Evaluatiebijeenkomst organiserend comité + DG; lessen geleerd vastleggen"),
        ("T+4 wk", "Definitieve notulen & besluitenlijst ter vaststelling volgende kabinetsvergadering (art. 21.4 HR)"),
        ("Continue", "Archivering in ownCloud / LionsBase; overdracht aan volgende organiserende club (roulatie)"),
    ]
    for moment, actie in eval_steps:
        add_bullet(doc, actie, bold_prefix=f"{moment}: ")

    doc.add_page_break()

    # ── HOOFDSTUK 3: ROLLEN & VERANTWOORDELIJKHEIDEN (RACI) ───────────────
    add_heading_styled(doc, "3. Rollen & Verantwoordelijkheden (RACI)", level=1)
    add_body_text(doc, (
        "R = Responsible (uitvoert), A = Accountable (eindverantwoordelijk), "
        "C = Consulted (adviseert), I = Informed (geïnformeerd)."
    ), italic=True)

    raci_data = [
        ["Activiteit", "DG", "1e VDG", "2e VDG", "Ambt. Secretaris", "Organiserende Club(s)", "Stembureau", "Gouverneursraad", "Clubs"],
        ["Locatie & datum vaststellen", "A", "R", "C", "I", "R", "I", "C", "I"],
        ["Budget opstellen & bewaken", "A", "R", "I", "C", "R", "I", "I", "I"],
        ["Oproeping & agenda versturen", "A", "I", "I", "R", "C", "I", "C", "I"],
        ["Registratieproces beheren", "I", "I", "I", "A", "R", "C", "I", "I"],
        ["Stembureau benoemen", "I", "I", "I", "C", "I", "I", "A/R", "I"],
        ["Voorstellen & moties innen", "A", "C", "C", "R", "I", "I", "C", "R"],
        ["Conventiestukken distribueren", "I", "I", "I", "A/R", "I", "I", "I", "I"],
        ["Vlaggenceremonie organiseren", "A", "R", "C", "I", "R", "I", "I", "I"],
        ["Verkiezingen leiden", "A", "C", "C", "C", "I", "R", "I", "I"],
        ["Notulen & besluitenlijst", "A", "I", "I", "R", "I", "I", "C", "I"],
        ["Financiële afsluiting", "A", "R", "I", "C", "R", "I", "I", "I"],
        ["Evaluatie & lessen geleerd", "A/R", "R", "R", "R", "R", "C", "I", "I"],
    ]
    add_table_with_style(doc, len(raci_data), len(raci_data[0]), raci_data,
                         col_widths=[4.5, 1.5, 1.5, 1.5, 2.0, 2.0, 1.5, 1.5, 1.5])

    doc.add_paragraph()
    add_body_text(doc, (
        "Opmerking: De ambtelijk secretaris fungeert als vaste vraagbaak voor de GR en aanspreekpunt voor de "
        "conventievoorzitter in verband met registratie en notulering (Handboek §3.1). De DG is de 'linking pin' "
        "samen met de ambtelijk secretaris voor de organisatie."
    ), italic=True)

    doc.add_page_break()

    # ── HOOFDSTUK 4: DOCUMENTEN & TEMPLATES ───────────────────────────────
    add_heading_styled(doc, "4. Documenten & Templates", level=1)

    add_heading_styled(doc, "4.1 Verplichte conventiestukken (art. 2, 4, 6, 7 HR)", level=2)
    templates = [
        ("Oproeping (min. 30 dagen van tevoren)", "Datum, tijd, locatie, agenda, voorstellen, registratietermijnen, good-standing vereiste"),
        ("Agenda", "Alle te behandelen onderwerpen incl. vaststelling agenda, herdenking, verkiezingen, werkplan/begroting, resoluties/moties"),
        ("Voorstellen gouverneursraad", "Conceptbesluiten met toelichting (art. 4.1 HR)"),
        ("Clubvoorstellen", "Schriftelijk conceptbesluit + toelichting (art. 4.2-3 HR)"),
        ("Amendementen", "Uiterlijk 20 dagen voor conventie ingediend (art. 7.1 HR)"),
        ("Resoluties & moties", "Schriftelijk ingediend; deadline 20 dagen voor digitaal versturen (art. 6-7 HR)"),
        ("Adviezen raad van advies", "Schriftelijk of mondeling; uiterlijk 7 dagen voor conventie verzonden (art. 5 HR)"),
        ("Kandidaatstellingen DG/VDG", "Schriftelijk, uiterlijk 30 dagen voor conventie, via districtsconventie (art. 10 HR)"),
        ("Stemkaarten & stembiljetten", "Voor zaken respectievelijk personen; gewaarmerkt voor herstemmingen (art. 3, 17 HR)"),
        ("Registratielijsten", "Stemgerechtigden, niet-stemgerechtigden, aanwezige clubs (art. 3.4 HR)"),
        ("Notulen & besluitenlijst", "Binnen 14 dagen na conventie (art. 21.4 HR)"),
        ("Stembureau-verslag", "Tellingen, quorum-verificatie, uitslagen (art. 15-16 HR)"),
    ]
    tpl_data = [["Document", "Beschrijving / Inhoud", "Deadline / Basis"]]
    for i, (doc_name, desc) in enumerate(templates):
        deadline = ""
        if "30 dagen" in desc:
            deadline = "T-30 dagen"
        elif "20 dagen" in desc:
            deadline = "T-20 dagen"
        elif "7 dagen" in desc:
            deadline = "T-7 dagen"
        elif "14 dagen na" in desc:
            deadline = "T+14 dagen"
        tpl_data.append([doc_name, desc, deadline])
    add_table_with_style(doc, len(tpl_data), 3, tpl_data, col_widths=[5, 10, 3])

    add_heading_styled(doc, "4.2 Interne werkdocumenten (niet voor distributie)", level=2)
    intern_data = [
        ["Document", "Doel", "Beheerder"],
        ["Projectplan conventie", "Tijdlijnen, budget, takenverdeling", "DG / Ambt. Secretaris"],
        ["Risico-analyse & mitigatie", "Scenario's (locatie, quorum, techniek)", "Organiserend comité"],
        ["Communicatieplan", "Invitaties, herinneringen, social media", "Commissie Communicatie"],
        ["Logistiek runbook", "Zaalindeling, AV, catering, vlaggen, protocol", "Organiserende club(s)"],
        ["Stembureau-instructies", "Procedures telling, quorum, ongeldige stemmen", "Voorzitter stembureau"],
        ["Evaluatierapport", "Lessen geleerd voor volgende roulatie", "DG / Ambt. Secretaris"],
    ]
    add_table_with_style(doc, len(intern_data), 3, intern_data, col_widths=[5, 8, 5])

    doc.add_page_break()

    # ── HOOFDSTUK 5: KWALITEITSCONTROLES ──────────────────────────────────
    add_heading_styled(doc, "5. Kwaliteitscontroles", level=1)

    add_heading_styled(doc, "5.1 Voorafgaande controles (Go/No-Go momenten)", level=2)
    qc_pre = [
        ["Moment", "Controle", "Verantwoordelijke", "Acceptatiecriterium"],
        ["T-30 dagen", "Oproeping verzonden aan alle clubs / Lions / Leoclubs", "Ambt. Secretaris", "Bewijs verzending (e-mail / post)"],
        ["T-20 dagen", "Conventiestukken digitaal beschikbaar", "Ambt. Secretaris", "Alle voorstellen, amendementen, adviezen in ownCloud"],
        ["T-14 dagen", "Registraties ingestroomd; stemgerechtigden per club bekend", "Registratiebureau", "Min. 50% clubs aangemeld (quorum-indicator)"],
        ["T-7 dagen", "Stembureau benoemd & geïnstrueerd", "DG / Gouverneursraad", "Voorzitter + leden bekrachtigd; instructies ondertekend"],
        ["T-3 dagen", "Logistiek check: zaal, AV, vlaggen, stemmateriaal, catering", "Organiserende club", "Runbook 100% compleet"],
        ["T-1 dag", "Laatste registratielijst; stemkaarten/stembiljetten geteld", "Registratiebureau / Stembureau", "Aantallen kloppen met voorbereiding"],
    ]
    add_table_with_style(doc, len(qc_pre), 4, qc_pre, col_widths=[2.5, 6, 3.5, 5.5])

    add_heading_styled(doc, "5.2 Controles tijdens de conventie", level=2)
    qc_during = [
        ["Moment", "Controle", "Verantwoordelijke", "Acceptatiecriterium"],
        ["Opening registratie", "Registratiebureau operationeel vanaf 1 uur voor aanvang", "Registratiebureau", "Alle materialen klaar; lijst up-to-date"],
        ["Quorum check opening", "Aantal stemgerechtigden ≥ 50% van totaal", "Voorzitter stembureau", "Quorum behaald → conventie geldig geopend"],
        ["Elke stemming", "Telling procedure gevolgd (visueel of fysiek)", "Stembureau", "Art. 16 HR nageleefd; resultaat vastgelegd"],
        ["Verkiezingen", "Stembiljetten gewaarmerkt; max 1 naam aangekruist", "Stembureau", "Geen ongeldige stemmen door procediefouten"],
        ["Herstemming", "Afzonderlijk herstemmingsbiljet gebruikt (art. 17.3 HR)", "Stembureau", "Proceduur correct uitgevoerd"],
    ]
    add_table_with_style(doc, len(qc_during), 4, qc_during, col_widths=[2.5, 5, 3.5, 6.5])

    add_heading_styled(doc, "5.3 Nacontrôles & archivering", level=2)
    qc_post = [
        ["Moment", "Controle", "Verantwoordelijke", "Acceptatiecriterium"],
        ["T+1 wk", "Notulen compleet & besluitenlijst opgesteld", "Ambt. Secretaris", "Alle besluiten genummerd & gedateerd"],
        ["T+2 wk", "Financiële afsluiting conventie", "Penningmeester / DG", "Budget vs. realisatie; afwijkingen toegelicht"],
        ["T+3 wk", "Evaluatierapport opgeleverd", "DG / Organiserend comité", "Lessen geleerd gecategoriseerd (logistiek, proces, communicatie)"],
        ["T+4 wk", "Archivering ownCloud / LionsBase", "Ambt. Secretaris", "Alle stukken (versiebeheerd) opgeslagen"],
        ["T+8 wk", "Overdracht aan volgende organiserende club (roulatie)", "DG / Ambt. Secretaris", "Complete overdrachtsmap incl. evaluatierapport"],
    ]
    add_table_with_style(doc, len(qc_post), 4, qc_post, col_widths=[2.5, 6, 3.5, 5.5])

    doc.add_page_break()

    # ── HOOFDSTUK 6: AFWIJKINGEN & ESCALATIE ──────────────────────────────
    add_heading_styled(doc, "6. Afwijkingen & Escalatie", level=1)

    add_heading_styled(doc, "6.1 Afwijkingen van deze procedure", level=2)
    add_body_text(doc, (
        "Elke afwijking van de beschreven processen, termijnen of verantwoordelijkheden moet worden vastgelegd, "
        "beoordeeld op impact en goedgekeurd volgens onderstaand escalatiepad."
    ))
    add_bullet(doc, "Afwijking vastleggen in schrijvend (e-mail of formulier) met: omschrijving, oorzaak, impact, voorgestelde oplossing.")
    add_bullet(doc, "Beoordeling impact: Laag (geen risico op geldigheid conventie) / Middelmatig (vertraging of extra werk) / Hoog (risico op quorum, geldigheid stemming, juridische aanvechtbaarheid).")
    add_bullet(doc, "Goedkeuring volgens escalatieniveau (zie 6.2).")
    add_bullet(doc, "Registratie in conventie-archief met beslissing en handtekening goedkeurder.")

    add_heading_styled(doc, "6.2 Escalatiepad", level=2)
    escalation = [
        ["Niveau", "Rol", "Bevoegdheid", "Responstermijn", "Voorbeelden"],
        ["1", "Ambtelijk Secretaris / Projectleider organisatie", "Afwijkingen Laag", "24 uur", "Kleine agenda-wijziging, logistieke detail"],
        ["2", "District Governor (conventievoorzitter)", "Afwijkingen Middelmatig", "4 uur (op conventiedag: direct)", "Termijnoverschrijding oproeping, wijziging stemproceduur"],
        ["3", "Gouverneursraad (voorzitter GR)", "Afwijkingen Hoog / fundamentele procedures", "Binnen vergadering / 24 uur", "Quorum niet behaald, aanvechtbaarheid stemming, statutaire afwijking"],
        ["4", "Conventie (plenaire vergadering)", "Statutaire / HR-wijzigingen, ordevoorstellen", "Direct tijdens conventie", "Art. 18 HR: gevallen niet voorzien in reglement"],
    ]
    add_table_with_style(doc, len(escalation), 5, escalation, col_widths=[1.2, 3.5, 3.5, 3, 5.5])

    add_heading_styled(doc, "6.3 Specifieke risicoscenario's & maatregelen", level=2)
    risks = [
        ("Quorum niet behaald bij opening",
         "Actieve herinneringen clubs (T-14, T-7, T-3); stimuleren aangifte stemgerechtigde (art. 2.2 HR); "
         "naderhand mogelijkheid conventie aanschorten en hervatten (art. 18 HR)."),
        ("Ongeldige stemmen bij verkiezingen",
         "Duidelijke instructies op stembiljet; stembureau-leden per blok; voorbeeld biljet tonen bij opening; "
         "herstemmingsbiljetten voorbereid (art. 17 HR)."),
        ("Late ingediende moties/resoluties",
         "Proceduur art. 7.2-3 HR volgen: stemming over plaatsing op agenda zonder discussie; bij ontvangst tijdens conventie directe stemming over behandeling."),
        ("Technische storing registratie/stemming",
         "Papieren backup stemkaarten/stembiljetten; handmatige telling mogelijk (art. 16.2 HR); "
         "reserve laptops/printers op locatie."),
        ("Internationale gasten afwezig / visa-issues",
         "Vroegtijdige uitnodiging (T-6 mnd); duidelijke afspraken spreektijd/voertaal; "
         "reserve-programma zonder gasten."),
    ]
    for title, desc in risks:
        add_bullet(doc, desc, bold_prefix=f"{title}: ")

    doc.add_page_break()

    # ── BIJLAGE A: CONTROLESET FEITEN ─────────────────────────────────────
    add_heading_styled(doc, "Bijlage A: Controleset Feiten (TierVerify §17)", level=1)
    add_body_text(doc, "Deze feiten MOETEN in alle deliverables consistent terugkomen:", italic=True)

    controleset = [
        ["Feit", "Waarde", "Bron"],
        ["District", DISTRICT, "District 110AN Club Health Assessment (sept 2025)"],
        ["Conventietype", CONVENTIE_TYPE, "Handboek Lions Conventies vs 06 20240729"],
        ["Datum", CONVENTIE_MAAND, "Conventie Roulatieschema / Werkplan AN 2026-2027"],
        ["Locatie", "Te bepalen op basis van roulatie (toerbeurt in district)", "Conventie Roulatieschema / Handboek §3.1"],
        ["Governance", GOVERNANCE, "Huishoudelijk Reglement MD 110 mei 2021"],
        ["Stemrechten", STEMRECHT_REGEL, "Huishoudelijk Reglement / LCI Statuten (art. 11)"],
        ["Quorum", QUORUM_REGEL, "Huishoudelijk Reglement (art. 15.4, 16 HR)"],
        ["Budget referentie", "Districtbegroting 25-26: post '1 Districtsconventie' € 3.500", "Districtbegroting 110 AN 25-26"],
        ["Voorzitter", "District Governor 2026-2027", "Werkplan AN 2026-2027 draft v1"],
        ["Secretaris", "Cabinet Secretary 2026-2027 / Ambtelijk Secretaris", "Werkplan AN 2026-2027 draft v1 / Handboek"],
        ["Thema FY 2026-2027", THEMA_2026_2027, "Werkplan AN 2026-2027 draft v1"],
        ["Vorige organisator", VORIGE_ORGANISATOR, "Werkplan AN 2025-2026"],
        ["Oproepingstermijn", "Minimaal 30 dagen van tevoren", "Art. 2.1 HR"],
        ["Registratie deadline stemgerechtigden", "Uiterlijk 48 uur voor aanvang conventie", "Art. 2.1 HR"],
        ["Club aangeeft stemgerechtigde", "Uiterlijk 24 uur voor aanvang conventie", "Art. 2.2 HR"],
        ["Kandidaatstelling deadline", "Uiterlijk 30 dagen voor conventie", "Art. 10.4 HR"],
        ["Voorstellen deadline digitaal versturen", "Uiterlijk 20 dagen voor conventie", "Art. 7.1 HR"],
        ["Advies raad van advies deadline", "Uiterlijk 7 dagen voor conventie", "Art. 5.1 HR"],
    ]
    add_table_with_style(doc, len(controleset), 3, controleset, col_widths=[5, 7, 5.5])

    doc.add_page_break()

    # ── BIJLAGE B: STEMRECHT BEREKENING PER CLUB ──────────────────────────
    add_heading_styled(doc, "Bijlage B: Stemrechtberekening per Club (Referentie: Club Health Assessment sept 2025)", level=1)
    add_body_text(doc, (
        "Regel: 1 stem per 10 leden (actief + buitengewoon + vrijgesteld + lid voor het leven + geaffilieerd), "
        "minimum 1, maximum 5 stemmen per club (conform LCI Statuten art. 11 / HR art. 19). "
        "Hieronder een indicatieve tabel op basis van ledenaantallen sept 2025."
    ), italic=True)

    # Sample berekening voor eerste 15 clubs uit de Club Health Assessment
    clubs_sample = [
        ("30740", "AALSMEER", 28, 3),
        ("57413", "AALSMEER OPHELIA", 26, 3),
        ("40649", "ABCOUDE BAAMBRUGGE", 27, 3),
        ("21347", "ALKMAAR", 8, 1),
        ("47289", "ALKMAAR PHOENIX", 12, 2),
        ("48550", "ALMERE HOST", 15, 2),
        ("105327", "ALMERE VERITAS", 17, 2),
        ("21349", "AMSTELVEEN", 7, 1),
        ("48437", "AMSTELVEEN DE AMSTEL", 18, 2),
        ("55110", "AMSTELVEEN MINGLE", 13, 2),
        ("21350", "AMSTERDAM 1 HOST ZUIDAS", 13, 2),
        ("62845", "AMSTERDAM GIJSBREGHT VAN AEMSTEL", 12, 2),
        ("119416", "AMSTERDAM 'T IJ", 15, 2),
        ("84293", "ANNA PAULOWNA", 24, 3),
        ("101134", "BADHOEVEDORP", 31, 4),
    ]
    stem_data = [["Club #", "Club Naam", "Leden (sept 2025)", "Stemmen (1/10, min1/max5)"]]
    for num, name, leden, stemmen in clubs_sample:
        stem_data.append([num, name, str(leden), str(stemmen)])
    add_table_with_style(doc, len(stem_data), 4, stem_data, col_widths=[2, 6, 3, 3.5])

    add_body_text(doc, "")
    add_body_text(doc, (
        "Let op: Definitieve stemrechtberekening gebeurt op basis van de ledenadministratie van het MD "
        "op de eerste dag van het verenigingsjaar (art. 25.1 HR) en de door clubs aangewezen stemgerechtigden "
        "(art. 2.2 HR). Deze tabel is indicatief op basis van Club Health Assessment data sept 2025."
    ), italic=True, size=Pt(9))

    # ── FOOTER / COLOPHON ─────────────────────────────────────────────────
    doc.add_page_break()
    add_heading_styled(doc, "Colofon", level=1)
    colofon_items = [
        f"Document: Procedure Voorjaarsconventie 2027 v1.0",
        f"District: {DISTRICT}",
        f"Datum aanmaak: {date.today().isoformat()}",
        f"Governance basis: {GOVERNANCE}",
        "Auteur: District Governor 2026-2027 / Ambtelijk Secretaris / Organiserend Comité",
        "Versiebeheer: v1.0 — initiële versie ter goedkeuring Gouverneursraad",
        "Volgende review: na evaluatie voorjaarsconventie 2027 (voor roulatie 2028)",
    ]
    for item in colofon_items:
        add_bullet(doc, item, bold_prefix=False)

    return doc


def main():
    output_path = "/root/projects/jg/2026-voorjaarsconventie-110an/working/Procedure_Voorjaarsconventie_2027_v1.0.docx"
    doc = build_document()
    doc.save(output_path)
    print(f"Document gegenereerd: {output_path}")


if __name__ == "__main__":
    main()