"""
Transforme le docx original (rempli, à titre d'exemple, version 2) en un
TEMPLATE réutilisable :
- remplace les 2 lignes "Nombres de parcelles concernées" / "Nom de rue..." par
  une ligne d'en-tête "Parcelle | Commune | Réf. cadastrale" (section A) qui
  sert de repère pour insérer dynamiquement 1 à 5 lignes de parcelles.
- nettoie la grille "Mitigations du risque au sol" (section B) : 5 lignes
  parcelle x 3 cases à cocher (M1(A)/M1(C)/M2), déjà présentes dans le fichier
  source sous forme de cellules-content-control (w:sdt enveloppant tout le
  <w:tc>, invisibles pour l'API haut-niveau de python-docx).
- corrige l'en-tête de la grille "Exigence de confinement" (section D),
  initialement un copier-coller erroné de la grille mitigations
  ("Mitigation → Parcelle ↓") -> "Parcelle" / "Densité moyenne (ppl/km²)",
  et porte le nombre de lignes à 5 (une par parcelle possible).
- remet toutes les cases à cocher à l'état non coché (y compris celles des
  deux grilles ci-dessus).
- remplace le texte des combo-box pilotes par le placeholder d'origine.

Ce script n'est exécuté qu'UNE FOIS pour produire
templates_word/FICHE_MISSION_TPZ_template.docx, qui est ensuite le fichier de
référence utilisé par l'appli (jamais modifié directement).
"""
import copy
import docx
from docx.oxml.ns import qn

SRC = "/sessions/epic-sweet-goldberg/mnt/uploads/FICHE_MISSION_TPZ (1).docx"
OUT = "/sessions/epic-sweet-goldberg/mnt/outputs/fiche_mission_app/templates_word/FICHE_MISSION_TPZ_template.docx"

PARCELLE_HEADER_MARKER = "Réf. cadastrale"
N_PARCELLES_MAX = 5


# ---------------------------------------------------------------------------
# Helpers bas niveau (cellules "normales" et cellules encapsulées en w:sdt)
# ---------------------------------------------------------------------------

def real_cells(tr):
    """Retourne la liste des vraies cellules d'une ligne, qu'elles soient
    enfants directs (<w:tc>) ou enveloppées dans un content control
    (<w:sdt><w:sdtContent><w:tc>...). Chaque élément retourné est le <w:tc>
    lui-même ; pour les cellules-checkbox, le <w:sdt> parent est aussi renvoyé."""
    out = []
    for child in tr:
        tag = child.tag.split('}')[-1]
        if tag == 'tc':
            out.append({"tc": child, "sdt": None})
        elif tag == 'sdt':
            content = child.find(qn('w:sdtContent'))
            if content is not None:
                tc = content.find(qn('w:tc'))
                if tc is not None:
                    out.append({"tc": tc, "sdt": child})
    return out


def tc_text(tc):
    return ''.join(t.text or '' for t in tc.iter(qn('w:t'))).strip()


def set_tc_text(tc, text):
    """Remplace le texte d'une cellule brute (w:tc), en gardant la mise en
    forme du premier run existant."""
    p = tc.find(qn('w:p'))
    runs = p.findall(qn('w:r'))
    if runs:
        keep = runs[0]
        t = keep.find(qn('w:t'))
        if t is None:
            t = keep.makeelement(qn('w:t'), {})
            keep.append(t)
        t.text = text
        t.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve')
        for r in runs[1:]:
            p.remove(r)
    else:
        r = p.makeelement(qn('w:r'), {})
        t = r.makeelement(qn('w:t'), {})
        t.text = text
        t.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve')
        r.append(t)
        p.append(r)
    # supprime les paragraphes en trop
    for extra_p in p.getparent().findall(qn('w:p'))[1:]:
        extra_p.getparent().remove(extra_p)


def set_cell_text(cell, text):
    """Version python-docx (pour les cellules non-sdt accessibles via l'API haut niveau)."""
    paragraphs = cell.paragraphs
    p = paragraphs[0]
    runs = p.runs
    if runs:
        keep = runs[0]
        keep.text = text
        for r in runs[1:]:
            r._element.getparent().remove(r._element)
    else:
        p.add_run(text)
    for extra_p in paragraphs[1:]:
        extra_p._element.getparent().remove(extra_p._element)


def clear_checkbox(sdt):
    """Force une case à cocher SDT à l'état non coché + met à jour le glyphe affiché."""
    sdtPr = sdt.find(qn('w:sdtPr'))
    cb = sdtPr.find(qn('w14:checkbox'))
    if cb is None:
        return
    checked = cb.find(qn('w14:checked'))
    unchecked_state = cb.find(qn('w14:uncheckedState'))
    checked.set(qn('w14:val'), '0')
    uncheck_char = chr(int(unchecked_state.get(qn('w14:val')), 16))
    content = sdt.find(qn('w:sdtContent'))
    for t in content.iter(qn('w:t')):
        t.text = uncheck_char


