#!/usr/bin/env python3
"""Génère la note méthodologique SportData & Territoires au format Word."""

from docx import Document
from docx.shared import Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
import copy

OUT = "/Users/patrickbayeux/Documents/2 - Observatoire/DATA/2026/SportData territoires/Note_methodologique_SportData_Territoires.docx"

NAVY   = RGBColor(0x1a, 0x23, 0x7e)
DARKBG = RGBColor(0x1a, 0x23, 0x7e)
WHITE  = RGBColor(0xFF, 0xFF, 0xFF)
GREY   = RGBColor(0x55, 0x55, 0x55)
LGREY  = RGBColor(0xF5, 0xF5, 0xF5)

doc = Document()

# ── Marges ────────────────────────────────────────────────────────────────────
for section in doc.sections:
    section.top_margin    = Cm(2)
    section.bottom_margin = Cm(2)
    section.left_margin   = Cm(2.5)
    section.right_margin  = Cm(2.5)

# ── Styles de base ────────────────────────────────────────────────────────────
style_normal = doc.styles["Normal"]
style_normal.font.name = "Calibri"
style_normal.font.size = Pt(10)

def set_cell_bg(cell, hex_color):
    tc   = cell._tc
    tcPr = tc.get_or_add_tcPr()
    shd  = OxmlElement("w:shd")
    shd.set(qn("w:val"),   "clear")
    shd.set(qn("w:color"), "auto")
    shd.set(qn("w:fill"),  hex_color)
    tcPr.append(shd)

def set_cell_borders(cell, **kwargs):
    tc   = cell._tc
    tcPr = tc.get_or_add_tcPr()
    tcBorders = OxmlElement("w:tcBorders")
    for edge, val in kwargs.items():
        el = OxmlElement(f"w:{edge}")
        el.set(qn("w:val"),   val.get("val",   "single"))
        el.set(qn("w:sz"),    val.get("sz",    "4"))
        el.set(qn("w:space"), val.get("space", "0"))
        el.set(qn("w:color"), val.get("color", "auto"))
        tcBorders.append(el)
    tcPr.append(tcBorders)

def add_para(text, bold=False, italic=False, size=10, color=None,
             align=WD_ALIGN_PARAGRAPH.LEFT, space_before=0, space_after=4):
    p = doc.add_paragraph()
    p.alignment = align
    p.paragraph_format.space_before = Pt(space_before)
    p.paragraph_format.space_after  = Pt(space_after)
    run = p.add_run(text)
    run.bold   = bold
    run.italic = italic
    run.font.size = Pt(size)
    if color:
        run.font.color.rgb = color
    return p

def add_bullet(text, level=0, italic=False, color=None):
    p = doc.add_paragraph(style="List Bullet")
    p.paragraph_format.space_after  = Pt(2)
    p.paragraph_format.space_before = Pt(0)
    p.paragraph_format.left_indent  = Cm(0.5 + level * 0.5)
    run = p.add_run(text)
    run.font.size = Pt(10)
    run.italic = italic
    if color:
        run.font.color.rgb = color
    return p

def add_section_title(text):
    """Bandeau bleu marine pleine largeur avec texte blanc."""
    tbl = doc.add_table(rows=1, cols=1)
    tbl.alignment = WD_TABLE_ALIGNMENT.LEFT
    tbl.style = "Table Grid"
    cell = tbl.cell(0, 0)
    set_cell_bg(cell, "1a237e")
    cell.width = Cm(16)
    p = cell.paragraphs[0]
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p.paragraph_format.space_before = Pt(4)
    p.paragraph_format.space_after  = Pt(4)
    run = p.add_run(text.upper())
    run.bold = True
    run.font.size = Pt(11)
    run.font.color.rgb = WHITE
    # Supprimer la bordure de tableau
    for row in tbl.rows:
        for c in row.cells:
            set_cell_borders(c,
                top={"val":"none"}, bottom={"val":"none"},
                left={"val":"none"}, right={"val":"none"})
    doc.add_paragraph().paragraph_format.space_after = Pt(2)

