#!/usr/bin/env python3
"""
Generator voor Kennisdossier_Voorjaarsconventie_2027_v1.0.docx
District 110AN - Voorjaarsconventie April 2027
Type: Kennisdossier (samengevoegde kennis uit Meta-Dossier v1)
Alle feiten afkomstig uit Meta-Dossier v1 (working/meta-dossier_v1.json).
Controleset: District 110AN · April 2027 · alle feiten uit Meta-Dossier.
"""

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

# ── Constants (alleen feiten uit Meta-Dossier v1) ─────────────────────────
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!"
THEMA_2025_2026 = "Veelzijdigheid verbindt!"
BUDGET_POST = "EUR 3.500 (post '1 Districtsconventie', Districtbegroting 25-26)"
LEDEN_DISTRICT = "+/- 1.200 leden (Districtbegroting 110 AN 25-26)"
# JvG logo: 754x676 px, ratio 1.115:1 -> EMU-afmetingen 2.0 cm x 1.8 cm
LOGO_PATH = "/root/projects/jg/2026-voorjaarsconventie-110an/assets/logo_jvg.png"
LOGO_WIDTH_CM = 2.0
LOGO_HEIGHT_CM = 1.8


def set_cell_shading(cell, color_hex: str):
    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):
    heading = doc.add_heading(text, level=level)
    for run in heading.runs:
        run.font.color.rgb = RGBColor(0x00, 0x33, 0x66)
        run.font.name = 'Calibri'
    return heading