def find_row_by_label(table, label_prefix):
    for r in table.rows:
        if r.cells[0].text.strip().startswith(label_prefix):
            return r
    return None


def clear_value_cell(table, label_prefix, col_index=1, new_text=""):
    r = find_row_by_label(table, label_prefix)
    if r is not None and col_index < len(r.cells):
        set_cell_text(r.cells[col_index], new_text)
        return True
    return False


# ---------------------------------------------------------------------------
# Étape 1 : bloc "Parcelles" — section A
# ---------------------------------------------------------------------------

def restructure_parcelles_section_a(table0):
    rows = table0.rows
    row_nb_parcelles = find_row_by_label(table0, "Nombres de parcelles")
    row_adresse = find_row_by_label(table0, "Nom de rue")
    row_pilotes_tel = find_row_by_label(table0, "Coordonnées téléphoniques")
    assert row_nb_parcelles is not None and row_adresse is not None and row_pilotes_tel is not None

    tmpl_tr = copy.deepcopy(row_pilotes_tel._tr)

    header_tr = copy.deepcopy(tmpl_tr)
    header_row = docx.table._Row(header_tr, table0)
    for c, txt in zip(header_row.cells, ["Parcelle", "Commune", PARCELLE_HEADER_MARKER]):
        set_cell_text(c, txt)
        for run in c.paragraphs[0].runs:
            run.bold = True

    data_tr = copy.deepcopy(tmpl_tr)
    data_row = docx.table._Row(data_tr, table0)
    for c in data_row.cells:
        set_cell_text(c, "")

    row_nb_parcelles._tr.addprevious(header_tr)
    header_tr.addnext(data_tr)

    row_nb_parcelles._tr.getparent().remove(row_nb_parcelles._tr)
    row_adresse._tr.getparent().remove(row_adresse._tr)


# ---------------------------------------------------------------------------
# Étape 2 : grille "Mitigations du risque au sol" (section B) — nettoyage
# ---------------------------------------------------------------------------

def clean_mitigations_grid(table1):
    """Repère la ligne d'en-tête ('Mitigations du risque au sol appliquées :')
    puis les N_PARCELLES_MAX lignes de données qui suivent : vide le nom de
    parcelle (2e cellule) ; les cases à cocher (cellules 3-5) sont laissées en
    place et seront décochées par le nettoyage global des checkboxes."""
    anchor_tr = None
    for tr in table1._tbl.findall(qn('w:tr')):
        cells = real_cells(tr)
        if cells and tc_text(cells[0]["tc"]).startswith("Mitigations du risque au sol"):
            anchor_tr = tr
            break
    assert anchor_tr is not None, "Ligne d'en-tête des mitigations introuvable"

    tr = anchor_tr
    for _ in range(N_PARCELLES_MAX):
        tr = tr.getnext()
        cells = real_cells(tr)
        if len(cells) < 2:
            break
        set_tc_text(cells[1]["tc"], "")


# ---------------------------------------------------------------------------
# Étape 3 : grille "Exigence de confinement" (section D) — en-tête + 5 lignes
# ---------------------------------------------------------------------------

def fix_confinement_grid(table3):
    anchor_tr = None
    for tr in table3._tbl.findall(qn('w:tr')):
        cells = real_cells(tr)
        if cells and tc_text(cells[0]["tc"]).startswith("Densité moyenne dans un rayon de 5 km"):
            anchor_tr = tr
            break
    assert anchor_tr is not None, "Ligne d'en-tête du bloc confinement introuvable"

    header_cells = real_cells(anchor_tr)
    assert len(header_cells) == 3, header_cells
    set_tc_text(header_cells[1]["tc"], "Parcelle")
    set_tc_text(header_cells[2]["tc"], "Densité moyenne (ppl/km²)")
    for run_tc in (header_cells[1]["tc"], header_cells[2]["tc"]):
        for r in run_tc.iter(qn('w:r')):
            rpr = r.find(qn('w:rPr'))
            if rpr is None:
                rpr = r.makeelement(qn('w:rPr'), {})
                r.insert(0, rpr)
            if rpr.find(qn('w:b')) is None:
                rpr.append(rpr.makeelement(qn('w:b'), {}))

    # Repère les lignes de données existantes (texte libre, pas de checkbox) et
    # les vide ; ajoute des lignes clonées jusqu'à atteindre N_PARCELLES_MAX.
    data_trs = []
    tr = anchor_tr
    while True:
        nxt = tr.getnext()
        if nxt is None:
            break
        cells = real_cells(nxt)
        if len(cells) != 3 or any(c["sdt"] is not None for c in cells):
            break  # on a atteint la ligne des cases à cocher <500/<5000
        data_trs.append(nxt)
        tr = nxt

    for dtr in data_trs:
        for c in real_cells(dtr):
            set_tc_text(c["tc"], "")

    last_tr = data_trs[-1] if data_trs else anchor_tr
    while len(data_trs) < N_PARCELLES_MAX:
        new_tr = copy.deepcopy(data_trs[0] if data_trs else last_tr)
        for c in real_cells(new_tr):
            set_tc_text(c["tc"], "")
        last_tr.addnext(new_tr)
        data_trs.append(new_tr)
        last_tr = new_tr