def add_sub_title(text):
    p = doc.add_paragraph()
    p.paragraph_format.space_before = Pt(6)
    p.paragraph_format.space_after  = Pt(3)
    run = p.add_run(text)
    run.bold = True
    run.font.size = Pt(10.5)
    run.font.color.rgb = NAVY

# ═══════════════════════════════════════════════════════════════════════════════
# EN-TÊTE
# ═══════════════════════════════════════════════════════════════════════════════
tbl_hdr = doc.add_table(rows=1, cols=1)
tbl_hdr.alignment = WD_TABLE_ALIGNMENT.LEFT
cell_h = tbl_hdr.cell(0, 0)
set_cell_bg(cell_h, "1a237e")
ph = cell_h.paragraphs[0]
ph.alignment = WD_ALIGN_PARAGRAPH.CENTER
ph.paragraph_format.space_before = Pt(8)
ph.paragraph_format.space_after  = Pt(2)
r1 = ph.add_run("SportData & Territoires")
r1.bold = True; r1.font.size = Pt(16); r1.font.color.rgb = WHITE

ph2 = cell_h.add_paragraph()
ph2.alignment = WD_ALIGN_PARAGRAPH.CENTER
ph2.paragraph_format.space_before = Pt(0)
ph2.paragraph_format.space_after  = Pt(8)
r2 = ph2.add_run("Note méthodologique — Approche et sources")
r2.font.size = Pt(11); r2.font.color.rgb = RGBColor(0xBB, 0xDE, 0xFB)
r3 = ph2.add_run("  |  par Patrick Bayeux — Décideurs du sport")
r3.italic = True; r3.font.size = Pt(10); r3.font.color.rgb = RGBColor(0x90, 0xCA, 0xF9)

for c in tbl_hdr.rows[0].cells:
    set_cell_borders(c,
        top={"val":"none"}, bottom={"val":"none"},
        left={"val":"none"}, right={"val":"none"})

doc.add_paragraph().paragraph_format.space_after = Pt(4)

# ═══════════════════════════════════════════════════════════════════════════════
# 1. SOURCES ET AVERTISSEMENTS
# ═══════════════════════════════════════════════════════════════════════════════
add_section_title("1. Sources de données et avertissements")

add_para(
    "Les données mobilisées proviennent du portail open data du Ministère chargé des Sports : "
    "data.sports.gouv.fr. Elles couvrent les licenciés fédéraux (2023), les clubs affiliés (2023) "
    "et les équipements sportifs issus du Recensement des Équipements Sportifs — RES (2023). "
    "Les données scolaires sont issues du Ministère de l'Éducation nationale (rentrée 2024).",
    space_after=4)

# Avertissement encadré
tbl_w = doc.add_table(rows=1, cols=1)
tbl_w.style = "Table Grid"
cw = tbl_w.cell(0, 0)
set_cell_bg(cw, "FFF8E1")
pw = cw.paragraphs[0]
pw.paragraph_format.space_before = Pt(3)
pw.paragraph_format.space_after  = Pt(3)
rw1 = pw.add_run("⚠  Données fournies à titre indicatif. ")
rw1.bold = True; rw1.font.size = Pt(10)
rw2 = pw.add_run(
    "Des erreurs ou omissions sont possibles, notamment concernant les équipements sportifs, "
    "dont le recensement repose sur des déclarations volontaires et dont la mise à jour n'est "
    "pas toujours régulière. Tout résultat présentant une anomalie manifeste doit faire l'objet "
    "d'une vérification sur le terrain avant toute décision.")
rw2.font.size = Pt(10)
doc.add_paragraph().paragraph_format.space_after = Pt(2)

add_para(
    "Géolocalisation des licenciés : les licenciés sont rattachés à leur commune de résidence "
    "et non à celle de leur club. Cette approche permet de mesurer la demande sportive réelle "
    "d'un territoire, indépendamment de la localisation des équipements et des clubs.",
    italic=True, space_after=6)

# ═══════════════════════════════════════════════════════════════════════════════
# 2. STRATES
# ═══════════════════════════════════════════════════════════════════════════════
add_section_title("2. Strates de comparaison")

