import io, re, shutil, random
from datetime import date
import sys
from openpyxl import load_workbook
from io import BytesIO
from openpyxl import Workbook
from js import console


def save_workbook_to_bytes(wb):
    buffer = io.BytesIO()
    wb.save(buffer)
    return buffer.getvalue()

# Pull variables set by JS
template_uint8 = globals().get("template_uint8")                  #get les id du html par le java
txt_content = globals().get("txt_content")
typeDoc = globals().get("typeDoc")
nom_du_releveur = globals().get("nom_du_releveur")
hauteur_bosch = globals().get("hauteur_bosch")

# Convert template bytes into Python bytes
template_bytes = bytes(template_uint8)

# --- Start of your original dictionaries and logic (slightly adapted) ---

cells = {}
if typeDoc == "uds":
    cells = {
        "poteau": "B4",
        "projet": "K3",
        "révision": "O3",
        "travaux": "B3",
        "diametre": "H3",
        "adresse": "K4",
        "plan": "H4",
        "code_barre": "N6",
        "pro_poteau": "K7",
        "annee_inspection": "H5",
        "parc": "K5",
        "option_HQ":"N5",
        "longueur": "C6",
        "classe": "D6",
        "annee": "H6",
        "circonference": "K6",
        "p/r":"D7",
        "usage_commun:": "O7",
        "angle": "K13",
        "lclc": "K14",
        "nbe_transfo": "L15",
        "type_transfo": "K15",
        "equip": "K16",
        "gradation": "K17",
        "lampadaire":"K18",
        "las":"K19",
        "montage_HQ":"K20",
        "portee_lache":"K21",
        "portee_pre:": "K22",
        "portee_sui:": "N22",
        "malt":"N21",
        "reseau":"N20",
        "cabinet":"O19",
        "luminaire":"N18",
        "traverse":"O17",
        "las":"N16",
        "fosse": "O14",
        "hauteur_transfo": "O15",
        "hauteur_top": "A11",
        "portee_pre:": "B14",
        "portee_sui:": "C14",
        "hauteur_mt1": "A14",
        "conducteur_mt1": "C14",
        "phase_mt1": "B14",
        "deri_mt1": "D14",
        "hauteur_mt2": "A15",
        "conducteur_mt2": "C15",
        "phase_mt2": "B15",
        "deri_mt2": "D15",
        "hauteur_mt3:": "A16",
        "conducteur_mt3": "C16",
        "phase_mt3": "B16",
        "deri_mt3": "D16",
        "hauteur_bt1": "A23",
        "conducteur_bt1": "B23",
        "visee_bt1": "C23",
        "deri_bt1": "D23",
        "hauteur_bt2": "A22",
        "conducteur_bt2": "B22",
        "visee_bt2": "C22",
        "deri_bt2": "D22",
        "hauteur_bt3": "A21",
        "conducteur_mbt3": "B21",
        "visee_bt3": "C21",
        "deri_bt3": "D21",
        "hauteur_bt4": "A20",
        "conducteur_bt4": "B20",
        "visee_bt4": "C20",
        "deri_bt4": "D20",
        "hauteur_bt5": "A19",
        "conducteur_bt5": "B19",
        "visee_bt5": "C19",
        "deri_bt5": "D19",
        "hauteur_bt6": "A18",
        "conducteur_bt6:": "B18",
        "visee_bt6": "C18",
        "deri_bt6": "D18",
        "hauteur_toron1": "A27",
        "proprio_toron1": "B27",
        "toron1_existant": "C27",
        "deri":"D27",
        "type_toron1": "J27",
        "nbe_de_cable_toron1": "L27",
        "diametre_toron1": "K27",
        "rupture_toron1": "M27",
        "deg_sol_toron1": "N27",
        "ancre_toron1": "O27",
        "hauteur_toron2": "A28",
        "proprio_toron2": "B28",
        "existant_toron2": "C28",
        "deri_toron2": "D28",
        "type_toron2": "J28",
        "nbe_de_cable_toron2": "L28",
        "diametre_toron2": "K28",
        "rupture_toron2": "M28",
        "deg_sol_toron2": "N28",
        "ancre_toron2": "O28",
        "hauteur_toron3": "A29",
        "proprio_toron3": "B29",
        "existant_toron3": "C29",
        "deri_toron3": "D29",
        "type_toron3": "J29",
        "nbe_de_cable_toron3": "L29",
        "diametre_toron3": "K29",
        "rupture_toron3": "M29",
        "deg_sol_toron3": "N29",
        "ancre_toron3": "O29",
        "hauteur_toron4": "A30",
        "proprio_toron4": "B30",
        "existant_toron4": "C30",
        "deri_toron4": "D30",
        "type_toron4": "J30",
        "nbe_de_cable_toron4": "L30",
        "diametre_toron4": "K30",
        "rupture_toron4": "M30",
        "deg_sol_toron4": "N30",
        "ancre_toron4": "O30",
        "hauteur_toron5": "A31",
        "proprio_toron5": "B31",
        "existant_toron5": "C31",
        "deri_toron5": "D31",
        "type_toron5": "J31",
        "nbe_de_cable_toron5": "L31",
        "diametre_toron5": "K31",
        "rupture_toron5": "M31",
        "deg_sol_toron5": "N31",
        "ancre_toron5": "O31",
        "hauteur_toron6": "A32",
        "proprio_toron6": "B32",
        "existant_toron6": "C32",
        "deri_toron6": "D32",
        "type_toron6": "J32",
        "nbe_de_cable_toron6": "L32",
        "diametre_toron6": "K32",
        "rupture_toron6": "M32",
        "deg_sol_toron6": "N32",
        "ancre_toron6": "O32",
        "type_de_sol_ancre1": "K36",
        "capacite_ancre1": "K37",
        "angle_ancre1":"K38",
        "hauban1_ancre1": "K39",
        "hauban2_ancre1": "K40",
        "hauban3_ancre1": "K41",
        "hauban4_ancre1": "K42",
        "tige_ancre1":"K43",
        "cosse_ancre1": "K44",
        "ecart_ancre1": "K45",
        "type_ancre1": "K46",
        "devi_ancre1": "K47",
        "espace_dispo_ancre1": "K48",
        "etat_ancre1": "K49",
        "type_de_sol_ancre2": "M36",
        "capacite_ancre2": "M37",
        "angle_ancre2":"M38",
        "hauban1_ancre2": "M39",
        "hauban2_ancre2": "M40",
        "hauban3_ancre2": "M41",
        "hauban4_ancre2": "M42",
        "tige_ancre2":"M43",
        "cosse_ancre2": "M44",
        "ecart_ancre2": "M45",
        "type_ancre2": "M46",
        "devi_ancre2": "M47",
        "espace_dispo_ancre2": "M48",
        "etat_ancre2": "M49",
        "type_de_sol_ancre3": "N36",
        "capacite_ancre3": "N37",
        "angle_ancre3": "N38",
        "hauban1_ancre3": "N39",
        "hauban2_ancre3": "N40",
        "hauban3_ancre3": "N41",
        "hauban4_ancre3": "N42",
        "tige_ancre3": "N43",
        "cosse_ancre3": "N44",
        "ecart_ancre3": "N45",
        "type_ancre3": "N46",
        "devi_ancre3": "N47",
        "espace_dispo_ancre3": "N48",
        "etat_ancre3": "N49",
        "type_de_sol_ancre4": "O36",
        "capacite_ancre4": "O37",
        "angle_ancre4": "O38",
        "hauban1_ancre4": "O39",
        "hauban2_ancre4": "O40",
        "hauban3_ancre4": "O41",
        "hauban4_ancre4": "O42",
        "tige_ancre4": "O43",
        "cosse_ancre4": "O44",
        "ecart_ancre4": "O45",
        "type_ancre4": "O46",
        "devi_ancre4": "O47",
        "espace_dispo_ancre4": "O48",
        "etat_ancre4": "O49",
        "ligne_haute_tension": "K51",
        "element_sensible": "O51",
        "note": "A56",
        "date": "K62",
    }