# ---------------------------------------------------------------------------
# Télépilotes : porter la grille à 4 emplacements (2 lignes de noms déjà
# présentes = 4 combos ; on duplique la ligne des téléphones pour obtenir
# 4 cellules de téléphone alignées par colonne avec les 4 noms).
# ---------------------------------------------------------------------------

def _set_vmerge(tc, val):
    """val = 'restart' ou 'continue'. Positionne/insère le w:vMerge de la cellule."""
    tcPr = tc.find(qn('w:tcPr'))
    if tcPr is None:
        tcPr = tc.makeelement(qn('w:tcPr'), {})
        tc.insert(0, tcPr)
    vm = tcPr.find(qn('w:vMerge'))
    if vm is None:
        vm = tcPr.makeelement(qn('w:vMerge'), {})
        tcPr.append(vm)
    vm.set(qn('w:val'), val)


def extend_phone_rows(table0):
    """Duplique la ligne 'Coordonnées téléphoniques télépilote :' pour disposer
    de 4 cellules de téléphone (2 lignes x 2 colonnes), le libellé étant
    fusionné verticalement sur les 2 lignes."""
    phone_tr = None
    for tr in table0._tbl.findall(qn('w:tr')):
        cells = real_cells(tr)
        if cells and tc_text(cells[0]["tc"]).startswith("Coordonnées téléphoniques"):
            phone_tr = tr
            break
    assert phone_tr is not None, "Ligne téléphones introuvable"

    cells = real_cells(phone_tr)
    # vide les 2 cellules de téléphone existantes
    for c in cells[1:]:
        set_tc_text(c["tc"], "")

    # clone -> 2e ligne de téléphones
    new_tr = copy.deepcopy(phone_tr)
    new_cells = real_cells(new_tr)
    for c in new_cells[1:]:
        set_tc_text(c["tc"], "")

    # fusion verticale du libellé : restart sur la 1re ligne, continue (vidé) sur la 2e
    _set_vmerge(cells[0]["tc"], "restart")
    _set_vmerge(new_cells[0]["tc"], "continue")
    set_tc_text(new_cells[0]["tc"], "")

    phone_tr.addnext(new_tr)


# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------

def main():
    d = docx.Document(SRC)
    table0, table1, table2, table3, table4 = d.tables

    restructure_parcelles_section_a(table0)
    clear_value_cell(table0, "Dates souhaitées")
    extend_phone_rows(table0)  # 4 emplacements de téléphone (alignés sur les 4 noms)
    # "Mode de vol" garde sa valeur par défaut "VLOS" dans le template.

    clear_value_cell(table1, "Noms des fichiers kml joints")
    clean_mitigations_grid(table1)
    clear_value_cell(table1, "GRC final")
    clear_value_cell(table1, "Remarques")
    # NB : "Densité de population maximale ... : Données quantitatives : Voir
    # Annexe 1." est maintenant un texte fixe (plus de valeur numérique à vider).

    # Valeurs par défaut demandées (toujours présentes sur la fiche) :
    clear_value_cell(table2, "Hauteur de vol maximale", 1, "40 m AGL")
    clear_value_cell(table2, "ARC final associé", 1, "ARC-B")
    clear_value_cell(table2, "Remarques")
    for r in table2.rows:
        for c in r.cells:
            if c.text.strip().startswith("Si oui, Nom"):
                set_cell_text(c, "Si oui, Nom : ")

    fix_confinement_grid(table3)

    # --- Toutes les cases à cocher -> non cochées (y compris les grilles) ---
    for sdt in d.element.body.iter(qn('w:sdt')):
        sdtPr = sdt.find(qn('w:sdtPr'))
        if sdtPr is not None and sdtPr.find(qn('w14:checkbox')) is not None:
            clear_checkbox(sdt)

    # --- Combo-box pilotes -> placeholder ---
    for sdt in d.element.body.iter(qn('w:sdt')):
        sdtPr = sdt.find(qn('w:sdtPr'))
        if sdtPr is not None and sdtPr.find(qn('w:comboBox')) is not None:
            content = sdt.find(qn('w:sdtContent'))
            for t in content.iter(qn('w:t')):
                t.text = "Choisir un télépilote"

    d.save(OUT)
    print("Template sauvegardé:", OUT)


if __name__ == "__main__":
    main()
