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

Excel-checklist (openpyxl) met corporate huisstijl, 6 tabs:
  1) Voorbereiding (T-12 t/m T-1 maand)
  2) Locatie & Logistiek
  3) Agenda & Sprekers
  4) Inschrijving & Communicatie
  5) Dagself (Setup / Registratie / Programma / Afsluiting)
  6) Evaluatie & Opvolging

Kolommen per taak:
  ID | Fase | Categorie | Taak | Verantwoordelijke | Deadline | Status | Opmerkingen | Afhankelijkheden

Bronnen (alleen feiten uit Meta-Dossier, working/meta-dossier_v1.json):
- Handboek Lions Conventies vs 06 20240729 (organisatie, logistiek, vlaggen, hospitality, PR)
- Huishoudelijk Reglement MD 110 mei 2021 (oproeping, stemmateriaal, termijnen, stembureau)
- Werkplan AN 2026-2027 draft v1 / Werkplan AN 2025-2026
- Conventie Roulatieschema (GR-vaststelling 6-5-2022)
- Districtbegroting 110 AN 25-26 (post '1 Districtsconventie' EUR 3.500)
- Verslag Najaarsconventie 110AN 2024 (lessen)
- agenda-110AN-2026-2027.json (distrikkalender)

Controleset (MOET consistent in alle deliverables):
District 110AN - Voorjaarsconventie April 2027 -
Agendapunten incl. herdenken overledenen, presentatie werkplan + begroting,
verkiezing 2e VDG / 1e VDG / DG - Stemrechten 1 per 10 leden (min 1, max 5) -
Quorum >50% van stemgerechtigden - Oproeping min. 30 dagen vooraf (art. 2.1 HR) -
Conventiestukken digitaal uiterlijk 20 dagen vooraf (art. 7 HR).