elif typeDoc == "rsa":
    cells = {
        "poteau": "B1",
        "projet": "F1",
        "révision": "I1",
        "travaux": "B2",
        "diametre": "D2",
        "classification_travaux":'F2',
        "anomalie_1": "B3",
        "anomalie_2": "B4",
        "anomalie_3": "B5",
        "probleme_1": "E3",
        "probleme_2": "E4",
        "probleme_3": "E5",
        "nom_poteau": "B6",
        "adresse": "D6",
        "plan": "G6",
        "code_barre": "I6",
        "pro_poteau": "B7",
        "usage_commun:": "D7",
        "parc": "F7",
        "lclc": "I7",
        "longueur": "B8",
        "classe": "D8",
        "annee": "F8",
        "nbe_transfo": "H8",
        "type_transfo": "I8",
        "annee_inspection": "B9",
        "modele_bell": "D9",
        "modele_HQ": "F9",
        "equip": "H9",
        "fosse": "B9",
        "hauteur_lampadaire": "D10",
        "cabinet": "F10",
        "hauteur_transfo": "H10",
        "hauteur_top": "A14",
        "portee_pre:": "B14",
        "portee_sui:": "C14",
        "portee_dero": "D14",
        "toron_ins": "E14",
        "milieu": "G13",
        "hauteur_mt1": "A16",
        "conducteur_mt1": "B16",
        "phase_mt1": "C16",
        "deri_mt1": "D16",
        "hauteur_mt2": "A17",
        "conducteur_mt2": "B17",
        "phase_mt2": "C17",
        "deri_mt2": "D17",
        "hauteur_mt3": "A18",
        "conducteur_mt3": "B18",
        "phase_mt3": "C18",
        "deri_mt3": "D18",
        "hauteur_mt4": "A19",
        "conducteur_mt4": "B19",
        "phase_mt4": "C19",
        "deri_mt4": "D19",
        "hauteur_mt5": "A20",
        "conducteur_mt5:": "B20",
        "phase_mt5": "C20",
        "deri_mt5": "D20",
        "hauteur_bt1": "A27",
        "conducteur_bt1": "B27",
        "visee_bt1": "C27",
        "deri_bt1": "D27",
        "hauteur_bt2": "A26",
        "conducteur_bt2": "B26",
        "visee_bt2": "C26",
        "deri_bt2": "D26",
        "hauteur_bt3": "A25",
        "conducteur_mbt3": "B25",
        "visee_bt3": "C25",
        "deri_bt3": "D25",
        "hauteur_bt4": "A24",
        "conducteur_bt4": "B24",
        "visee_bt4": "C24",
        "deri_bt4": "D24",
        "hauteur_bt5": "A23",
        "conducteur_bt5": "B23",
        "visee_bt5": "C23",
        "deri_bt5": "D23",
        "hauteur_bt6": "A22",
        "conducteur_bt6:": "B22",
        "visee_bt6": "C22",
        "deri_bt6": "D22",
        "hauteur_toron1": "A29",
        "proprio_toron1": "B29",
        "type_toron1": "C29",
        "nbe_de_cable_toron1": "D29",
        "diametre_toron1": "E29",
        "rupture_toron1": "F29",
        "deg_sol_toron1": "G29",
        "croisement_toron1": "H29",
        "ancre_toron1": "I29",
        "hauteur_toron2": "A30",
        "proprio_toron2": "B30",
        "type_toron2": "C30",
        "nbe_de_cable_toron2": "D30",
        "diametre_toron2": "E30",
        "rupture_toron2": "F30",
        "deg_sol_toron2": "G30",
        "croisement_toron2": "H30",
        "ancre_toron2": "I30",
        "hauteur_toron3": "A31",
        "proprio_toron3": "B31",
        "type_toron3": "C31",
        "nbe_de_cable_toron3": "D31",
        "diametre_toron3": "E31",
        "rupture_toron3": "F31",
        "deg_sol_toron3": "G31",
        "croisement_toron3": "H31",
        "ancre_toron3": "I31",
        "hauteur_toron4": "A32",
        "proprio_toron4": "B32",
        "type_toron4": "C32",
        "nbe_de_cable_toron4": "D32",
        "diametre_toron4": "E32",
        "rupture_toron4": "F32",
        "deg_sol_toron4": "G32",
        "croisement_toron4": "H32",
        "ancre_toron4": "I32",
        "hauteur_toron5": "A33",
        "proprio_toron5": "B33",
        "type_toron5": "C33",
        "nbe_de_cable_toron5": "D33",
        "diametre_toron5": "E33",
        "rupture_toron5": "F33",
        "deg_sol_toron5": "G33",
        "croisement_toron5": "H33",
        "ancre_toron5": "I33",
        "hauteur_toron6": "A34",
        "proprio_toron6": "B34",
        "type_toron6": "C34",
        "nbe_de_cable_toron6": "D34",
        "diametre_toron6": "E34",
        "rupture_toron6": "F34",
        "deg_sol_toron6": "G34",
        "croisement_toron6": "H34",
        "ancre_toron6": "I34",
        "type_de_sol_ancre1": "F17",
        "tige_ancre1": "F18",
        "cosse_ancre1": "F19",
        "type_ancre1": "F20",
        "ecart_ancre1": "F21",
        "hauban1_ancre1": "F22",
        "hauban2_ancre1": "F23",
        "hauban3_ancre1": "F24",
        "hauban4_ancre1": "F25",
        "etat_ancre1": "f26",
        "espace_dispo_ancre1": "F27",
        "type_de_sol_ancre2": "G17",
        "tige_ancre2": "G18",
        "cosse_ancre2": "G19",
        "type_ancre2": "G20",
        "ecart_ancre2": "G21",
        "hauban1_ancre2": "G22",
        "hauban2_ancre2": "G23",
        "hauban3_ancre2": "G24",
        "hauban4_ancre2": "G25",
        "etat_ancre2": "G26",
        "espace_dispo_ancre2": "G27",
        "type_de_sol_ancre3": "H17",
        "tige_ancre3": "H18",
        "cosse_ancre3": "H19",
        "type_ancre3": "H20",
        "ecart_ancre3": "H21",
        "hauban1_ancre3": "H22",
        "hauban2_ancre3": "H23",
        "hauban3_ancre3": "H24",
        "hauban4_ancre3": "H25",
        "etat_ancre3": "H26",
        "espace_dispo_ancre3": "H27",
        "type_de_sol_ancre4": "I17",
        "tige_ancre4": "I18",
        "cosse_ancre4": "I19",
        "type_ancre4": "I20",
        "ecart_ancre4": "I21",
        "hauban1_ancre4": "I22",
        "hauban2_ancre4": "I23",
        "hauban3_ancre4": "I24",
        "hauban4_ancre4": "I25",
        "etat_ancre4": "I26",
        "espace_dispo_ancre4": "I27" ,
        "ligne_haute_tension": "A36",
        "dis_appro": "C36",
        "element_sensible": "D36",
        "coord": "G36",
        "note": "A38",
        "date": "F49",
        "releveur": "F47",
    }