add_para(
    "Pour permettre une comparaison pertinente, les communes et les intercommunalités sont "
    "classées en strates démographiques homogènes. Les indicateurs de strate sont des taux "
    "pondérés par la population (somme des licenciés / clubs / équipements de la strate "
    "rapportée à la population totale de la strate × 1 000).",
    space_after=5)

tbl_s = doc.add_table(rows=6, cols=2)
tbl_s.style = "Table Grid"
tbl_s.alignment = WD_TABLE_ALIGNMENT.CENTER
headers = ["Communes", "Intercommunalités (EPCI)"]
strates_comm = ["< 3 500 hab.", "3 500 à 10 000 hab.", "10 000 à 30 000 hab.",
                "30 000 à 100 000 hab.", "> 100 000 hab."]
strates_epci = ["< 15 000 hab.", "15 000 à 50 000 hab.", "50 000 à 250 000 hab.",
                "> 250 000 hab.", ""]

for ci, h in enumerate(headers):
    cell = tbl_s.cell(0, ci)
    set_cell_bg(cell, "1a237e")
    p = cell.paragraphs[0]
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    r = p.add_run(h)
    r.bold = True; r.font.size = Pt(10); r.font.color.rgb = WHITE

for ri, (sc, se) in enumerate(zip(strates_comm, strates_epci), start=1):
    for ci, txt in enumerate([sc, se]):
        cell = tbl_s.cell(ri, ci)
        if ri % 2 == 0:
            set_cell_bg(cell, "E8EAF6")
        p = cell.paragraphs[0]
        p.alignment = WD_ALIGN_PARAGRAPH.CENTER
        p.paragraph_format.space_before = Pt(2)
        p.paragraph_format.space_after  = Pt(2)
        r = p.add_run(txt)
        r.font.size = Pt(10)

doc.add_paragraph().paragraph_format.space_after = Pt(4)

# ═══════════════════════════════════════════════════════════════════════════════
# 3. BESOINS THÉORIQUES — LICENCIÉS
# ═══════════════════════════════════════════════════════════════════════════════
add_section_title("3. Besoins théoriques — Clubs sportifs (licenciés)")

add_para(
    "Le besoin théorique en équipements est calculé à partir des licenciés de chaque fédération "
    "selon la formule :", space_after=3)

# Formule encadrée
tbl_f = doc.add_table(rows=1, cols=1)
tbl_f.style = "Table Grid"
cf = tbl_f.cell(0, 0)
set_cell_bg(cf, "E3F2FD")
pf = cf.paragraphs[0]
pf.alignment = WD_ALIGN_PARAGRAPH.CENTER
pf.paragraph_format.space_before = Pt(5)
pf.paragraph_format.space_after  = Pt(5)
rf = pf.add_run(
    "Besoin = (Licenciés ÷ Effectif de groupe) × Entraînements/semaine × Durée (h) ÷ Disponibilité hebdomadaire (h)")
rf.bold = True; rf.font.size = Pt(10); rf.font.color.rgb = NAVY
doc.add_paragraph().paragraph_format.space_after = Pt(3)

add_para(
    "Un coefficient majorateur est appliqué pour tenir compte des temps d'occupation "
    "non strictement sportifs (vestiaires, rangement, logistique) :",
    space_after=4)

tbl_eq = doc.add_table(rows=5, cols=3)
tbl_eq.style = "Table Grid"
tbl_eq.alignment = WD_TABLE_ALIGNMENT.CENTER
eq_headers = ["Type d'équipement", "Fédérations concernées", "Coeff."]
eq_data = [
    ("Courts de tennis",          "FF Tennis",                                       "× 1,15"),
    ("Salles multisports",        "Basketball, Handball, Volley-Ball, Badminton",    "× 1,15"),
    ("Terrains de grands jeux",   "Football, Rugby",                                 "× 1,20"),
    ("Salles de combat",          "Judo, Taekwondo, Aïkido, Karaté, Boxe",          "× 1,20"),
]
for ci, h in enumerate(eq_headers):
    cell = tbl_eq.cell(0, ci)
    set_cell_bg(cell, "1a237e")
    p = cell.paragraphs[0]
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p.paragraph_format.space_before = Pt(2)
    p.paragraph_format.space_after  = Pt(2)
    r = p.add_run(h)
    r.bold = True; r.font.size = Pt(9.5); r.font.color.rgb = WHITE

