from random import choice, shuffle
from os import makedirs
import os

#version 3.1.0 - PDF et OG parfaits

nbexo=10000

langage="E" #E ou FR
dico_files={}
dico_files["E"]="dico_anglais.txt"
dico_files["FR"]="dico.txt"

# Chargement du dictionnaire
fichier = open(dico_files[langage], "r")
dico_list = fichier.read().split()
fichier.close()

# OPTIMISATION : Utiliser un set pour les recherches O(1)
dico_set = set(mot for mot in dico_list if 3 <= len(mot) < 17)

# Créer un set de préfixes
prefixes = set()
for mot in dico_set:
    for i in range(2, len(mot)):
        prefixes.add(mot[:i])

svg_template="""<svg width="100%" height="100%" viewBox="0 0 425 425" xmlns="http://www.w3.org/2000/svg" style="max-width: 100%; height: auto;">
  <rect x="25" y="25" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="70" y="80" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="120" y="25" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="165" y="80" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="215" y="25" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="260" y="80" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="310" y="25" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="355" y="80" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="25" y="120" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="70" y="175" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="120" y="120" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="165" y="175" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="215" y="120" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="260" y="175" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="310" y="120" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="355" y="175" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="25" y="215" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="70" y="270" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="120" y="215" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="165" y="270" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="215" y="215" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="260" y="270" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="310" y="215" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="355" y="270" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="25" y="310" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="70" y="365" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="120" y="310" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="165" y="365" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="215" y="310" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="260" y="365" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="310" y="310" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="355" y="365" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
</svg>"""

# SVG pour PDF (dimensions fixes pour WeasyPrint)
svg_template_pdf="""<svg width="400" height="400" viewBox="0 0 425 425" xmlns="http://www.w3.org/2000/svg">
  <rect x="25" y="25" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="70" y="80" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="120" y="25" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="165" y="80" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="215" y="25" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="260" y="80" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="310" y="25" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="355" y="80" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="25" y="120" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="70" y="175" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="120" y="120" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="165" y="175" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="215" y="120" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="260" y="175" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="310" y="120" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="355" y="175" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="25" y="215" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="70" y="270" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="120" y="215" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="165" y="270" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="215" y="215" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="260" y="270" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="310" y="215" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="355" y="270" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="25" y="310" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="70" y="365" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="120" y="310" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="165" y="365" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="215" y="310" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="260" y="365" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
  
  <rect x="310" y="310" width="90" height="90" fill="white" stroke="black" stroke-width="3"/>
  <text x="355" y="365" font-size="48" font-family="Arial" text-anchor="middle" font-weight="bold">{}</text>
</svg>"""

des=[ "ETUKNO",
      "EVGTIN",
      "DECAMP",
      "IELRUW",
      "EHIFSE",
      "RECALS",
      "ENTDOS",
      "OFXRIA",
      "NAVEDZ",
      "EIOATA",
      "GLENYU",
      "BMAQJO",
      "TLIBRA",
      "SPULTE",
      "AIMSOR",
      "ENHRIS"]

leplateau=""
      
plateau=[[1,4,5],
         [0,2,4,5,6],
         [1,3,5,6,7],
         [2,6,7],
         [0,1,5,8,9],
         [0,1,2,4,6,8,9,10],
         [1,2,3,5,7,9,10,11],
         [2,3,6,10,11],
         [4,5,9,12,13],
         [4,5,6,8,10,12,13,14],
         [5,6,7,9,11,13,14,15],
         [6,7,10,14,15],
         [8,9,13],
         [8,9,10,12,14],
         [9,10,11,13,15],
         [10,11,14]]

consigne={}
consigne["FR"]="Trouvez des mots de 3 lettres minimum en reliant des cases adjacentes"
consigne["E"]="Find words of 3+ letters by connecting adjacent cells"