else:
    raise Exception("Erreur: typeDoc invalide (uds ou rsa requis)")

# keep your type_poteaux & parc dictionaries exactly
type_poteaux = {
    74:(35, 5),
    79:{'JP': (35, 5), 'SYP': (40, 5), 'LPP': (35, 5)},
    80:(35, 4),
    81:(35, 5),
    82:(45, 5),
    83:{'LPP': (40, 5), 'WRC': (35, 5)},
    84:(40, 5),
    86:{'RP': (40, 5), 'JP': (35, 4)},
    87:(45, 5),
    88:{'RP': (35, 4), 'JP': (45, 5), 'WRC': (40, 5)},
    89:(45, 4),
    90:{'RP': (45, 5), 'LPP': (40, 4), 'WRC': (35, 4)},
    91:(40, 4),
    92:(45, 5),
    93:{'RP': (40, 4), 'SYP': (35, 2)},
    94:(45, 4),
    95:{'JP': (45, 4), 'WRC': (40, 4)},
    97:(45, 4),
    98: {'SYP': (40, 2), 'LPP': (35, 2)},
    99:(35, 2),
    100:(45, 4),
    101:(35, 2),
    103:{'SYP': (45, 2), 'WRC': (35, 2)},
    104:(40, 2),
    105:(40, 2),
    107:(40, 2),
    109:(45, 2),
    110:{'JP': (45, 2), 'WRC': (40, 2)},
    112:(45, 2),
    115:(45, 2),
}