for ri, (t, f, c) in enumerate(eq_data, start=1):
    row_data = [t, f, c]
    for ci, txt in enumerate(row_data):
        cell = tbl_eq.cell(ri, ci)
        if ri % 2 == 0:
            set_cell_bg(cell, "E8EAF6")
        p = cell.paragraphs[0]
        p.alignment = WD_ALIGN_PARAGRAPH.CENTER if ci == 2 else WD_ALIGN_PARAGRAPH.LEFT
        p.paragraph_format.space_before = Pt(2)
        p.paragraph_format.space_after  = Pt(2)
        r = p.add_run(txt)
        r.font.size = Pt(9.5)
        if ci == 2:
            r.bold = True

doc.add_paragraph().paragraph_format.space_after = Pt(3)
add_para(
    "L'écart = équipements actuels − besoins calculés. "
    "Un écart négatif signale un déficit ; un écart positif un excédent théorique.",
    italic=True, color=GREY, space_after=6)

# ═══════════════════════════════════════════════════════════════════════════════
# 4. BESOINS THÉORIQUES — SCOLAIRES
# ═══════════════════════════════════════════════════════════════════════════════
add_section_title("4. Besoins théoriques — Scolaires")

add_sub_title("A. Gymnases")

add_para(
    "Le calcul est fondé sur les effectifs scolaires (primaire, collège, lycée GT) "
    "et les volumes horaires EPS réglementaires. La maternelle est exclue (activités "
    "physiques ne nécessitant pas de gymnase). Deux hypothèses sont retenues selon la part "
    "du temps EPS pratiqué en gymnase :", space_after=4)

tbl_g = doc.add_table(rows=5, cols=5)
tbl_g.style = "Table Grid"
tbl_g.alignment = WD_TABLE_ALIGNMENT.CENTER
g_headers = ["Niveau", "Élèves/classe", "H. EPS/sem.", "H. programme", "Inclus"]
g_data = [
    ("Maternelle", "20", "3 h", "24 h", "Non"),
    ("Primaire",   "22", "3 h", "27 h", "Oui"),
    ("Collège",    "25", "4 h", "36 h", "Oui"),
    ("Lycée GT",   "28", "3 h", "40 h", "Oui"),
]
for ci, h in enumerate(g_headers):
    cell = tbl_g.cell(0, ci)
    set_cell_bg(cell, "1a237e")
    p = cell.paragraphs[0]
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p.paragraph_format.space_before = Pt(2)
    p.paragraph_format.space_after  = Pt(2)
    r = p.add_run(h)
    r.bold = True; r.font.size = Pt(9.5); r.font.color.rgb = WHITE

for ri, row in enumerate(g_data, start=1):
    for ci, txt in enumerate(row):
        cell = tbl_g.cell(ri, ci)
        if ri % 2 == 0:
            set_cell_bg(cell, "E8EAF6")
        p = cell.paragraphs[0]
        p.alignment = WD_ALIGN_PARAGRAPH.CENTER
        p.paragraph_format.space_before = Pt(2)
        p.paragraph_format.space_after  = Pt(2)
        r = p.add_run(txt)
        r.font.size = Pt(9.5)
        if ci == 4 and txt == "Non":
            r.font.color.rgb = RGBColor(0xC0, 0x39, 0x2B)
        if ci == 4 and txt == "Oui":
            r.font.color.rgb = RGBColor(0x27, 0xAE, 0x60)

doc.add_paragraph().paragraph_format.space_after = Pt(3)

add_bullet("Hypothèse 30 % : 30 % du temps EPS se déroule en gymnase → "
           "classes/structure = H. programme ÷ (H. EPS × 30 %) ; "
           "besoin = nb de classes ÷ classes/structure")
add_bullet("Hypothèse 50 % : même calcul avec 50 % du temps EPS en gymnase")