regles_completes={}
regles_completes["FR"]="""<h3>Règles du jeu :</h3>
<ul>
<li>Cherchez des mots pouvant être formés à partir de lettres <strong>adjacentes</strong> du plateau (horizontalement, verticalement ou en diagonale)</li>
<li>Les mots doivent être de <strong>3 lettres minimum</strong></li>
<li>On ne peut pas utiliser plusieurs fois le même dé pour le même mot</li>
<li>Durée : <strong>3 minutes</strong></li>
</ul>
<h3>Calcul des points :</h3>
<table border="1" cellpadding="8" style="border-collapse: collapse; margin: 20px 0;">
<thead>
<tr><th>Lettres</th><th>Points</th></tr>
</thead>
<tbody>
<tr><td>3-4</td><td>1</td></tr>
<tr><td>5</td><td>2</td></tr>
<tr><td>6</td><td>3</td></tr>
<tr><td>7</td><td>5</td></tr>
<tr><td>8+</td><td>11</td></tr>
</tbody>
</table>
<p><em>Si plusieurs joueurs trouvent le même mot, il est rayé de toutes les listes.</em></p>"""

regles_completes["E"]="""<h3>Game Rules:</h3>
<ul>
<li>Find words from <strong>adjacent</strong> letters (horizontally, vertically, or diagonally)</li>
<li>Words must be <strong>3+ letters</strong> long</li>
<li>Cannot use the same cube twice in one word</li>
<li>Duration: <strong>3 minutes</strong></li>
</ul>
<h3>Scoring:</h3>
<table border="1" cellpadding="8" style="border-collapse: collapse; margin: 20px 0;">
<thead>
<tr><th>Letters</th><th>Points</th></tr>
</thead>
<tbody>
<tr><td>3-4</td><td>1</td></tr>
<tr><td>5</td><td>2</td></tr>
<tr><td>6</td><td>3</td></tr>
<tr><td>7</td><td>5</td></tr>
<tr><td>8+</td><td>11</td></tr>
</tbody>
</table>
<p><em>If multiple players find the same word, it is removed from all lists.</em></p>"""

phrase_corr={}
phrase_corr["FR"]="""<p style="margin: 10px 0;"><strong>{0} mot{1} de {2} lettres ({3} point{1}) :</strong> """
phrase_corr["E"]="""<p style="margin: 10px 0;"><strong>{0} word{1} of {2} letters ({3} point{1}):</strong> """

repertoires={}
repertoires["FR"]=("ennonces_html_FR","corriges_html_FR","exercices_pdf_FR","og_images_FR")
repertoires["E"]=("ennonces_html_E","corriges_html_E","exercices_pdf_E","og_images_E")

url_base={}
url_base["FR"]="https://site2wouf.fr/boggle_Fr.php?x="
url_base["E"]="https://site2wouf.fr/boggle_E.php?x="

def sauv_ex(chaine):
    with open(repertoires[langage][0]+"/"+leplateau+".html", "w", encoding='utf-8') as f:
        f.write(chaine)

def sauv_corr(chaine):
    with open(repertoires[langage][1]+"/"+leplateau+".html", "w", encoding='utf-8') as f:
        f.write(chaine)
        
def pluriel(x):
    return "s" if x > 1 else ""

def points_mot(n):
    if n < 5:
        return 1
    elif n == 5:
        return 2
    elif n == 6:
        return 3
    elif n == 7:
        return 5
    else:
        return 11
    
def melange():
    global leplateau
    leplateau = ""
    for de in des:
        leplateau += choice(de)
    liste = list(leplateau)
    shuffle(liste)
    leplateau = "".join(liste)

def lemot(liste):
    return "".join(leplateau[l] for l in liste)

def purge(liste):
    seen = {}
    for item in liste:
        item = item.strip()
        if item not in seen:
            seen[item] = True
    return sorted(seen.keys())

def in_dico(lettres):
    return lettres in prefixes