parc = {
    "304":("saint-remi","saint-michel","sherrington"),
    "339":("sainte-clotilde","saint-chrysostome","hemmingford","havelock"),
    "303":("franklin","ormstown","saint-antoine","hinchinbrooke","godmanchester","huntingdon","saint-anicet","dundee","elgin"),
    "306":("lacolle","napierville","saint-bernard-de-lacolle"),
    "363":("saint-barbe","saint-stanislas-de-kostka","saint-etienne-de-beauharnois","saint-louis-de-gonzague"),
}

# We'll parse the txt content similar to your script
lines = txt_content.splitlines()
valeurs = {}
outputs = []  # list of tuples (filename, bytes)

def create_excel_from_valeurs(valeurs_dict):
    # create a name and a workbook based on the uploaded template bytes
    nom_du_poteau = valeurs_dict.get('poteau', 'poteau').strip() + '.xlsx'
    # load a fresh workbook from template bytes
    bio = io.BytesIO(template_bytes)
    wb = load_workbook(filename=bio)
    # choose 'Grille' sheet if exists else active
    if 'Grille' in wb.sheetnames:
        ws = wb['Grille']
    else:
        ws = wb.active

    for key, value in list(valeurs_dict.items()):
        try:
            champs = cells[key]
            ws[champs] = value
        except Exception:
            # ignore keys not present in cells
            continue

    out_bytes = save_workbook_to_bytes(wb)
    return nom_du_poteau, out_bytes