def add_body_text(doc, text: str, bold=False, italic=False, size=Pt(11), alignment=None):
    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):
    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):
    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)
    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)
    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)
    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):
    """JvG logo (754x676 px, ratio 1.115:1) rechtsboven in de header; EMU: 2.0 x 1.8 cm."""
    if os.path.exists(logo_path):
        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):
    style = doc.styles['Normal']
    font = style.font
    font.name = 'Calibri'
    font.size = Pt(11)
    font.color.rgb = RGBColor(0x33, 0x33, 0x33)
    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)


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

    # ── COVER ─────────────────────────────────────────────────────────────
    for _ in range(4):
        doc.add_paragraph()
    title = doc.add_paragraph(); title.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = title.add_run("KENNISDOSSIER VOORJAARSCONVENTIE 2027")
    r.font.size = Pt(28); r.font.bold = True
    r.font.color.rgb = RGBColor(0x00, 0x33, 0x66); r.font.name = 'Calibri'
    subtitle = doc.add_paragraph(); subtitle.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = subtitle.add_run(f"District {DISTRICT}  -  {CONVENTIE_MAAND}")
    r.font.size = Pt(16); r.font.color.rgb = RGBColor(0x00, 0x66, 0x99); r.font.name = 'Calibri'
    doc.add_paragraph()
    version = doc.add_paragraph(); version.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = version.add_run("Versie 1.0 - Kennisdossier (samengevoegde kennis uit Meta-Dossier v1)")
    r.font.size = Pt(12); r.font.italic = True
    r.font.color.rgb = RGBColor(0x66, 0x66, 0x66); r.font.name = 'Calibri'
    doc.add_paragraph(); doc.add_paragraph()
    gov = doc.add_paragraph(); gov.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = gov.add_run(f"Governance: {GOVERNANCE} - Handboek MD 110 Lions Conventies (vs 06, 29-07-2024)")
    r.font.size = Pt(10); r.font.color.rgb = RGBColor(0x66, 0x66, 0x66); r.font.name = 'Calibri'
    thema = doc.add_paragraph(); thema.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = thema.add_run(f'Jaarthema 2026-2027: "{THEMA_2026_2027}"')
    r.font.size = Pt(11); r.font.italic = True
    r.font.color.rgb = RGBColor(0x00, 0x66, 0x99); r.font.name = 'Calibri'
    doc.add_page_break()

    # ── DOCUMENTBEHEER ────────────────────────────────────────────────────
    add_heading_styled(doc, "Documentbeheer", level=1)
    add_heading_styled(doc, "Versiehistorie", level=2)
    versie_data = [
        ["Versie", "Datum", "Auteur", "Status / Wijziging"],
        ["1.0", date.today().isoformat(), "District 110AN - Conventiecommissie / Cabinet Secretary",
         "Initiele versie; kennis samengevoegd uit Meta-Dossier v1"],
    ]
    add_table_with_style(doc, len(versie_data), 4, versie_data, col_widths=[2, 3, 6.5, 6])
    add_heading_styled(doc, "Status document", level=2)
    add_bullet(doc, "Dit kennisdossier bundelt alle geverifieerde kennis uit het Meta-Dossier voor de organisatie van de voorjaarsconventie van District 110AN in april 2027.")
    add_bullet(doc, "Karakter: informatief en ondersteunend. Voor bindende kaders gelden het Beleidsdocument en de Procedure; bij conflicten zijn het Huishoudelijk Reglement MD 110 en het Handboek Lions Conventies leidend.")
    add_bullet(doc, "Bronvermelding: alle feiten in dit dossier zijn herleidbaar naar het Meta-Dossier v1 (zie hoofdstuk 5: Bronnenlijst, geannoteerd).")
    doc.add_page_break()

    # ── INHOUDSOPGAVE ─────────────────────────────────────────────────────
    add_heading_styled(doc, "Inhoudsopgave", level=1)
    for item in [
        "1. Management Samenvatting",
        "2. Methodiek",
        "3. Tier 1 & 2 Toetsing (Interne Procedures & Wetgeving)",
        "4. Tier 3 Markt Intelligence & Trends",
        "5. Bronnenlijst (Geannoteerd)",
        "Bijlage A: Controleset Feiten",
    ]:
        add_body_text(doc, item, bold=True)
    doc.add_page_break()

    # ── 1. MANAGEMENT SAMENVATTING ────────────────────────────────────────
    add_heading_styled(doc, "1. Management Samenvatting", level=1)
    add_body_text(doc, (
        f"Dit kennisdossier bundelt de geverifieerde kennis voor de organisatie van de "
        f"voorjaarsconventie (District Convention) van District {DISTRICT} in {CONVENTIE_MAAND}. "
        "De kennis is samengevoegd uit het Meta-Dossier v1, waarin elf brondocumenten "
        "(Tier 1 en Tier 2) zijn ontsloten via een map-reduce pipeline."
    ))
    add_heading_styled(doc, "1.1 Kernfeiten", level=2)
    kern = [
        ["Feit", "Waarde", "Bron"],
        ["District", DISTRICT + " (Multiple District 110 Nederland)", "Club Health Assessment 110AN (sept 2025)"],
        ["Conventietype", CONVENTIE_TYPE, "Handboek Lions Conventies vs 06"],
        ["Datum", CONVENTIE_MAAND + " (exacte datum conform roulatie)", "Conventie Roulatieschema"],
        ["Locatie", "Te bepalen op basis van roulatie", "Conventie Roulatieschema"],
        ["Governance", GOVERNANCE, "Huishoudelijk Reglement MD 110"],
        ["Stemrecht", STEMRECHT_REGEL, "HR / LCI Statuten"],
        ["Quorum", QUORUM_REGEL + " (meeste artikelen)", "Huishoudelijk Reglement"],
        ["Budgetreferentie", BUDGET_POST, "Districtbegroting 110 AN 25-26"],
        ["Voorzitter", "District Governor 2026-2027", "Werkplan AN 2026-2027 draft v1"],
        ["Jaarthema 2026-2027", THEMA_2026_2027, "Werkplan AN 2026-2027 draft v1"],
        ["Omvang district", LEDEN_DISTRICT, "Districtbegroting 110 AN 25-26"],
    ]
    add_table_with_style(doc, len(kern), 3, kern, col_widths=[4.5, 7, 6])
    add_heading_styled(doc, "1.2 Belangrijkste bevindingen", level=2)
    add_bullet(doc, "Tijdens de voorjaarsconventie deelt de zittende gouverneur de voortgang van het werkplan en worden de inkomende 2e VDG, 1e VDG en DG benoemd; de inkomende DG presenteert de plannen en begroting voor het volgende Lionsjaar (start 1 juli). (Handboek Lions Conventies, sectie 1.0)", bold_prefix="Statutair karakter: ")
    add_bullet(doc, "Oproeping ten minste 30 dagen vooraf (HR art. 2.1); aanmelding voor stemrecht uiterlijk 48 uur voor aanvang; aanwijzing stemgerechtigden door de club uiterlijk 24 uur voor aanvang (HR art. 2.1-2.2).", bold_prefix="Harde termijnen: ")
    add_bullet(doc, "Districtsconventies moeten 6 weken voor de nationale conventies worden gehouden, zodat punten nog tijdig (minimaal 30 dagen tevoren) kunnen worden ingebracht. (Handboek, sectie 1.1)", bold_prefix="Timing in landelijk kader: ")
    add_bullet(doc, "De districtssecretaris is de centrale regelaar: verzamelen van stukken, uitnodiging via de vergadermodule in het CMS, publicatie van agenda en stukken 30 dagen vooraf (site, uitnodiging, ownCloud), registratie bij de entree, badges, roll-call en stemmaterialen. (Handboek, sectie 1.1)", bold_prefix="Centrale rol secretariaat: ")
    add_bullet(doc, "De districtbegroting 25-26 reserveert 3.500 euro voor 1 Districtsconventie; de begroting kent 1.200 leden bij een contributie van 20 euro per lid. (Districtbegroting 110 AN 25-26)", bold_prefix="Financieel kader: ")
    add_bullet(doc, "De Leden Ontmoetingsavond van 17 oktober 2024 in Alkmaar trok 66 personen uit 20 clubs die samen 42 stemmen uitbrachten; het jaarverslag werd per acclamatie goedgekeurd met verlening van decharge; verkiezingen verliepen unaniem. (Verslag Najaarsconventie 110AN, 17-10-2024)", bold_prefix="Precedent uit 2024: ")
    add_bullet(doc, "Het Handboek signaleert een grotere rol voor hybride bijeenkomsten, locaties nabij OV-punten, vegetarisch aanbod, herbruikbare gadgets en minder papier. (Handboek, sectie 1.0)", bold_prefix="Maatschappelijke trends: ")
    add_heading_styled(doc, "1.3 Kennishiaten (Tier 3)", level=2)
    add_body_text(doc, (
        "Actuele marktdata (Tier 3, jonger dan 6 maanden) zijn nog niet verzameld: LCI Convention "
        "Guidelines (online), een database met Nederlandse event-locaties en horeca/catering-"
        "prijsindicaties 2026-2027. Deze hiaten zijn geagendeerd; zie hoofdstuk 4."
    ))
    doc.add_page_break()

    # (vervolg in deel 2: Methodiek, Tier 1 & 2 Toetsing)
    return _build_part2(doc)