def etape_1():
    global listes
    liste = []
    for n in range(16):
        for k in plateau[n]:
            mot = lemot([n, k])
            if mot in prefixes:
                liste.append([n, k])
    listes.append(liste)
    
def etape_suivante():
    global listes
    taille = len(listes) + 2
    print("Mots de {} lettres".format(taille))
    liste = []
    mots_trouves = set()
    
    for j in listes[-1]:
        for k in plateau[j[-1]]:
            if k not in j:
                nouveau = j + [k]
                mot = lemot(nouveau)
                
                if mot in dico_set:
                    mots_trouves.add(mot)
                
                if mot in prefixes:
                    liste.append(nouveau)
    
    mots_liste = sorted(mots_trouves)
    nb_mots = len(mots_liste)
    
    print("Nombre : ", nb_mots)
    chaine = ""
    
    if nb_mots > 0:
        pts = points_mot(taille)
        # Format avec classe CSS spécifique par taille
        chaine = f'<p class="boggle-solution-ligne boggle-mots-{taille}"><strong class="boggle-solution-label">'
        chaine += phrase_corr[langage].format(nb_mots, pluriel(nb_mots), taille, pts).replace('<p style="margin: 10px 0;"><strong>', '').replace('</strong> ', '</strong>')
        chaine += '<span class="boggle-solution-mots">'
        
        for u in mots_liste:
            print(u, end="; ")
            chaine += u + "; "
        print()
        chaine = chaine[:-2]  # Enlever le dernier "; "
        chaine += ".</span></p>"
    
    listes.append(liste)    
    return chaine, nb_mots  # Retourner aussi le nombre

def generer_qrcode(url, filepath):
    """Génère un QR code"""
    try:
        import qrcode
        qr = qrcode.QRCode(version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=10, border=2)
        qr.add_data(url)
        qr.make(fit=True)
        img = qr.make_image(fill_color="black", back_color="white")
        img.save(filepath)
        return True
    except ImportError:
        print("Warning: qrcode not installed")
        return False