p_note = doc.add_paragraph()
p_note.paragraph_format.space_before = Pt(4)
p_note.paragraph_format.space_after  = Pt(6)
p_note.add_run("* Le pourcentage du temps de l'EPS passé en gymnase varie selon les "
               "établissements, la disponibilité des équipements et les choix pédagogiques. "
               "Les deux hypothèses encadrent la fourchette réaliste des besoins.").italic = True

add_sub_title("B. Piscines — Plan d'eau")

add_para(
    "Le calcul est conforme à la circulaire du 28 février 2022 relative à l'enseignement "
    "de la natation scolaire. Il modélise, pour chaque niveau d'enseignement, "
    "la fréquence des cycles de natation, la taille des groupes et la durée des créneaux "
    "afin d'estimer le nombre de m² de plan d'eau nécessaires. "
    "Le résultat est exprimé en trois valeurs :", space_after=4)

add_bullet("Hypothèse basse — résultat minimal selon les paramètres de la circulaire")
add_bullet("Hypothèse haute — résultat maximal")
add_bullet("Hypothèse moyenne — moyenne des deux hypothèses, valeur de référence retenue "
           "pour les indicateurs de synthèse")

add_para(
    "En complément, une estimation par ratio habitant est proposée selon trois standards "
    "couramment utilisés dans la planification sportive :",
    space_after=3)

add_bullet("0,016 m² de plan d'eau par habitant  (hypothèse basse)")
add_bullet("0,018 m² de plan d'eau par habitant  (hypothèse médiane)")
add_bullet("0,020 m² de plan d'eau par habitant  (hypothèse haute)")

# ═══════════════════════════════════════════════════════════════════════════════
# 5. CODE COULEUR
# ═══════════════════════════════════════════════════════════════════════════════
add_section_title("5. Code couleur des indicateurs")

add_para(
    "Les indicateurs de licenciés, clubs et équipements sont comparés à un indicateur moyen "
    "calculé comme la moyenne des taux disponibles (territoire, département, région, France). "
    "La position relative est visualisée par un code couleur :", space_after=4)

# Tableau code couleur
tbl_c = doc.add_table(rows=2, cols=5)
tbl_c.style = "Table Grid"
tbl_c.alignment = WD_TABLE_ALIGNMENT.CENTER
couleurs = [("1a7a45", "> +10 %"), ("e67e22", "+5 à +10 %"),
            ("1565c0", "± 5 %"), ("d35400", "−5 à −10 %"), ("c0392b", "< −10 %")]
libelles = ["Très au-dessus\nde la moyenne", "Au-dessus\nde la moyenne",
            "Dans la norme", "En dessous\nde la moyenne", "Très en dessous\nde la moyenne"]

for ci, (color, label) in enumerate(couleurs):
    cell = tbl_c.cell(0, ci)
    set_cell_bg(cell, color)
    p = cell.paragraphs[0]
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p.paragraph_format.space_before = Pt(4)
    p.paragraph_format.space_after  = Pt(4)
    r = p.add_run(label)
    r.bold = True; r.font.size = Pt(9.5); r.font.color.rgb = WHITE

for ci, lib in enumerate(libelles):
    cell = tbl_c.cell(1, ci)
    p = cell.paragraphs[0]
    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    p.paragraph_format.space_before = Pt(3)
    p.paragraph_format.space_after  = Pt(3)
    r = p.add_run(lib)
    r.font.size = Pt(8.5)

doc.add_paragraph().paragraph_format.space_after = Pt(6)

# ═══════════════════════════════════════════════════════════════════════════════
# PIED DE PAGE
# ═══════════════════════════════════════════════════════════════════════════════
from docx.oxml import OxmlElement as OE
from docx.oxml.ns import qn as QN
section = doc.sections[0]
footer = section.footer
pf = footer.paragraphs[0]
pf.alignment = WD_ALIGN_PARAGRAPH.CENTER
pf.paragraph_format.space_before = Pt(4)
rf1 = pf.add_run("SportData & Territoires — Patrick Bayeux — Décideurs du sport  |  "
                  "Sources : data.sports.gouv.fr · Ministère de l'Éducation nationale 2024")
rf1.font.size = Pt(8)
rf1.font.color.rgb = GREY
rf1.italic = True

doc.save(OUT)
print(f"Document créé : {OUT}")