def _build_part2(doc):
    # ── 2. METHODIEK ──────────────────────────────────────────────────────
    add_heading_styled(doc, "2. Methodiek", level=1)
    add_heading_styled(doc, "2.1 Gelaagde bronbenadering (tiers)", level=2)
    add_body_text(doc, (
        "De kennisverzameling hanteert een drielaagse bronhiërarchie. Bij conflicten is de hogere "
        "laag leidend. Alle bronnen zijn ontsloten in het Meta-Dossier v1."
    ))
    tiers = [
        ["Tier", "Categorie", "Betekenis", "Status Meta-Dossier v1"],
        ["Tier 1", "Interne Procedures & Governance (Leidend)",
         "Handboeken, reglementen, besluiten, werkplannen, begroting, verslagen",
         "10 brondocumenten ontsloten"],
        ["Tier 2", "Wetgeving & Externe Standaarden (Validatie)",
         "Gestructureerde externe data ter validatie van interne procedures",
         "1 bron ontsloten (districtsagenda 2026-2027, JSON)"],
        ["Tier 3", "Actuele Data & Trends (< 6 maanden)",
         "Marktintelligence: locaties, prijzen, actuele LCI-richtlijnen online",
         "Nog te verzamelen (3 bronnen geagendeerd)"],
    ]
    add_table_with_style(doc, len(tiers), 4, tiers, col_widths=[1.8, 4.7, 6.5, 4.5])
    add_heading_styled(doc, "2.2 Map-reduce pipeline", level=2)
    add_body_text(doc, (
        "Omdat het project meer dan 2 brondocumenten met samen meer dan 50.000 woorden betreft, "
        "was map-reduce verplicht (Fase 2.5, vóór deliverable-productie). Elke bron is per chunk "
        "geëxtraheerd (map), voorzien van een samenvatting en vervolgens samengevoegd tot het "
        "Meta-Dossier (reduce). Het Meta-Dossier bevat per bron: bronnaam, tier, tokenaantal, "
        "inhoud en samenvatting."
    ))
    add_bullet(doc, "11 kernbronnen geïndexeerd in het bronnenoverzicht (sources.md, onderdeel van Meta-Dossier v1)")
    add_bullet(doc, "22 content-items ontsloten (volledige extracts + samenvattingen per bron)")
    add_bullet(doc, "Ter verificatie van consistentie geldt de controleset feiten (Bijlage A), die in alle deliverables identiek moet terugkomen")
    add_heading_styled(doc, "2.3 Kwaliteitsborging van de kennis", level=2)
    add_bullet(doc, "Elk feit in dit dossier is herleidbaar naar een bron uit het Meta-Dossier (bronvermelding per tabel en per bullet).")
    add_bullet(doc, "Waar bronnen elkaar mogelijk tegenspreken, is de hogere tier leidend; conflicten zijn in dit dossier niet geconstateerd.")
    add_bullet(doc, "Namen van personen zijn alleen opgenomen waar ze vastliggen in de bron (verslag 2024, werkplan 2026-2027 draft).")
    doc.add_page_break()

    # ── 3. TIER 1 & 2 TOETSING ───────────────────────────────────────────
    add_heading_styled(doc, "3. Tier 1 & 2 Toetsing (Interne Procedures & Wetgeving)", level=1)
    add_body_text(doc, (
        "Dit hoofdstuk toetst de organisatie van de voorjaarsconventie 2027 aan de leidende "
        "interne procedures (Tier 1) en valideert met externe standaarden (Tier 2). Per bron "
        "wordt weergegeven welke eisen daaruit volgen voor de conventieorganisatie."
    ))

    add_heading_styled(doc, "3.1 Handboek MD 110 Lions Conventies (vs 06, 29-07-2024) - KERN", level=2)
    add_body_text(doc, (
        "Het Handboek is de officiële handleiding voor de organisatie van districtconventies en "
        "de primaire bron voor conventie-eisen. Kerneisen voor de voorjaarsconventie:"
    ))
    add_bullet(doc, "Doel voorjaarsconventie: voortgang werkplan zittende gouverneur; benoeming inkomende 2e VDG, 1e VDG en DG; presentatie plannen en begroting inkomende DG voor het Lionsjaar dat start op 1 juli. (sectie 1.0)")
    add_bullet(doc, "Districtsconventies moeten 6 weken vóór de nationale conventies worden gehouden (invoer punten minimaal 30 dagen tevoren). (sectie 1.1)")
    add_bullet(doc, "Controleer of de datum niet in een vakantie valt; verplaats nooit een eerder vastgestelde en gecommuniceerde datum. (sectie 1.1)")
    add_bullet(doc, "De districtssecretaris zorgt dat agenda en vergaderstukken een maand (30 dagen) voor de gekozen datum benaderbaar zijn via de site, een uitnodiging en de ownCloud. (sectie 1.1)")
    add_bullet(doc, "De districtssecretaris zit duidelijk zichtbaar bij de entree, noteert aanwezigen, deelt badges uit met naam en clubnaam, houdt inzicht in aanwezigen en stemgerechtigden en verzorgt de roll-call. (sectie 1.1)")
    add_bullet(doc, "Kleding dagelijks bestuur op elkaar afstemmen, liefst allen in tenue de ville inclusief actuele functiepin; koninklijke onderscheidingen mogen gedragen worden. (sectie 1.1)")
    add_bullet(doc, "Opkomststimulering: aantrekkelijke locatie met rondleiding, aansprekende spreker of actueel onderwerp; goede catering, aankleding, muzikale ondersteuning en een open, persoonlijke en warme ontvangst. Alleen een inspirerende (herhalings)mail is niet voldoemd; ook website, social media en zonevoorzitters actief inzetten. (sectie 1.0)")

    add_heading_styled(doc, "3.2 Huishoudelijk Reglement MD 110 (mei 2021) - Sectie 1 Conventiereglement", level=2)
    hr = [
        ["Artikel", "Vereiste", "Consequentie bij niet-naleving"],
        ["Art. 1", "Reglement is nadere uitwerking van de statuten van het MD ten aanzien van conventies", "Grondslagontbreken"],
        ["Art. 2.1", "Oproeping door de gouverneursraad ten minste 30 dagen voor de conventie aan clubs, clubs in oprichting, alle Lions en Leoclubs in het MD; omvat o.a. datum/tijd/locatie, agenda met alle onderwerpen, voorstellen/bijlagen, aanvangstijd registratie, vermelding good-standing-vereiste en 48-uurs-aanmeldingsregel", "Oproeping ongeldig / termijnschade"],
        ["Art. 2.1-2.2", "Aanmelding deelneming uiterlijk 48 uur voor aanvang voor stemrecht; club geeft uiterlijk 24 uur voor aanvang door wie namens de club stemgerechtigd is", "Club is niet stemgerechtigd"],
        ["Art. 2.3-2.4", "Lions niet als stemgerechtigde aangewezen: toegang zonder spreekrecht; leden van MD-organen en MD-stichtingen hebben spreekrecht", "Beperkte deelname"],
        ["Art. 3", "Registratie vanaf ten minste een uur voor opening tot de opening; stemkaart (zaken) en stembiljet (personen) per stemgerechtigde; stembiljetten voor herstemmingen; totaaltellingen (uit te brengen stemmen, stemgerechtigden, niet-stemgerechtigden, aanwezige clubs) zo spoedig mogelijk na sluiting registratie naar de voorzitter", "Stemming onregelmatig"],
        ["Art. 4", "Gouverneursraad legt eigen voorstellen voor (minimaal alle statutair voorgeschreven onderwerpen); elke club in good standing kan voorstellen indienen; alle voorstellen omvatten een schriftelijk conceptbesluit met toelichting", "Agendering onvolledig"],
        ["Art. 5", "Raad van advies kan over conventiestukken (taakstellend werkplan, begroting, jaarrekening, onkostenvergoedingsregeling) advies uitbrengen; schriftelijke adviezen tot zeven dagen voor aanvang worden zo snel mogelijk verzonden", "Adviesrecht geschonden"],
    ]
    add_table_with_style(doc, len(hr), 3, hr, col_widths=[2.2, 10.3, 5])
    add_bullet(doc, "Stemrecht: " + STEMRECHT_REGEL + "; quorum: " + QUORUM_REGEL + " (voor de meeste artikelen). (HR / LCI Statuten)")

    add_heading_styled(doc, "3.3 Conventie Roulatieschema (Gouverneursraad, 6-5-2022)", level=2)
    add_body_text(doc, (
        "Het roulatieschema van de landelijke voorjaarsconventies is op 6 mei 2022 vastgesteld "
        "door de Gouverneursraad. Relevante roulatie (landelijke voorjaarsconventies):"
    ))
    roul = [
        ["Seizoen", "Organiserend district"],
        ["2023-2024", "110CO"],
        ["2024-2025", "110BN"],
        ["2025-2026", "110AN"],
        ["2026-2027", "110AZ"],
        ["2027-2028", "110CW"],
        ["2028-2029", "110BZ"],
    ]
    add_table_with_style(doc, len(roul), 2, roul, col_widths=[4, 6])
    add_body_text(doc, (
        "Let wel: bovenstaand schema geldt de landelijke voorjaarsconventies. De districts-"
        "voorjaarsconventie van 110AN in april 2027 valt in Lionsjaar 2026-2027; de exacte datum "
        "en locatie worden conform het roulatieprincipe vastgesteld. Voor de kennisdeling geldt "
        "dat ervaringen worden overgedragen aan het volgend organiserende district."
    ), italic=True)

    add_heading_styled(doc, "3.4 Districtbegroting 110 AN 2025-2026 (financieel kader)", level=2)
    beg = [
        ["Post", "Bedrag", "Toelichting"],
        ["Aantal leden in district", "1.200", "Basis contributie-inkomsten"],
        ["Contributiebedrag leden", "EUR 20", "Per lid per jaar"],
        ["Inkomsten totaal", "EUR 24.500", "Waarvan contributie EUR 24.000 + rente EUR 500"],
        ["Uitgaven totaal", "EUR 29.500", "Inclusief bestuur, kabinet, zones, district, trainingen"],
        ["Saldo", "EUR -5.000", "Normative begroting vertoort een tekort"],
        ["Post '1 Districtsconventie'", "EUR 3.500", "Referentiebudget voor de conventie"],
        ["Overige districtsposten (context)", "EUR 3.000 Ledenontmoetings-/inspiratieavond; EUR 2.500 Stamppotavond MJF/PDG", "Ter vergelijking van omvang"],
    ]
    add_table_with_style(doc, len(beg), 3, beg, col_widths=[6, 3.5, 8])
    add_bullet(doc, "Conclusie: het referentiebudget voor de conventie is EUR 3.500; exploitatie dient deugdelijk te zijn (geen negatief eindresultaat voor het district).")

    add_heading_styled(doc, "3.5 Werkplan AN 2026-2027 (draft v1) - conventiejaar", level=2)
    add_bullet(doc, 'Jaarthema 2026-2027: "' + THEMA_2026_2027 + '", voortbouwend op het thema 2025-2026 "' + THEMA_2025_2026 + '" van voorganger Pieter Haex.')
    add_bullet(doc, "District AN omschrijft zichzelf als 'het kleinste maar meest vooruitstrevende district van MD 110'.")
    add_bullet(doc, "Kabinet 2026-2027 (per draft): DG (voorzitter), Pieter Haex (LC Amsterdam 't IJ) als IPDG, Martijn Wokke (Clubbranch Alkmaar Victorie) als VDG, alsmede 2e VDG, secretaris en penningmeester; daarnaast de Global Action Team (GLT/GST/GMT). Namen van DG, 2e VDG, secretaris en penningmeester zijn in de draft nog als placeholder opgenomen.")
    add_bullet(doc, "Themapijlers: duurzame relaties, duurzame projecten, duurzame groei (ledenbehoud en werving met focus op diversiteit), duurzame kennisdeling (training en mentorschap) en duurzame structuren.")
    add_bullet(doc, "Relevantie voor de conventie: op de voorjaarsconventie presenteert de inkomende DG dit werkplan met begroting ter goedkeuring (Handboek sectie 1.0).")

    add_heading_styled(doc, "3.6 Verslag Najaarsconventie 110AN (17 oktober 2024) - precedent", level=2)
    verslag = [
        ["Element", "Waarneming (verslag 17-10-2024)"],
        ["Locatie", "Stadscaffee Laurens, Kerkplein 9, 1811 KL Alkmaar"],
        ["Opkomst", "66 personen, uit 20 clubs, samen 42 stemmen"],
        ["Stembureau", "Joost Paijmans (LC Lisse De Oude Duinen) en districtssecretaris Esmee Bon-Duijn (Clubbranch Almere Veritas Venus)"],
        ["Notulen", "Verslag najaarsconventie 19-10-2023 zonder vragen goedgekeurd"],
        ["Financiele verantwoording", "Jaarverslag FY 2023-2024 toegelicht door penningmeester ad interim Pieter Haex; positief advies Kascommissie (Martijn Eelman); goedkeuring jaarverslag en decharge per acclamatie"],
        ["Verkiezingen", "Kandidaat 2VDG Jorick van Gemert (Clubbranch Alkmaar Victorie), kandidaat penningmeester Harrie Welmer (LC Den Helder) en kandidaat kascommissielid Nienke Budde (LC Amsterdam Gijsbrecht v Aemstel) unaniem verkozen"],
        ["Informeel", "Best Club Project Award gewonnen door LC Lisse de Oude Duinen"],
        ["Notulist", "Esmee Bon-Duijn, districtssecretaris (verslag gedateerd 1 november 2024)"],
    ]
    add_table_with_style(doc, len(verslag), 2, verslag, col_widths=[5, 12.5])
    add_bullet(doc, "Les voor 2027: dit model (stembureau, roll-call, per acclamatie goedkeuren waar mogelijk, gekoppelde verkiezingen, informeel programma met award) is het werkende precedent binnen 110AN.")

    add_heading_styled(doc, "3.7 Overige Tier 1 bronnen (context)", level=2)
    overig = [
        ["Bron", "Relevantie", "Kernpunt"],
        ["Werkplan AN 2025-2026", "MIDDEL - context huidig werkjaar", "Thema 'Veelzijdigheid verbindt!'; activiteiten en commissies van het huidige jaar"],
        ["Lions 110AN Werkplan 2024-2025 (v1.0)", "MIDDEL - commissiestructuur", "Motto 'Groen Groei Groots'; taken- en verantwoordelijkhedenstructuur"],
        ["2024-2025 MD110 Werkplan Gouverneursraad", "MIDDEL - MD-coördinatie", "Werkplan Gouverneursraad op MD-niveau; afstemming landelijke agenda"],
        ["District 110AN Club Health Assessment (sept 2025)", "HOOG - districtcontext", "Ledenaantallen en clubstatus per club; basis voor stemrechtberekening (1 stem per 10 leden)"],
    ]
    add_table_with_style(doc, len(overig), 3, overig, col_widths=[6.5, 4.5, 6.5])

    add_heading_styled(doc, "3.8 Tier 2 - Validatie met externe standaarden", level=2)
    add_body_text(doc, (
        "Als Tier 2-bron is de gestructureerde districtsagenda 2026-2027 (JSON, geparsed uit "
        "Kalender_110AN_2026-2027_final_jg_werkbestand.xlsx) gebruikt ter validatie van de "
        "planning in het conventiejaar. De agenda bevat 70 items met datums en signalen."
    ))
    t2 = [
        ["Validatiepunt", "Waarneming uit agenda 2026-2027", "Consequentie voor conventie"],
        ["Kabinetsoverdracht", "15 augustus 2026", "Start Lionsjaar 2026-2027; conventie valt daarna (april 2027)"],
        ["Internationale conventie", "LionsCon Hong Kong (juli 2026, 2 agendadagen)", "Internationale agenda meewegen in datakeuze; geen botsing"],
        ["Bestuursvergaderingen", "O.a. DB-vergadering digitaal (4 aug 2026), vast ritme", "Conventievoorbereiding afstemmen op DB-vergaderingen"],
        ["Signalen", "Elk item kent 4 voorafgaande signaalmomenten", "Neem signaalmomenten op in de conventie-tijdlijn (T-mijlpalen)"],
    ]
    add_table_with_style(doc, len(t2), 3, t2, col_widths=[4, 7, 6.5])
    add_bullet(doc, "Conclusie Tier 2: de districtsagenda bevestigt dat april 2027 vrij ligt van direct botsende vaste districtsmomenten; de kabinetsoverdracht (15-8-2026) gaat ruim vooraf.")
    doc.add_page_break()

    # ── 4. TIER 3 MARKT INTELLIGENCE & TRENDS ────────────────────────────
    add_heading_styled(doc, "4. Tier 3 Markt Intelligence & Trends", level=1)
    add_heading_styled(doc, "4.1 Gedocumenteerde trends (uit Handboek, sectie 1.0)", level=2)
    add_body_text(doc, (
        "Het Handboek MD 110 Lions Conventies benoemt expliciet ontwikkelingen die in de toekomst "
        "een grotere rol gaan spelen bij conventies. Deze trends zijn de enige in Tier 1/2 "
        "gedocumenteerde marktintelligence en vormen de verbinding naar de nog te verzamelen Tier 3-data."
    ))
    trends = [
        ["Trend", "Implicatie voor organisatie", "Bron"],
        ["Hybride bijeenkomsten", "Vereist locatie met streaming/opnamemogelijkheden en een hybride registratie- en stemproces", "Handboek 1.0"],
        ["Locatie nabij OV-punt", "Bereikbaarheid weegt zwaarder in locatiekeuze", "Handboek 1.0"],
        ["Vegetarisch aanbod", "Catering moet standaard volwaardig vegetarisch aanbod omvatten", "Handboek 1.0"],
        ["Herbruikbare gadgets", "Afscheid van wegwerppromotie; duurzaam relatiegeschenk", "Handboek 1.0"],
        ["Minder papier", "Digitale stukkenverzorging (ownCloud/site) in plaats van papieren map", "Handboek 1.0"],
    ]
    add_table_with_style(doc, len(trends), 3, trends, col_widths=[4.5, 9, 4])
    add_heading_styled(doc, "4.2 Opkomststimulering (bewezen hefbomen)", level=2)
    add_bullet(doc, "Aantrekkelijke locatie met rondleiding", bold_prefix="Programma: ")
    add_bullet(doc, "Aansprekende spreker of actueel onderwerp", bold_prefix="Inhoud: ")
    add_bullet(doc, "Goede catering, aankleding, muzikale ondersteuning", bold_prefix="Beleving: ")
    add_bullet(doc, "Open, persoonlijke en warme ontvangst", bold_prefix="Hospitality: ")
    add_bullet(doc, "Niet alleen een inspirerende herhalingsmail, maar ook website, social media en zonevoorzitters actief inzetten", bold_prefix="Communicatie: ")
    add_heading_styled(doc, "4.3 Status en actiepunten Tier 3 (nog te verzamelen)", level=2)
    add_body_text(doc, (
        "De volgende actuele bronnen zijn in het bronnenoverzicht als Tier 3 geagendeerd maar "
        "(nog) niet verzameld; ze vallen buiten de feitenbasis van dit dossier."
    ))
    t3 = [
        ["Bron", "Type", "Status", "Doel"],
        ["LCI Convention Guidelines (online)", "Web", "Te raadplegen", "Actualiteit LCI-eisen toetsen tegen Handboek vs 06"],
        ["Nederlandse event-locaties database", "Web", "Te raadplegen", "Locatie-longlist op basis van zaalcapaciteit, OV-bereikbaarheid, hybride faciliteiten"],
        ["Horeca/catering prijsindicaties 2026-2027", "Web", "Te raadplegen", "Budgettoets aan EUR 3.500 referentie en deelnemersbijdrage"],
    ]
    add_table_with_style(doc, len(t3), 4, t3, col_widths=[5.5, 2, 3, 7])
    add_body_text(doc, (
        "Advies: verzamel deze Tier 3-bronnen uiterlijk 9 maanden voor de conventiedatum, zodat "
        "locatie- en cateringkeuzes op actuele data kunnen worden gebaseerd (uitwerking in het "
        "Projectplan PVA)."
    ), italic=True)
    doc.add_page_break()

    # ── 5. BRONNENLIJST (GEANNOTEERD) ────────────────────────────────────
    add_heading_styled(doc, "5. Bronnenlijst (Geannoteerd)", level=1)
    add_body_text(doc, (
        "Alle onderstaande bronnen zijn opgenomen in het Meta-Dossier v1 (map-reduce pipeline). "
        "Annotaties geven het gebruik van elke bron in dit kennisdossier weer."
    ))
    add_heading_styled(doc, "5.1 Tier 1 - Interne Procedures & Governance (Leidend)", level=2)
    bronnen1 = [
        ["#", "Bron", "Type", "Relevantie", "Gebruik in dit dossier"],
        ["1", "Handboek Lions Conventies vs 06 (29-07-2024)", "PDF (LCI-handleiding)", "KERN", "Conventie-eisen, doel voorjaarsconventie, rol districtssecretaris, trends (h3.1, h4.1, h4.2)"],
        ["2", "Conventie Roulatieschema (GR, 06-05-2022)", "DOCX", "HOOG", "Roulatietabel landelijke voorjaarsconventies 2023-2024 t/m 2028-2029 (h3.3)"],
        ["3", "Huishoudelijk Reglement MD 110 mei 2021", "PDF", "HOOG", "Sectie 1 Conventiereglement art. 1-5: oproeping, stemrecht, registratie, voorstellen, adviesrecht (h3.2)"],
        ["4", "District 110AN (1).pdf - Club Health Assessment (sept 2025)", "PDF", "HOOG", "Districtcontext; club- en ledengegevens als basis stemrechtberekening (h1.1, h3.7)"],
        ["5", "Verslag Najaarsconventie 110AN (17-10-2024)", "DOCX", "HOOG", "Precedent: opkomst 66/20 clubs/42 stemmen, stembureau, decharge, verkiezingen (h3.6)"],
        ["6", "Werkplan AN 2025-2026", "PDF", "MIDDEL", "Context huidig werkjaar; thema 'Veelzijdigheid verbindt!' (h3.7)"],
        ["7", "Werkplan AN 2026-2027 draft v1", "DOCX", "HOOG", "Conventiejaar: thema 'Samen verder bouwen!', kabinet, themapijlers (h3.5)"],
        ["8", "Lions 110AN Werkplan 2024-2025 v1.0", "DOCX", "MIDDEL", "Commissiestructuur; motto 'Groen Groei Groots' (h3.7)"],
        ["9", "2024-2025 MD110 Werkplan Gouverneursraad", "PDF", "MIDDEL", "MD-coördinatie en landelijke afstemming (h3.7)"],
        ["10", "Districtbegroting 110 AN 25-26", "PDF", "MIDDEL", "Financieel kader: 1.200 leden, EUR 20 contributie, EUR 3.500 conventiepost (h3.4)"],
    ]
    add_table_with_style(doc, len(bronnen1), 5, bronnen1, col_widths=[0.8, 5.2, 2.2, 1.7, 7.6])
    add_heading_styled(doc, "5.2 Tier 2 - Wetgeving & Externe Standaarden (Validatie)", level=2)
    bronnen2 = [
        ["#", "Bron", "Type", "Relevantie", "Gebruik in dit dossier"],
        ["11", "agenda-110AN-2026-2027.json (uit Kalender 110AN 2026-2027, sheet 110AN werkversie)", "JSON", "HOOG", "Validatie planning: 70 items, Kabinetsoverdracht 15-08-2026, LionsCon Hong Kong, signaalmomenten (h3.8)"],
    ]
    add_table_with_style(doc, len(bronnen2), 5, bronnen2, col_widths=[0.8, 5.2, 2.2, 1.7, 7.6])
    add_heading_styled(doc, "5.3 Tier 3 - Actuele Data & Trends (nog te verzamelen)", level=2)
    bronnen3 = [
        ["#", "Bron", "Type", "Status", "Gebruik in dit dossier"],
        ["12", "LCI Convention Guidelines (online)", "Web", "Te raadplegen", "Alleen als hiaat benoemd (h4.3); geen feiten overgenomen"],
        ["13", "Nederlandse event-locaties database", "Web", "Te raadplegen", "Alleen als hiaat benoemd (h4.3); geen feiten overgenomen"],
        ["14", "Horeca/catering prijsindicaties 2026-2027", "Web", "Te raadplegen", "Alleen als hiaat benoemd (h4.3); geen feiten overgenomen"],
    ]
    add_table_with_style(doc, len(bronnen3), 5, bronnen3, col_widths=[0.8, 5.2, 2.2, 1.7, 7.6])
    add_body_text(doc, (
        "Volledigheid: het Meta-Dossier bevat daarnaast per bron automatische samenvattingen "
        "(document_summary) en een contentindex met tokenaantallen; deze zijn voor de "
        "leesbaarheid niet afzonderlijk in deze bronnenlijst opgenomen."
    ), italic=True, size=Pt(9))
    doc.add_page_break()

    # ── BIJLAGE A: CONTROLESET FEITEN ────────────────────────────────────
    add_heading_styled(doc, "Bijlage A: Controleset Feiten (TierVerify)", 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 + " (exacte datum conform roulatie)", "Conventie Roulatieschema"],
        ["Locatie", "Conform roulatieschema (GR, vastgesteld 6 mei 2022)", "Conventie Roulatieschema"],
        ["Governance", GOVERNANCE, "Huishoudelijk Reglement MD 110 mei 2021"],
        ["Stemrechten", STEMRECHT_REGEL, "Huishoudelijk Reglement / LCI Statuten"],
        ["Quorum", QUORUM_REGEL, "Huishoudelijk Reglement"],
        ["Budget referentie", "Districtbegroting 25-26: post '1 Districtsconventie' EUR 3.500", "Districtbegroting 110 AN 25-26"],
        ["Voorzitter", "District Governor 2026-2027", "Werkplan AN 2026-2027 draft v1"],
        ["Secretaris", "Cabinet Secretary 2026-2027", "Werkplan AN 2026-2027 draft v1"],
        ["Thema FY 2026-2027", THEMA_2026_2027, "Werkplan AN 2026-2027 draft v1"],
        ["Thema FY 2025-2026", THEMA_2025_2026, "Werkplan AN 2025-2026 / Werkplan AN 2026-2027 draft"],
        ["Leden district (referentie)", "+/- 1.200 (Districtbegroting 25-26)", "Districtbegroting 110 AN 25-26"],
    ]
    add_table_with_style(doc, len(controleset), 3, controleset, col_widths=[5, 7, 5.5])
    doc.add_page_break()

    # ── COLOFON ───────────────────────────────────────────────────────────
    add_heading_styled(doc, "Colofon", level=1)
    for item in [
        "Document: Kennisdossier Voorjaarsconventie 2027 v1.0",
        "District: " + DISTRICT,
        "Datum aanmaak: " + date.today().isoformat(),
        "Kennisbasis: Meta-Dossier v1 (map-reduce pipeline, 11 kernbronnen)",
        "Governance basis: " + GOVERNANCE + " - Handboek MD 110 Lions Conventies (vs 06, 29-07-2024)",
        "Auteur: District 110AN - Conventiecommissie / Cabinet Secretary",
        "Volgende review: na aanvulling Tier 3-bronnen dan wel bij actualisatie Meta-Dossier",
    ]:
        add_bullet(doc, item)

    return doc


def main():
    output_path = "/root/projects/jg/2026-voorjaarsconventie-110an/deliverables/docx/Kennisdossier_Voorjaarsconventie_2027_v1.0.docx"
    os.makedirs(os.path.dirname(output_path), exist_ok=True)
    doc = build_document()
    doc.save(output_path)
    print(f"Document gegenereerd: {output_path}")


if __name__ == "__main__":
    main()