def creer_image_og():
    """Crée une image OG : grille à gauche, règles à droite avec couleurs"""
    try:
        from PIL import Image, ImageDraw, ImageFont
        
        # Taille OG standard avec fond dégradé simulé
        img = Image.new('RGB', (1200, 630), color='white')
        draw = ImageDraw.Draw(img)
        
        # Fond avec bandes de couleur
        # Bande supérieure bleue
        draw.rectangle([0, 0, 1200, 100], fill='#3498db')
        # Bande inférieure claire
        draw.rectangle([0, 100, 1200, 630], fill='#ecf0f1')
        
        # Polices
        try:
            font_title = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 52)
            font_text = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 30)
            font_plateau = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf", 56)
            font_small = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 24)
        except:
            font_title = font_text = font_plateau = font_small = ImageFont.load_default()
        
        # Titre BOGGLE en blanc sur fond bleu
        draw.text((600, 50), "BOGGLE", fill='white', font=font_title, anchor="mm")
        
        # GAUCHE : Grille 4x4
        start_x = 60
        start_y = 150
        cell_size = 105
        
        for i in range(4):
            for j in range(4):
                x = start_x + j * cell_size
                y = start_y + i * cell_size
                # Rectangle avec couleur alternée
                if (i + j) % 2 == 0:
                    fill_color = '#ffffff'
                else:
                    fill_color = '#f8f9fa'
                draw.rectangle([x, y, x + cell_size, y + cell_size], 
                             outline='#2c3e50', width=4, fill=fill_color)
                # Lettre
                idx = i * 4 + j
                lettre = leplateau[idx]
                draw.text((x + cell_size//2, y + cell_size//2), lettre, 
                         fill='#2c3e50', font=font_plateau, anchor="mm")
        
        # DROITE : Consigne + Règles
        right_x = 580
        y_pos = 160
        
        # Consigne
        consigne_text = consigne[langage]
        
        # Découper la consigne en lignes
        words = consigne_text.split()
        lines = []
        current_line = []
        max_width = 580
        
        for word in words:
            test_line = ' '.join(current_line + [word])
            bbox = draw.textbbox((0, 0), test_line, font=font_text)
            if bbox[2] - bbox[0] <= max_width:
                current_line.append(word)
            else:
                if current_line:
                    lines.append(' '.join(current_line))
                current_line = [word]
        if current_line:
            lines.append(' '.join(current_line))
        
        for line in lines:
            draw.text((right_x, y_pos), line, fill='#2c3e50', font=font_text)
            y_pos += 42
        
        y_pos += 40
        
        # Règles supplémentaires avec puces colorées
        rules = []
        if langage == "FR":
            rules = [
                "• 3 lettres minimum",
                "• Cases adjacentes",
                "• Durée : 3 minutes"
            ]
        else:
            rules = [
                "• 3+ letters minimum",
                "• Adjacent cells",
                "• Duration: 3 minutes"
            ]
        
        for rule in rules:
            draw.text((right_x, y_pos), rule, fill='#e74c3c', font=font_small)
            y_pos += 38
        
        # Cadre décoratif autour de la zone droite
        draw.rectangle([560, 140, 1180, y_pos + 20], outline='#3498db', width=3)
        
        # Site web en bas à droite avec couleur
        draw.text((1150, 605), "site2wouf.fr", fill='#3498db', font=font_small, anchor="rm")
        
        # Sauvegarder
        filepath = f"{repertoires[langage][3]}/{leplateau}.png"
        img.save(filepath, 'PNG', optimize=True)
        print(f"✓ Image OG créée : {filepath}")
        return True
    except ImportError as e:
        print(f"Warning: PIL not installed - {e}")
        return False

def creer_pdf_complet(enonce_html, correction_html):
    """Crée un PDF : Page 1 = grille verticale + consigne + QR, Page 2 = correction + règles"""
    try:
        from weasyprint import HTML, CSS
        
        url_qrcode = url_base[langage] + leplateau
        qr_filepath = f"{repertoires[langage][2]}/qr_{leplateau}.png"
        
        # Générer le QR code
        qr_exists = generer_qrcode(url_qrcode, qr_filepath)
        
        # HTML pour le PDF
        html_content = f"""
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
        @page {{
            size: A4;
            margin: 2cm 2cm 2.5cm 2cm;
            
            @top-left {{
                content: "BOGGLE_{langage}";
                font-weight: bold;
                font-size: 12pt;
                font-family: Arial, sans-serif;
            }}
            
            @top-right {{
                content: "{leplateau}";
                font-size: 10pt;
                font-family: monospace;
            }}
            
            @bottom-center {{
                content: "Page " counter(page) " / 3";
                font-size: 10pt;
                font-family: Arial, sans-serif;
            }}
            
            @bottom-right {{
                content: "© site2wouf.fr 2026";
                font-size: 10pt;
                font-family: Arial, sans-serif;
            }}
        }}
        
        body {{
            font-family: Arial, sans-serif;
            font-size: 11pt;
        }}
        
        h1 {{
            text-align: center;
            margin: 0 0 20px 0;
            font-size: 24pt;
            color: #333;
        }}
        
        h2 {{
            text-align: center;
            margin: 20px 0 10px 0;
            font-size: 16pt;
            color: #666;
        }}
        
        .page-enonce {{
            position: relative;
        }}
        
        .qr-code {{
            position: absolute;
            top: 0;
            right: 0;
            width: 3cm;
            height: 3cm;
        }}
        
        .grille-container {{
            text-align: center;
            margin: 30px 0;
        }}
        
        svg {{
            display: block;
            margin: 0 auto;
        }}
        
        .consigne {{
            text-align: center;
            font-size: 14pt;
            margin: 30px 50px;
            font-weight: bold;
            color: #2c3e50;
        }}
        
        .page-break {{
            page-break-after: always;
        }}
        
        .page-break-before {{
            page-break-before: always;
        }}
        
        h3 {{
            color: #2c3e50;
            margin-top: 20px;
            font-size: 14pt;
        }}
        
        table {{
            margin: 15px auto;
            border-collapse: collapse;
        }}
        
        table th, table td {{
            border: 1px solid #333;
            padding: 8px 15px;
            text-align: center;
        }}
        
        table th {{
            background-color: #f0f0f0;
            font-weight: bold;
        }}
        
        ul {{
            margin: 10px 0;
            padding-left: 30px;
        }}
        
        li {{
            margin: 8px 0;
        }}
        
        .solutions {{
            margin: 20px 0;
        }}
        
        .solutions p {{
            margin: 8px 0;
            line-height: 1.6;
        }}
    </style>
</head>
<body>
    <!-- PAGE 1: ÉNONCÉ -->
    <div class="page-enonce page-break">
        {'<img src="file://' + os.path.abspath(qr_filepath) + '" class="qr-code" alt="QR Code">' if qr_exists else ''}
        
        <h1>BOGGLE</h1>
        
        <div class="grille-container">
            {svg_template_pdf.format(*list(leplateau))}
        </div>
        
        <div class="consigne">
            {consigne[langage]}
        </div>
    </div>
    
    <!-- PAGE 2: CORRECTION -->
    <div class="page-break">
        <h1>Solutions</h1>
        
        <div class="solutions">
            {correction_html}
        </div>
    </div>
    
    <!-- PAGE 3: RÈGLES -->
    <div>
        {regles_completes[langage]}
    </div>
</body>
</html>
        """
        
        # Générer le PDF
        pdf_filepath = f"{repertoires[langage][2]}/{leplateau}.pdf"
        
        HTML(string=html_content).write_pdf(pdf_filepath)
        
        print(f"✓ PDF créé : {pdf_filepath}")
        
        # Nettoyer le QR code temporaire
        if qr_exists and os.path.exists(qr_filepath):
            os.remove(qr_filepath)
        
        return True
    except ImportError as e:
        print(f"Warning: weasyprint not installed - {e}")
        return False

def generer_meta_description(stats_mots):
    """Génère le fichier meta description au format pipe pour le SEO"""
    # stats_mots = {3: 28, 4: 34, 5: 21, 6: 12, 7: 7}
    
    # Calculer le nombre total de mots et le score max
    total_mots = sum(stats_mots.values())
    score_total = sum(nb * points_mot(taille) for taille, nb in stats_mots.items())
    longueur_max = max(stats_mots.keys()) if stats_mots else 0
    
    # Déterminer la difficulté
    if total_mots >= 100:
        difficulte = "facile"
    elif total_mots >= 60:
        difficulte = "moyenne"
    else:
        difficulte = "difficile"
    
    # Générer la description textuelle
    if langage == "FR":
        description = f"Grille Boggle {leplateau} avec {total_mots} mots. Difficulté {difficulte}. Score max : {score_total} points. Le plus long mot fait {longueur_max} lettres. Jouez gratuitement en 3 minutes !"
    else:
        if difficulte == "facile":
            diff_en = "easy"
        elif difficulte == "moyenne":
            diff_en = "medium"
        else:
            diff_en = "hard"
        description = f"Boggle grid {leplateau} with {total_mots} words. {diff_en.capitalize()} difficulty. Max score: {score_total} points. Longest word: {longueur_max} letters. Play free for 3 minutes!"
        difficulte = diff_en  # Utiliser la version anglaise
    
    # Sauvegarder au format pipe : chaine|mots|score|difficulté|longueur_max|description
    meta_dir = f"meta_{langage}"
    makedirs(meta_dir, exist_ok=True)
    
    meta_content = f"{leplateau}|{total_mots}|{score_total}|{difficulte}|{longueur_max}|{description}"
    
    with open(f"{meta_dir}/meta_{leplateau}.txt", "w", encoding='utf-8') as f:
        f.write(meta_content)
    
    print(f"✓ Meta description créée : {meta_dir}/meta_{leplateau}.txt")
    
    # Retourner les données pour l'index JSON
    return {
        "chaine": leplateau,
        "mots": total_mots,
        "score": score_total,
        "difficulte": difficulte,
        "longueur_max": longueur_max
    }

# Préparation des répertoires
for repertoire in repertoires[langage]:
    makedirs(repertoire, exist_ok=True)

def generer_index_json_global(toutes_grilles):
    """Génère l'index JSON global compact à la fin de la génération"""
    from datetime import datetime
    
    meta_dir = f"meta_{langage}"
    index_file = f"index_{langage}.json"
    
    # Format compact : [chaine, mots, score, difficulte, longueur_max]
    index_data = {
        "generated": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "total": len(toutes_grilles),
        "grilles": [
            [g["chaine"], g["mots"], g["score"], g["difficulte"], g["longueur_max"]]
            for g in toutes_grilles
        ]
    }
    
    import json
    with open(index_file, "w", encoding='utf-8') as f:
        json.dump(index_data, f, ensure_ascii=False, separators=(',', ':'))
    
    print(f"\n✓ Index JSON créé : {index_file} ({len(toutes_grilles)} grilles uniques)")
    return index_file

# Installer les dépendances
def install_dependencies():
    import subprocess
    import sys
    
    dependencies = ['weasyprint', 'qrcode[pil]', 'Pillow']
    
    for package in dependencies:
        try:
            if package == 'Pillow':
                __import__('PIL')
            elif package == 'qrcode[pil]':
                __import__('qrcode')
            else:
                __import__(package)
        except ImportError:
            print(f"Installation de {package}...")
            subprocess.check_call([sys.executable, "-m", "pip", "install", "--break-system-packages", package])

print("Vérification des dépendances...")
install_dependencies()
print("✓ Dépendances OK\n")

# Liste pour collecter toutes les grilles générées
toutes_les_grilles = []

# BOUCLE PRINCIPALE
for no_ex in range(nbexo):
    print("=" * 60)
    print(f"Exercice {no_ex+1}/{nbexo}")
    print("=" * 60)
    
    listes = []
    melange()
    
    # Calculer les solutions
    etape_1()
    correction_html = ""
    stats_mots = {}  # {3: 28, 4: 34, ...}
    
    for i in range(14):
        html, nb = etape_suivante()
        correction_html += html
        if nb > 0:
            stats_mots[len(listes) + 1] = nb
    
    # Générer la meta description et collecter les données
    print("\n→ Création meta description...")
    meta_data = generer_meta_description(stats_mots)
    toutes_les_grilles.append(meta_data)
    
    # Générer l'énoncé avec H2 et classes CSS
    enonce_html = f'''<div class="boggle-enonce">
    <h2 class="boggle-title">BOGGLE</h2>
    <div class="boggle-grille">
        {svg_template.format(*list(leplateau))}
    </div>
    <p class="boggle-consigne">{consigne[langage]}</p>
</div>'''
    
    # Générer la correction avec classes CSS (sans grille, sans titre)
    correction_complete = f'''<div class="boggle-correction">
    <div class="boggle-solutions">
        {correction_html}
    </div>
</div>'''
    
    sauv_ex(enonce_html)
    sauv_corr(correction_complete)
    
    # Créer l'image OG
    print("→ Création image OG...")
    creer_image_og()
    
    # Créer le PDF
    print("→ Création PDF...")
    creer_pdf_complet(enonce_html, correction_complete)
    
    print()

print("\n" + "=" * 60)
print("✓ GÉNÉRATION TERMINÉE")
print("=" * 60)

# Générer l'index JSON global
print("\n→ Génération de l'index JSON global...")
generer_index_json_global(toutes_les_grilles)

print("\n" + "=" * 60)
print(f"✓ {len(toutes_les_grilles)} grilles générées")
print("=" * 60)