Uitvoeren:  python3 generate_checklist.py
Output:     Checklist_Voorjaarsconventie_2027_v1.0.xlsx (zelfde map)
"""

import os
from datetime import date
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.utils import get_column_letter
from openpyxl.worksheet.datavalidation import DataValidation
from openpyxl.formatting.rule import CellIsRule

# == Constanten & feitelijke data (alleen uit Meta-Dossier) ==================
DISTRICT = "110AN"
CONVENTIE = "Voorjaarsconventie 2027"
CONVENTIE_MAAND = "April 2027"
VERSIE = "Versie 1.0"
AANGEMAAKT = date.today().isoformat()

# Maandrekenkunde: conventie April 2027 -> T-12 mnd = apr 2026 ... T-1 mnd = mrt 2027
OUTPUT_PATH = os.path.join(
    os.path.dirname(os.path.abspath(__file__)),
    "Checklist_Voorjaarsconventie_2027_v1.0.xlsx",
)

# == Corporate huisstijl (identiek aan overige deliverables) ================
CORP_BLUE = "003366"      # primaire kleur (titelbalk, tabelkop)
CORP_MID = "006699"       # secundair blauw (subtitel)
ACCENT = "FFB81C"         # gouden accent (Lions)
GOLD_TXT = "886E0A"       # donkere goudtint voor tekst op licht
TEXT_DARK = "1F2937"
TEXT_SEC = "374151"
CARD = "F8F9FA"           # lichtgrijs voor zebrarijen
WHITE = "FFFFFF"
LIJN = "D0D5DD"

STATUS_GROEN = "C6EFCE"
STATUS_AMBER = "FFEB9C"
STATUS_ROOD = "FFC7CE"

STATUS_OPTIES = '"Niet gestart,In uitvoering,Afgerond,Geblokkeerd,N.v.t."'
DEFAULT_STATUS = "Niet gestart"
FONT_NAAM = "Calibri"

KOLOMMEN = [
    "ID", "Fase", "Categorie", "Taak", "Verantwoordelijke",
    "Deadline", "Status", "Opmerkingen", "Afhankelijkheden",
]
KOLOM_BREEDTES = [10, 17, 18, 52, 24, 19, 14, 44, 16]

THIN = Side(style="thin", color=LIJN)
RAND = Border(left=THIN, right=THIN, top=THIN, bottom=THIN)

# == Taakdata ================================================================
# Tuple-volgorde: (Fase, Categorie, Taak, Verantwoordelijke, Deadline,
#                  Opmerkingen, Afhankelijkheden)

TAKEN_VOORBEREIDING = [
    ("T-12 mnd (apr 2026)", "Governance",
     "Roulatieschema en distrikkalender raadplegen; datum en gaststad/locatie vaststellen",
     "DG + Ambt. Secretaris", "T-12 mnd (apr 2026)",
     "Datum niet in vakantie; 6 weken voor nationale conventie; vastgestelde datum "
     "nooit verplaatsen (Handboek 1.1)", ""),
    ("T-12 mnd (apr 2026)", "Communicatie",
     "Voorlopige datum en locatie publiceren in distrikkalender en GR-agenda",
     "Ambt. Secretaris", "T-12 mnd (apr 2026)",
     "In lijn met agenda-110AN-2026-2027", "VB-001"),
    ("T-10 mnd (jun 2026)", "Organisatie",
     "Conventiecommissie / organiserend comite formeren (DG, VDG's, ambt. secretaris, "
     "vertegenwoordigers host club)",
     "DG", "T-10 mnd (jun 2026)",
     "DG is conventievoorzitter en linking pin samen met ambt. secretaris "
     "(Handboek 3.1)", "VB-001"),
    ("T-10 mnd (jun 2026)", "Organisatie",
     "Werkgroepen instellen: zaal/techniek, vlaggen, hospitality, decor, registratie",
     "Conventiecommissie", "T-10 mnd (jun 2026)",
     "Zie Werkinstructie hoofdstuk 2", "VB-003"),
    ("T-9 mnd (jul 2026)", "Financien",
     "Conventiebegroting opstellen en afstemmen met Districtspenningmeester",
     "DG + Penningmeester", "T-9 mnd (jul 2026)",
     "Referentie: Districtbegroting post '1 Districtsconventie' EUR 3.500", "VB-003"),
    ("T-9 mnd (jul 2026)", "Governance",
     "Locatie definitief boeken incl. contract en capaciteitscheck (incl. partners/gasten)",
     "Conventiecommissie", "T-9 mnd (jul 2026)",
     "Handboek: apart afgesloten zaaldeel vereist", "VB-001"),
    ("T-9 mnd (jul 2026)", "Governance",
     "Projectplan conventie vaststellen: tijdlijnen, budget, takenverdeling",
     "DG + Ambt. Secretaris", "T-9 mnd (jul 2026)",
     "Conform Procedure hoofdstuk 5", "VB-004"),
    ("T-6 mnd (okt 2026)", "Statutair",
     "Kaderagenda opstellen: herdenken overledenen, presentatie werkplan + begroting, "
     "verkiezing 2e VDG / 1e VDG / DG",
     "Ambt. Secretaris", "T-6 mnd (okt 2026)",
     "Vaste agendapunten: welkom, roll-call, rondvraag (Handboek 1.1)", "VB-007"),
    ("T-6 mnd (okt 2026)", "Statutair",
     "Oproeping voorbereiden: datum, tijd, locatie, agenda, voorstellen, "
     "registratietref, good-standing vereiste",
     "Ambt. Secretaris", "T-6 mnd (okt 2026)",
     "Verzending min. 30 dagen voor conventie via CMS-vergadermodule (art. 2.1 HR)",
     "VB-008"),
    ("T-6 mnd (okt 2026)", "Gasten",
     "Internationale gasten en buitenlandse gouverneurs vroegtijdig uitnodigen",
     "DG", "T-6 mnd (okt 2026)",
     "Spreektijd, voertaal en volksliederen vooraf afspreken (Handboek 1.1)", "VB-008"),
    ("T-4 mnd (dec 2026)", "Statutair",
     "Voorstellen, amendementen, resoluties en moties innen bij clubs",
     "Ambt. Secretaris", "T-4 mnd (dec 2026)",
     "Deadline digitaal aanleveren: T-20 dagen (art. 7 HR)", "VB-009"),
    ("T-4 mnd (dec 2026)", "Verkiezingen",
     "Kandidaatstellingen DG / 1e VDG / 2e VDG verzamelen en valideren",
     "Gouverneursraad", "T-4 mnd (dec 2026)",
     "Schriftelijk, uiterlijk 30 dagen voor conventie (art. 10.4 HR)", "VB-008"),
    ("T-3 mnd (jan 2027)", "Statutair",
     "Stembureau benoemen via gouverneursraad en instrueren",
     "Gouverneursraad", "T-3 mnd (jan 2027)",
     "Voorzitter + leden; instructies vastleggen (art. 15 HR)", "VB-012"),
    ("T-3 mnd (jan 2027)", "Organisatie",
     "Vrijwilligersplan host club opstellen (balie, zaaldienst, techniek, parkeerbegeleiding)",
     "Host club", "T-3 mnd (jan 2027)",
     "Zie Werkinstructie 4.1", "VB-004"),
    ("T-2 mnd (feb 2027)", "Statutair",
     "Conventiestukken digitaal versturen en in ownCloud plaatsen",
     "Ambt. Secretaris", "T-20 dagen",
     "Agenda + alle stukken uiterlijk 20 dagen vooraf beschikbaar (art. 7.1 HR)",
     "VB-011"),
    ("T-1 mnd (mrt 2027)", "Registratie",
     "Laatste check registratielijsten en stemgerechtigden per club (1 per 10 leden, "
     "min 1, max 5) + quorum-analyse",
     "Registratiebureau", "T-1 mnd (mrt 2027)",
     "Quorum: >50% van stemgerechtigden", "VB-015"),
    ("T-1 mnd (mrt 2027)", "Governance",
     "Generale coordinatievergadering en go/no-go met conventiecommissie",
     "Conventiecommissie", "T-1 mnd (mrt 2027)",
     "Alle werkgroepen rapporteren gereedheid", "VB-016"),
]

TAKEN_LOCATIE = [
    ("T-9 mnd (jul 2026)", "Locatie",
     "Locatiebezoek: zalen, routing, parkeergelegenheid en gelijktijdige andere "
     "gezelschappen checken met uitbater",
     "Werkgroep zaal/techniek", "T-9 mnd (jul 2026)",
     "Andere gezelschappen = extra banners voor routing (Handboek 1.1)", "VB-006"),
    ("T-9 mnd (jul 2026)", "Locatie",
     "Check afgesloten zaaldeel en minimale geluidsoverlast (keuken, espressomachine)",
     "Werkgroep zaal/techniek", "T-9 mnd (jul 2026)",
     "Handboek 1.1: vergadering moet ongestoord kunnen plaatsvinden", "LL-001"),
    ("T-6 mnd (okt 2026)", "Techniek",
     "AV-specificatie opstellen en huren/reserveren: microfoons, beamer, geluid, "
     "muziekinstallatie volksliederen",
     "Werkgroep techniek", "T-6 mnd (okt 2026)",
     "Incl. reserve-laptop en presentatie-afstandsbediening", ""),
    ("T-6 mnd (okt 2026)", "Decor",
     "Vlaggen en standaarden reserveren: USA, gastlanden, Nederland",
     "Werkgroep vlaggen", "T-6 mnd (okt 2026)",
     "Volgorde: USA, gastlanden naar belangrijkheid, NL (Handboek)", ""),
    ("T-6 mnd (okt 2026)", "Decor",
     "Lions-aankleding reserveren: banners, standaarden, themabord jaarthema",
     "Werkgroep decor", "T-6 mnd (okt 2026)",
     "Zorg voor voldoende Lions-aankleding (Handboek 1.1)", ""),
    ("T-3 mnd (jan 2027)", "Locatie",
     "Definitieve zaalindeling tekenen: podium, stembureau, registratie, "
     "spreekgestoelte, zaalbezetting",
     "Werkgroep zaal/techniek", "T-3 mnd (jan 2027)",
     "Routing afstemmen met cateraar (Handboek 1.1)", "LL-001"),
    ("T-6 wkn (mrt 2027)", "Catering",
     "Eten en drinken definitief bestellen incl. dieetwensen en vegetarisch aanbod",
     "Werkgroep hospitality", "T-6 weken",
     "Koffie/thee bij aankomst en pauzes; lunch voor alle conventiegangers", "VB-006"),
    ("T-6 wkn (mrt 2027)", "Hospitality",
     "Vrijdagavond diner + Get Together borrel en overnachtingen gasten boeken",
     "Werkgroep hospitality", "T-6 weken",
     "Handboek 3.1: gasten uitgenodigd voor diner, conventie incl. lunch en borrel",
     "VB-010"),
    ("T-1 mnd (mrt 2027)", "Catering",
     "Tijdschema conventiedag en routing met cateraar en locatie afstemmen",
     "Werkgroep hospitality", "T-1 mnd (mrt 2027)",
     "Voorkom verrassingen over zit- en looproutes", "LL-006"),
    ("T-1 mnd (mrt 2027)", "Personeel",
     "Vrijwilligersrooster definitief maken en communiceren",
     "Host club", "T-1 mnd (mrt 2027)",
     "Balie, zaaldienst, techniek, parkeerbegeleiding", "VB-014"),
    ("T-1 mnd (mrt 2027)", "PR",
     "Fotograaf regelen (liefst digitale spiegelreflexcamera)",
     "Werkgroep PR", "T-1 mnd (mrt 2027)",
     "Handboek: bedenk vooraf foto-plek formele momenten (geen zonlicht/scherm "
     "op achtergrond)", ""),
    ("T-1 mnd (mrt 2027)", "Financien",
     "Afspraken vastleggen wat gratis wordt aangeboden en waarvoor betaald moet worden",
     "Conventiecommissie", "T-1 mnd (mrt 2027)",
     "Handboek 1.1; verwerk in communicatie (tab Inschrijving)", "VB-005"),
]

TAKEN_AGENDA = [
    ("T-6 mnd (okt 2026)", "Programma",
     "Conceptagenda opstellen met vaste agendapunten: welkom, roll-call, rondvraag",
     "Ambt. Secretaris", "T-6 mnd (okt 2026)",
     "Handboek 1.1: vaste agendapunten conventievergadering", "VB-008"),
    ("T-6 mnd (okt 2026)", "Sprekers",
     "Aansprekende spreker of actueel onderwerp werven (stimuleert opkomst)",
     "Conventiecommissie", "T-6 mnd (okt 2026)",
     "Handboek 1.0: opkomst stimuleren via locatie, spreker, onderwerp", ""),
    ("T-4 mnd (dec 2026)", "Verkiezingen",
     "Verkiezingsprocedure inpassen incl. apart agendapunt v\u00f3\u00f3r bekendmaking "
     "uitslag (teltijd stembureau)",
     "Ambt. Secretaris", "T-4 mnd (dec 2026)",
     "Handboek 1.1: agendapunt voorafgaand aan uitslag stemming op personen",
     "VB-012"),
    ("T-4 mnd (dec 2026)", "Presentaties",
     "Presentaties werkplan en begroting (DG) laten aanleveren",
     "DG", "T-4 mnd (dec 2026)",
     "Inkomende DG presenteert plannen Lionsjaar vanaf 1 juli incl. begroting "
     "(Handboek 1.0)", "VB-008"),
    ("T-3 mnd (jan 2027)", "Gasten",
     "Programmering internationale gasten: spreektijd, voertaal, volksliederen "
     "(NL, VS, gastland)",
     "DG + Werkgroep techniek", "T-3 mnd (jan 2027)",
     "Handboek 1.1: volksliederen laten spelen; muziek regelen", "VB-010"),
    ("T-3 mnd (jan 2027)", "Protocol",
     "Kleding dagelijks bestuur en partners op elkaar afstemmen",
     "Dagelijks bestuur", "T-3 mnd (jan 2027)",
     "Tenue de ville, actuele pin met functie; Koninklijke onderscheidingen mogen "
     "(Handboek 1.1)", ""),
    ("T-2 mnd (feb 2027)", "Programma",
     "Definitieve agenda vaststellen en aanleveren voor conventiestukken",
     "Ambt. Secretaris", "T-2 mnd (feb 2027)",
     "Sluit aan op art. 7.1 HR-deadline (T-20 dagen)", "AS-001"),
    ("T-2 mnd (feb 2027)", "Programma",
     "Externe presentaties buiten de formele vergadering plannen",
     "Conventiecommissie", "T-2 mnd (feb 2027)",
     "Handboek 1.1", "AS-007"),
    ("T-1 mnd (mrt 2027)", "Protocol",
     "Gereserveerde plaatsen met bordjes voor hoogwaardigheidsbekleders",
     "Werkgroep decor", "T-1 mnd (mrt 2027)",
     "Oud-gouverneurs, international directors, buitenlandse gouverneurs "
     "(Handboek 1.1)", "VB-010"),
    ("T-1 mnd (mrt 2027)", "Sprekers",
     "Spreektijden en microfoongebruik met alle sprekers afspreken",
     "Conventiecommissie", "T-1 mnd (mrt 2027)",
     "Gezicht naar de zaal richten; presentatie is ondersteunend (Handboek 1.2)",
     "AS-002"),
    ("T-1 mnd (mrt 2027)", "Programma",
     "Partnerprogramma en zaterdagse activiteiten lokale clubs co\u00f6rdineren",
     "Host club", "T-1 mnd (mrt 2027)",
     "Handboek 3.1: activiteitenprogramma met eigen bijdrage; partnerprogramma "
     "tijdens conventie", "AS-008"),
]

TAKEN_INSCHRIJVING = [
    ("T-6 mnd (okt 2026)", "Uitnodiging",
     "Uitnodiging via vergadermodule in CMS voorbereiden (aan alle leden)",
     "Ambt. Secretaris", "T-6 mnd (okt 2026)",
     "Districtssecretaris is centrale regelaar voor uitnodiging (Handboek 1.1)",
     "VB-009"),
    ("T-6 mnd (okt 2026)", "Communicatie",
     "Communicatieplan opstellen: website, social media en zonevoorzitters activeren",
     "Werkgroep PR", "T-6 mnd (okt 2026)",
     "Handboek: alleen een uitnodigingsmail is NIET voldoende", ""),
    ("T-3 mnd (jan 2027)", "Uitnodiging",
     "Oproeping-verzendplanning opstellen: verzending uiterlijk T-30 dagen",
     "Ambt. Secretaris", "T-30 dagen",
     "Aan clubs, Lions en Leoclubs (art. 2.1 HR); bewijs van verzending bewaren",
     "IC-001"),
    ("T-3 mnd (jan 2027)", "Registratie",
     "Registratieprocedure en badgelijsten opzetten (naam + clubnaam op badge)",
     "Registratiebureau", "T-3 mnd (jan 2027)",
     "Handboek 1.1: badges met naam en clubnaam", "VB-006"),
    ("T-2 mnd (feb 2027)", "Communicatie",
     "Herinneringsactie 1 via zonevoorzitters en clubbesturen",
     "Zonevoorzitters", "T-14 dagen",
     "Actief aanprijzen verhoogt opkomst (Handboek)", "IC-002"),
    ("T-1 mnd (mrt 2027)", "Registratie",
     "Tussenstand registraties en quorum-indicator bepalen (min. 50% clubs aangemeld)",
     "Registratiebureau", "T-14 dagen",
     "Stuurt aanvullende acties aan bij tekort", "IC-004"),
    ("T-1 mnd (mrt 2027)", "Communicatie",
     "Laatste herinnering met praktische info: parkeren, routing, dieetwensen, "
     "gratis/kostende onderdelen",
     "Ambt. Secretaris", "T-7 dagen",
     "Afstemmen met tab Locatie (LL-012)", "IC-005"),
    ("T-1 mnd (mrt 2027)", "PR",
     "PR-afspraken vastleggen: wie plaatst wat voor de Lion, op website en social media",
     "Werkgroep PR", "T-1 mnd (mrt 2027)",
     "Handboek 1.1: afspraken over PR vooraf maken", "IC-002"),
    ("T-1 mnd (mrt 2027)", "Registratie",
     "Good-standing controle en definitieve stemgerechtigdenlijst per club opstellen",
     "Ambt. Secretaris", "T-7 dagen",
     "Stemrecht: 1 per 10 leden, min 1, max 5", "IC-006"),
    ("T-1 mnd (mrt 2027)", "PR",
     "Persbericht en aankondiging regionale media voorbereiden",
     "Werkgroep PR", "T-1 mnd (mrt 2027)",
     "Optioneel; afstemmen met DG", "IC-002"),
]

TAKEN_DAGSELF = [
    ("Setup (T-1 dag)", "Zaal",
     "Zaal openen en opbouwen: podium, tafels, stoelen richting podium",
     "Werkgroep zaal/techniek", "Vrijdag ochtend",
     "Conform definitieve zaalindeling (LL-006)", ""),
    ("Setup (T-1 dag)", "Techniek",
     "AV volledig opbouwen en testen: microfoons, beamer, weergave, zoninval, "
     "muziek volksliederen",
     "Werkgroep techniek", "Vrijdag middag",
     "Alle onderdelen 1x volledig zonder storing draaien", "DS-001"),
    ("Setup (T-1 dag)", "Decor",
     "Vlaggen en standaarden plaatsen in juiste volgorde",
     "Werkgroep vlaggen", "Vrijdag middag",
     "USA - gastlanden naar belangrijkheid - NL (Handboek)", "DS-001"),
    ("Setup (T-1 dag)", "Decor",
     "Lions-aankleding aanbrengen: banners, themabord, routingsborden",
     "Werkgroep decor", "Vrijdag middag",
     "Extra banners bij andere gezelschappen op locatie", "DS-003"),
    ("Setup (T-1 dag)", "Registratie",
     "Registratiebalie inrichten: lijsten, badges, stemkaarten, stembiljetten, pennen",
     "Werkgroep registratie", "Vrijdag middag",
     "Stemmmateriaal geteld tegen verwachte stemgerechtigden", "IC-004"),
    ("Setup (T-1 dag)", "Stemming",
     "Stembureau-tafel inrichten met stembussen en groot voorbeeld-stembiljet",
     "Stembureau", "Vrijdag middag",
     "Voorbeeldbiljet zaalbreed zichtbaar v\u00f3\u00f3r eerste schriftelijke stemming",
     "VB-013"),
    ("Setup (T-1 dag)", "Programma",
     "Generale repetitie: opening, vlaggenceremonie-muziek, microfooncheck sprekers",
     "Conventiecommissie + techniek", "Vrijdag avond",
     "Alle presentaties op \u00e9\u00e9n laptop (Handboek 1.1)", "DS-002"),
    ("Setup (T-1 dag)", "Hospitality",
     "Aankomst en ontvangst DG, VDG's, partners en internationale gasten",
     "Werkgroep hospitality", "Vrijdag avond",
     "Overnachtingen nabij locatie geregeld (LL-008)", "LL-008"),
    ("Setup (T-1 dag)", "Programma",
     "Get Together borrel en diner vrijdagavond",
     "Werkgroep hospitality", "Vrijdag avond",
     "Handboek 3.1: traditie voorjaarsconventie", "DS-008"),
    ("Setup (T-1 dag)", "Co\u00f6rdinatie",
     "Laatste coordinatievergadering DG, ambt. secretaris en commissie",
     "Conventiecommissie", "Vrijdag avond",
     "Runbook 100% compleet (T-3 dagen-controle)", "DS-007"),
    ("Registratie (T-3 tot T-1 uur)", "Zaal",
     "Gebouw openen, techniek aanzetten, laatste zaalcheck",
     "Werkgroep zaal/techniek", "Zaterdag T-3 uur",
     "Dagelijks bestuur 1-2 uur voor aanvang aanwezig (Handboek 1.1)", "DS-002"),
    ("Registratie (T-3 tot T-1 uur)", "Registratie",
     "Registratiebalie operationeel vanaf ten minste 1 uur voor opening",
     "Registratiebureau", "Zaterdag T-1 uur",
     "Secretaris duidelijk zichtbaar bij entree; noteert aanwezigen", "DS-005"),
    ("Registratie (T-3 tot T-1 uur)", "Registratie",
     "Badges uitdelen met naam en clubnaam; ontvangst door twee bestuursleden bij entree",
     "Dagelijks bestuur", "Zaterdag T-1 uur",
     "Persoonlijke, warme verwelkoming (Handboek 1.1)", "DS-012"),
    ("Registratie (T-3 tot T-1 uur)", "Stemming",
     "Roll-call: opgaven, afmeldingen, aanwezigen en stemmen per club vaststellen",
     "Ambt. Secretaris", "Zaterdag opening",
     "Inzicht aantal aanwezigen en stemgerechtigden (Handboek 1.1)", "DS-012"),
    ("Programma", "Protocol",
     "Opening en welkom; oud-gouverneurs, international directors en buitenlandse "
     "gouverneurs persoonlijk met titel noemen",
     "DG", "Zaterdag ochtend",
     "Handboek 1.1", "DS-014"),
    ("Programma", "Protocol",
     "Herdenken van de overledenen",
     "DG", "Zaterdag ochtend",
     "Vast agendapunt voorjaarsconventie (Handboek 1.1)", "DS-015"),
    ("Programma", "Statutair",
     "Presentatie werkplan en begroting zittende/in komende DG",
     "DG", "Zaterdag ochtend",
     "Inkomende DG presenteert plannen Lionsjaar incl. begroting", "DS-015"),
    ("Programma", "Verkiezingen",
     "Verkiezingen 2e VDG / 1e VDG / DG: stembriefjes, vooraf ingevulde "
     "stemformulieren, telling",
     "Stembureau", "Zaterdag ochtend",
     "Apart agendapunt v\u00f3\u00f3r uitslag; voldoende stembriefjes (Handboek 1.1)",
     "DS-014"),
    ("Programma", "Programma",
     "Microfoonbeheer en sprekersbegeleiding tijdens heel programma",
     "Werkgroep techniek", "Zaterdag",
     "Sprekers richten gezicht naar de zaal (Handboek 1.2)", "DS-002"),
    ("Programma", "PR",
     "Fotografie van formele momenten",
     "Fotograaf", "Zaterdag",
     "Foto-plek zonder zonlicht of beeldscherm op achtergrond", "LL-011"),
    ("Programma", "Programma",
     "Rondvraag en inbreng leden mogelijkheden bieden",
     "DG", "Zaterdag",
     "Niet benadrukken dat programma te vol is (Handboek 1.2)", "DS-018"),
    ("Afsluiting", "Protocol",
     "Onderscheidingen uitreiken aan einde van de vergadering incl. kado of bloemen",
     "DG", "Zaterdag einde",
     "Handboek 1.1", "DS-018"),
    ("Afsluiting", "Programma",
     "Expliciete sluiting van het vergaderdeel op natuurlijke manier",
     "DG", "Zaterdag einde",
     "Duidelijk voor iedereen dat vergaderdeel klaar is (Handboek 1.1)", "DS-022"),
    ("Afsluiting", "Hospitality",
     "Gezamenlijke borrel voor alle conventiegangers; lunch/activiteitenprogramma",
     "Werkgroep hospitality", "Zaterdag middag",
     "Handboek 3.1: afsluitende borrel is traditie voorjaarsconventie", "DS-023"),
    ("Afsluiting", "Organisatie",
     "Afbouw zaal, retour vlaggen/materiaal en controle schade/achtergebleven spullen",
     "Host club", "Zaterdag middag",
     "Locatie conform contract opleveren", "DS-024"),
    ("Afsluiting", "Protocol",
     "Dagelijks bestuur vertrekt als laatsten",
     "Dagelijks bestuur", "Zaterdag einde",
     "Handboek 1.2: altijd bestuursleden als laatste laten vertrekken", "DS-025"),
]

TAKEN_EVALUATIE = [
    ("Opvolging (T+1 dgn)", "Evaluatie",
     "Digitaal evaluatieformulier naar alle deelnemers versturen",
     "Werkgroep PR", "T+1 dag",
     "Kort en concreet; respons binnen 1 week vragen", "DS-026"),
    ("Opvolging (T+1 wk)", "Notulen",
     "Notulen en besluitenlijst finaliseren",
     "Ambt. Secretaris", "T+1 week",
     "Notulering formeel deel conform Handboek", "DS-018"),
    ("Opvolging (T+1 wk)", "Financien",
     "Financiele afrekening met locatie, cateraar en leveranciers",
     "Penningmeester", "T+1 week",
     "Toetsen aan conventiebegroting (VB-005)", "VB-005"),
    ("Opvolging (T+2 wk)", "PR",
     "Foto's selecteren, verslag en publicaties op website/social media plaatsen",
     "Werkgroep PR", "T+2 weken",
     "Conform PR-afspraken (IC-008)", "DS-020"),
    ("Opvolging (T+2 wk)", "Relaties",
     "Bedankjes aan gasten, spreker, host club en vrijwilligers",
     "DG", "T+2 weken",
     "Persoonlijke noot van DG", ""),
    ("Opvolging (T+3 wk)", "Evaluatie",
     "Evaluatierapport opstellen: lessen geleerd (logistiek, proces, communicatie)",
     "DG + Conventiecommissie", "T+3 weken",
     "Input: evaluatieformulieren + evaluatievergadering", "EO-001"),
    ("Opvolging (T+4 wk)", "Archief",
     "Alle stukken, uitslagen en verslagen archiveren in ownCloud",
     "Ambt. Secretaris", "T+4 weken",
     "Incl. registratielijsten en stemuitslagen", "EO-002"),
    ("Opvolging (T+4 wk)", "Statutair",
     "Besluiten en punten voor nationale conventie indienen (min. 30 dagen vooraf)",
     "Ambt. Secretaris", "T+30 dagen v\u00f3\u00f3r NC",
     "Handboek 1.1: districtsconventie 6 weken voor nationale conventie", "EO-002"),
    ("Opvolging (T+8 wk)", "Overdracht",
     "Overdrachtsmap incl. evaluatierapport aan volgende organiserende club (roulatie)",
     "DG + Ambt. Secretaris", "T+8 weken",
     "Complete map: contracten, offertes, evaluatie, contacten", "EO-006"),
]

# == Stijl-helpers ===========================================================

def vul(kleur):
    return PatternFill("solid", fgColor=kleur)


def koptekst_blok(ws, tabnr, tabtitel, subtotaal):
    """Titelbalk (navy), subtitel (goud) en legenderegel per tab."""
    laatste_kol = get_column_letter(len(KOLOMMEN))
    ws.merge_cells(f"A1:{laatste_kol}1")
    c = ws["A1"]
    c.value = f"{tabnr}. {tabtitel.upper()} - {CONVENTIE} DISTRICT {DISTRICT}"
    c.font = Font(name=FONT_NAAM, size=14, bold=True, color=WHITE)
    c.fill = vul(CORP_BLUE)
    c.alignment = Alignment(horizontal="left", vertical="center", indent=1)
    ws.row_dimensions[1].height = 26

    ws.merge_cells(f"A2:{laatste_kol}2")
    c = ws["A2"]
    c.value = (f"{CONVENTIE_MAAND} | {VERSIE} | aangemaakt {AANGEMAAKT} | "
               f"{subtotaal} taken | Status: Niet gestart / In uitvoering / "
               f"Afgerond / Geblokkeerd / N.v.t.")
    c.font = Font(name=FONT_NAAM, size=9, italic=True, color=GOLD_TXT)
    c.fill = vul(ACCENT)
    c.alignment = Alignment(horizontal="left", vertical="center", indent=1)
    ws.row_dimensions[2].height = 16
    ws.row_dimensions[3].height = 6


def tabel(ws, taken, id_prefix, start_rij=4):
    """Tabelkop + datarijen met zebrastrepen; retourneert laatste rij."""
    # Tabelkop
    for j, naam in enumerate(KOLOMMEN, start=1):
        c = ws.cell(row=start_rij, column=j, value=naam)
        c.font = Font(name=FONT_NAAM, size=10, bold=True, color=WHITE)
        c.fill = vul(CORP_BLUE)
        c.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
        c.border = RAND
    ws.row_dimensions[start_rij].height = 20

    # Datarijen
    for i, taak in enumerate(taken):
        rij = start_rij + 1 + i
        task_id = f"{id_prefix}-{i + 1:03d}"
        fase, cat, omschr, verantw, deadline, opmerk, afh = taak
        waarden = [task_id, fase, cat, omschr, verantw, deadline,
                   DEFAULT_STATUS, opmerk, afh]
        for j, waarde in enumerate(waarden, start=1):
            c = ws.cell(row=rij, column=j, value=waarde)
            c.border = RAND
            c.font = Font(name=FONT_NAAM, size=10, color=TEXT_DARK)
            c.alignment = Alignment(vertical="top", wrap_text=True)
            if i % 2 == 1:
                c.fill = vul(CARD)
        # ID-kolom: bold navy; Status: gecentreerd
        ws.cell(row=rij, column=1).font = Font(name=FONT_NAAM, size=10,
                                               bold=True, color=CORP_MID)
        ws.cell(row=rij, column=7).alignment = Alignment(
            horizontal="center", vertical="top", wrap_text=True)
    return start_rij + len(taken)


def maak_tab(wb, tabnr, tabnaam, tabtitel, taken, id_prefix):
    """Volledig gestylede tab: kopblok, tabel, validatie, voorwaardelijke
    opmaak, filters, freeze panes, kolombreedtes en printinstellingen."""
    ws = wb.create_sheet(tabnaam)
    koptekst_blok(ws, tabnr, tabtitel, len(taken))
    laatste_rij = tabel(ws, taken, id_prefix)

    # Kolombreedtes
    for j, breedte in enumerate(KOLOM_BREEDTES, start=1):
        ws.column_dimensions[get_column_letter(j)].width = breedte

    # Status-dropdown (data validatie) op de Status-kolom (G)
    dv = DataValidation(type="list", formula1=STATUS_OPTIES, allow_blank=True)
    dv.error = "Kies een status uit de lijst."
    dv.errorTitle = "Ongeldige status"
    ws.add_data_validation(dv)
    dv.add(f"G5:G{laatste_rij}")

    # Voorwaardelijke opmaak op Status
    bereik = f"G5:G{laatste_rij}"
    ws.conditional_formatting.add(bereik, CellIsRule(
        operator="equal", formula=['"Afgerond"'],
        fill=vul(STATUS_GROEN), font=Font(name=FONT_NAAM, color="006100")))
    ws.conditional_formatting.add(bereik, CellIsRule(
        operator="equal", formula=['"In uitvoering"'],
        fill=vul(STATUS_AMBER), font=Font(name=FONT_NAAM, color="9C6500")))
    ws.conditional_formatting.add(bereik, CellIsRule(
        operator="equal", formula=['"Geblokkeerd"'],
        fill=vul(STATUS_ROOD), font=Font(name=FONT_NAAM, color="9C0006")))

    # Filter en freeze panes
    ws.auto_filter.ref = f"A4:{get_column_letter(len(KOLOMMEN))}{laatste_rij}"
    ws.freeze_panes = "A5"

    # Printinstellingen: liggend, passend op breedte
    ws.page_setup.orientation = "landscape"
    ws.page_setup.fitToWidth = 1
    ws.page_setup.fitToHeight = 0
    ws.sheet_properties.pageSetUpPr.fitToPage = True
    ws.print_title_rows = "1:4"

    return ws


def main():
    wb = Workbook()
    wb.remove(wb.active)  # verwijder standaard sheet

    maak_tab(wb, 1, "1. Voorbereiding", "Voorbereiding (T-12 t/m T-1 mnd)",
             TAKEN_VOORBEREIDING, "VB")
    maak_tab(wb, 2, "2. Locatie & Logistiek", "Locatie & Logistiek",
             TAKEN_LOCATIE, "LL")
    maak_tab(wb, 3, "3. Agenda & Sprekers", "Agenda & Sprekers",
             TAKEN_AGENDA, "AS")
    maak_tab(wb, 4, "4. Inschrijving & Comm", "Inschrijving & Communicatie",
             TAKEN_INSCHRIJVING, "IC")
    maak_tab(wb, 5, "5. Dagself", "Dagself (Setup / Registratie / Programma / Afsluiting)",
             TAKEN_DAGSELF, "DS")
    maak_tab(wb, 6, "6. Evaluatie & Opvolging", "Evaluatie & Opvolging",
             TAKEN_EVALUATIE, "EO")

    wb.save(OUTPUT_PATH)
    totaal = sum(len(t) for t in (TAKEN_VOORBEREIDING, TAKEN_LOCATIE,
                                  TAKEN_AGENDA, TAKEN_INSCHRIJVING,
                                  TAKEN_DAGSELF, TAKEN_EVALUATIE))
    print(f"OK: {OUTPUT_PATH}")
    print(f"6 tabs, {totaal} taken totaal.")
    print(f"Controleset: District {DISTRICT} - {CONVENTIE} - {CONVENTIE_MAAND}")


if __name__ == "__main__":
    main()