# helper to safely convert floats when needed
def safe_float(x):
    try:
        return float(x)
    except:
        return None

# The main parsing loop (close to your original)
for line in lines:
    if '---' in line:
        # finalize current record
        if 'poteau' in valeurs and valeurs.get('poteau','').strip() != '':
            fname, b = create_excel_from_valeurs(valeurs)
            outputs.append((fname, b))
            console.log(f'Created output: {fname}')
        valeurs = {}
        continue

    if line.strip() == "":
        continue

    if ':' not in line:
        continue

    variable, value = line.split(":", 1)
    variable = variable.strip()
    value = value.rstrip("\n")

    # replicate your special handling rules
    if 'hauteur' or "deg" in variable:
        if value.strip() == "":
            continue

     # compute with hauteur_bosch (string)
        try:
            c = float(value)
            a = 1
            hb = float(hauteur_bosch)
            b = (c**2 - a**2)**0.5 + hb
            b = round(b, 2)
            value = str(b).replace(".", ",")

        except Exception:

            if value.strip() == 'tri':
                valeurs["hauteur_top"] = str(valeurs["hauteur_top"].replace(",", "."))
                value = str(round(float(valeurs['hauteur_top']) + 0.3, 2)).replace(".", ",")
                valeurs["hauteur_mt2"] = str(round(float(valeurs['hauteur_top']) - 0.15,2)).replace(".", ",")
                valeurs["hauteur_top"] = str(valeurs["hauteur_top"].replace(".", ","))
            pass

    if 'nom_poteau' in variable:
        # copy name from 'poteau' (first token)
        if 'poteau' in valeurs:
            value = valeurs["poteau"].split(" ", 1)[0]

    if 'adresse' in variable:

         # =================================================================
            # Utilise re.sub() pour retirer le texte non numérique au début,
            # puis supprimer toute indication de type "+2" ou "-3" accolée
            # au numéro principal, en conservant le reste de l'adresse.
            #
            # Expression utilisée : r'^\D*(\d+)(?:[+-]\d+)?(.*)'
            # - ^         → début de la chaîne
            # - \D*       → zéro ou plusieurs caractères qui NE sont PAS des chiffres
            #               (supprime par exemple "PHD", "PHC", etc.)
            # - (\d+)     → capture le numéro principal (un ou plusieurs chiffres)
            # - (?: ... ) → parenthèses non capturantes (pour regrouper sans créer un groupe séparé)
            # - [+-]\d+   → un signe "+" ou "-" suivi d'un ou plusieurs chiffres
            #               (par ex. "+2" ou "-3")
            # - ?         → rend la partie [+-]\d+ optionnelle
            # - (.*)      → capture tout le reste de la chaîne (l'adresse après le numéro)
            #
            # Remplacement utilisé : r'\1\2'
            # - \1 → insère le numéro principal capturé
            # - \2 → insère le texte restant de l'adresse
            #
            # Exemple :
            # "PHD248+2 chemin de l'église" devient "248 chemin de l'église"
            # "PHC300-1 rue des lilas"     devient "300 rue des lilas"
            # =================================================================
        if 'poteau' in valeurs:
            value = re.sub(r'^\D*(\d+)(?:[+-]\d+)?(.*)', r'\1\2', valeurs["poteau"])

    if 'date' in variable:
        if typeDoc == 'uds':
            value = str(nom_du_releveur + '\\n') + str(date.today())
        else:
            value = str(date.today())

    if 'longueur' in variable:
        
        value = value.strip()
       
        try:
            value_int = int(value)
        except ValueError:           
            continue

        if value_int not in type_poteaux:
            valeurs[variable] = value
            continue

        type_poteaux_entre = type_poteaux[value_int]
       
        if isinstance(type_poteaux_entre, dict):    
            
            bois = valeurs.get('bois', '').strip()
            if bois == '':
                value = next(iter(type_poteaux_entre.values()))[0]  
                valeurs['classe'] = next(iter(type_poteaux_entre.values()))[1] 
                valeurs[variable] = value                                             #Créer une itérateur qui permet de parcourir les éléments une par une
                continue

            valeurs['classe'] = type_poteaux_entre[bois][1]
            value = type_poteaux_entre[bois][0]
        else:
            valeurs['classe'] = type_poteaux_entre[1]
            value = type_poteaux_entre[0]

    if "ville" in variable:
        # determine parc key covering the town name
        found = None
        for k,v in parc.items():
            if value.strip() in v:
                found = k
                break
        valeurs['parc'] = found

    if "releveur" in variable:

        value = nom_du_releveur

    # finally store the variable
    valeurs[variable] = value

# if file doesn't end with '---', create last record
if valeurs and 'poteau' in valeurs and valeurs.get('poteau','').strip() != '':
    fname, b = create_excel_from_valeurs(valeurs)
    outputs.append((fname, b))

from js import Uint8Array, Blob, URL, document

for fname, bbytes in outputs:
    u8 = Uint8Array.new(bbytes)  # explicitly convert Python bytes to JS Uint8Array
    blob = Blob.new([u8], { "type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" })
    url = URL.createObjectURL(blob)
    a = document.createElement("a")
    a.href = url
    a.download = fname
    a.textContent = "[Télécharger] " + fname
    document.getElementById("downloads").appendChild(a)
    console.log("Prepared download for " + fname)


# also print a summary to the page console element
from js import console as js_console
js_console.log(f"Created {len(outputs)} file(s).")
print(f"Created {len(outputs)} file(s).")  # visible in the log element too









