#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script pour analyser les fautes d'orthographe et de grammaire dans un fichier livre.org
et générer un rapport par chapitre.

Ce script:
1. Lit le fichier livre.org
2. Extrait le texte par chapitre
3. Analyse les fautes d'orthographe et de grammaire dans chaque chapitre
4. Génère un rapport détaillé des erreurs trouvées
"""

import re
import os
import csv
import argparse
from pyspellchecker import SpellChecker
import language_tool_python
# Vérifier si les modules nécessaires sont disponibles
try:
    import language_tool_python
    LANGUAGE_TOOL_AVAILABLE = True
except ImportError:
    print("AVERTISSEMENT: Module language_tool_python non disponible. La vérification grammaticale sera désactivée.")
    LANGUAGE_TOOL_AVAILABLE = False

try:
    from spellchecker import SpellChecker
    SPELLCHECKER_AVAILABLE = True
except ImportError:
    print("AVERTISSEMENT: Module spellchecker non disponible. La vérification orthographique sera désactivée.")
    SPELLCHECKER_AVAILABLE = False

# Définir les arguments en ligne de commande
parser = argparse.ArgumentParser(description='Analyser les fautes d\'orthographe et de grammaire dans un fichier Org-mode.')
parser.add_argument('dossier', nargs='?', help='Le chemin du dossier contenant le fichier livre.org. Si aucun dossier n\'est spécifié, le dossier courant sera utilisé.', default=os.getcwd())
args = parser.parse_args()

# Chemin vers le fichier livre.org
fichier_livre = f"{args.dossier}/livre.org"

def extract_chapters(file_path):
    """
    Extrait les chapitres d'un fichier org-mode.
    Retourne un dictionnaire avec les titres des chapitres comme clés et leur contenu comme valeurs.
    """
    with open(file_path, 'r', encoding='utf-8') as file:
        content = file.read()
    
    # Diviser le contenu par chapitres (lignes commençant par **)
    chapter_pattern = r'^\*\* (.*?)$(.*?)(?=^\*\* |\Z)'
    chapters = re.findall(chapter_pattern, content, re.MULTILINE | re.DOTALL)
    
    chapter_dict = {}
    for title, content in chapters:
        # Nettoyer le titre (supprimer ": title:" s'il existe)
        clean_title = re.sub(r'\s*:\s*title\s*:', '', title).strip()
        
        # Nettoyer le contenu
        clean_content = clean_chapter_content(content)
        
        chapter_dict[clean_title] = clean_content
    
    return chapter_dict

def clean_chapter_content(content):
    """
    Nettoie le contenu d'un chapitre en supprimant les commentaires et les balises org-mode.
    """
    # Supprimer les blocs de commentaires
    content = re.sub(r'#\+begin_comment.*?#\+end_comment', '', content, flags=re.DOTALL | re.IGNORECASE)
    
    # Supprimer les lignes de métadonnées (commençant par #+)
    content = re.sub(r'^\s*#\+.*$', '', content, flags=re.MULTILINE)
    
    # Supprimer les sous-titres (lignes commençant par ***)
    content = re.sub(r'^\s*\*\*\*.*$', '', content, flags=re.MULTILINE)
    
    # Supprimer les liens org-mode [[...][...]] et [[...]]
    content = re.sub(r'\[\[.*?\]\](?:\[.*?\])?', '', content)
    
    # Supprimer les lignes vides multiples
    content = re.sub(r'\n\s*\n', '\n\n', content)
    
    return content.strip()
def load_custom_dictionary(file_path):
    """
    Charge le dictionnaire personnalisé à partir d'un fichier texte.
    Retourne un ensemble de mots à considérer comme corrects.
    """
    custom_words = set()

    # Vérifier si le fichier existe
    if os.path.exists(file_path):
        with open(file_path, 'r', encoding='utf-8') as file:
            for line in file:
                # Ignorer les lignes vides et les commentaires
                line = line.strip()
                if line and not line.startswith('#'):
                    custom_words.add(line.lower())

    return custom_words


def check_spelling(text, lang='fr', custom_dict_path='dictionnaire_personnalise.txt'):

    """
    Vérifie l'orthographe d'un texte et retourne les mots mal orthographiés.
    Utilise un dictionnaire personnalisé pour exclure certains mots de la vérification.
    """
    # Vérifier si le module spellchecker est disponible
    if not SPELLCHECKER_AVAILABLE:
        print("Vérification orthographique désactivée car le module spellchecker n'est pas disponible.")
        return []

    try:
        spell = SpellChecker(language=lang)

        # Charger le dictionnaire personnalisé
        custom_words = load_custom_dictionary(custom_dict_path)

        # Ajouter les mots du dictionnaire personnalisé au dictionnaire du vérificateur
        if custom_words:
            spell.word_frequency.load_words(custom_words)

        # Diviser le texte en mots
        words = re.findall(r'\b\w+\b', text.lower())

        # Trouver les mots mal orthographiés
        misspelled = spell.unknown(words)

        # Créer un dictionnaire avec les mots mal orthographiés et leurs suggestions
        spelling_errors = []
        for word in misspelled:
            # Vérifier si le mot est dans le dictionnaire personnalisé
            if word in custom_words:
                continue

            # Obtenir les suggestions de correction
            suggestions = spell.candidates(word)
            # Limiter à 5 suggestions maximum
            suggestions_list = list(suggestions) if suggestions is not None else []
            suggestions_list = suggestions_list[:5]

            # Trouver toutes les occurrences du mot dans le texte original
            for match in re.finditer(r'\b' + re.escape(word) + r'\b', text, re.IGNORECASE):
                # Extraire le contexte autour du mot
                word_start = match.start()
                word_end = match.end()

                # Trouver les limites des lignes contenant le mot
                line_start = text.rfind('\n', 0, word_start) + 1 if text.rfind('\n', 0, word_start) >= 0 else 0
                line_end = text.find('\n', word_end) if text.find('\n', word_end) >= 0 else len(text)

                # Extraire les lignes précédentes et suivantes pour plus de contexte
                prev_line_start = text.rfind('\n', 0, line_start - 1) + 1 if text.rfind('\n', 0, line_start - 1) >= 0 else 0
                next_line_end = text.find('\n', line_end + 1) if text.find('\n', line_end + 1) >= 0 else len(text)

                # Créer le contexte standard et étendu
                context = text[line_start:line_end]
                extended_context = text[prev_line_start:next_line_end]

                # Calculer les offsets pour les contextes
                context_offset = word_start - line_start
                extended_offset = word_start - prev_line_start

                spelling_errors.append({
                    'word': word,
                    'context': context,
                    'extended_context': extended_context,
                    'context_offset': context_offset,
                    'extended_offset': extended_offset,
                    'suggestions': suggestions_list
                })

        return spelling_errors
    except Exception as e:
        print(f"Erreur lors de la vérification orthographique: {str(e)}")
        return []
    spell = SpellChecker(language=lang)

    # Diviser le texte en mots
    words = re.findall(r'\b\w+\b', text.lower())

    # Trouver les mots mal orthographiés
    misspelled = spell.unknown(words)

    # Créer un dictionnaire avec les mots mal orthographiés et leurs suggestions
    spelling_errors = {}
    for word in misspelled:
        # Obtenir les suggestions de correction
        suggestions = spell.candidates(word)
        # Limiter à 5 suggestions maximum
        suggestions_list = list(suggestions)[:5]
        spelling_errors[word] = suggestions_list

    return spelling_errors

def check_grammar(text, lang='fr'):
    """
    Vérifie la grammaire d'un texte et retourne les erreurs grammaticales.
    """
    # Vérifier si le module language_tool_python est disponible
    if not LANGUAGE_TOOL_AVAILABLE:
        print("Vérification grammaticale désactivée car le module language_tool_python n'est pas disponible.")
        return []

    try:
        # Initialiser l'outil de vérification grammaticale
        tool = language_tool_python.LanguageTool(lang)

        # Vérifier le texte
        matches = tool.check(text)

        # Créer une liste d'erreurs grammaticales
        grammar_errors = []
        for match in matches:
            # Ignorer les erreurs d'orthographe (déjà traitées par le vérificateur d'orthographe)
            if match.ruleId.startswith('MORFOLOGIK_RULE'):
                continue

            # Extraire plus de contexte autour de l'erreur
            error_start = match.offset
            error_end = match.offset + match.errorLength

            # Trouver les limites des lignes contenant l'erreur
            line_start = text.rfind('\n', 0, error_start) + 1 if text.rfind('\n', 0, error_start) >= 0 else 0
            line_end = text.find('\n', error_end) if text.find('\n', error_end) >= 0 else len(text)

            # Extraire les lignes précédentes et suivantes pour plus de contexte
            prev_line_start = text.rfind('\n', 0, line_start - 1) + 1 if text.rfind('\n', 0, line_start - 1) >= 0 else 0
            next_line_end = text.find('\n', line_end + 1) if text.find('\n', line_end + 1) >= 0 else len(text)

            # Créer le contexte étendu
            extended_context = text[prev_line_start:next_line_end]

            # Ajuster les offsets pour le contexte étendu
            extended_offset = error_start - prev_line_start

            error = {
                'message': match.message,
                'context': match.context,
                'extended_context': extended_context,
                'suggestions': match.replacements,
                'offset': match.offset,
                'extended_offset': extended_offset,
                'length': match.errorLength,
                'rule': match.ruleId
            }
            grammar_errors.append(error)

        # Fermer l'outil pour libérer les ressources
        tool.close()

        return grammar_errors
    except Exception as e:
        print(f"Erreur lors de la vérification grammaticale: {str(e)}")
        return []

def generate_error_report(chapters, output_path):
    """
    Génère un rapport des erreurs d'orthographe et de grammaire par chapitre.
    """
    with open(output_path, 'w', encoding='utf-8') as report_file:
        report_file.write("# Rapport d'analyse orthographique et grammaticale\n\n")
        
        total_spelling_errors = 0
        total_grammar_errors = 0
        
        for chapter_title, chapter_content in chapters.items():
            report_file.write(f"## Chapitre: {chapter_title}\n\n")
            
            # Vérifier l'orthographe
            spelling_errors = check_spelling(chapter_content)
            
            # Vérifier la grammaire
            grammar_errors = check_grammar(chapter_content)
            
            # Mettre à jour les totaux
            total_spelling_errors += len(spelling_errors)
            total_grammar_errors += len(grammar_errors)
            
            # Écrire les erreurs d'orthographe
            report_file.write("### Erreurs d'orthographe\n\n")
            if spelling_errors:
                # Regrouper les erreurs par mot
                errors_by_word = {}
                for error in spelling_errors:
                    word = error['word']
                    if word not in errors_by_word:
                        errors_by_word[word] = {
                            'suggestions': error['suggestions'],
                            'occurrences': []
                        }
                    errors_by_word[word]['occurrences'].append({
                        'context': error['context'],
                        'extended_context': error['extended_context'],
                        'context_offset': error['context_offset'],
                        'extended_offset': error['extended_offset']
                    })

                # Écrire les erreurs regroupées par mot
                for word, data in errors_by_word.items():
                    suggestions_str = ", ".join(data['suggestions']) if data['suggestions'] else "Aucune suggestion"
                    report_file.write(f"- **{word}**: {suggestions_str}\n")

                    # Ajouter les contextes pour chaque occurrence
                    for i, occurrence in enumerate(data['occurrences']):
                        # Mettre en évidence le mot dans le contexte
                        context = occurrence['context']
                        offset = occurrence['context_offset']
                        highlighted_context = context[:offset] + f"**{word}**" + context[offset+len(word):]

                        # Ajouter le contexte étendu
                        extended_context = occurrence['extended_context']
                        report_file.write(f"  - **Occurrence {i+1}**:\n")
                        report_file.write(f"    - **Contexte**: {highlighted_context}\n")
                        report_file.write(f"    - **Contexte étendu**: ```\n{extended_context}\n```\n")
            else:
                report_file.write("Aucune erreur d'orthographe détectée.\n")
            
            report_file.write("\n")
            
            # Écrire les erreurs grammaticales
            report_file.write("### Erreurs grammaticales\n\n")
            if grammar_errors:
                for i, error in enumerate(grammar_errors):
                    suggestions_str = ", ".join(error['suggestions'][:5]) if error['suggestions'] else "Aucune suggestion"

                    # Mettre en évidence l'erreur dans le contexte
                    context = error['context'].replace(error['context'][error['offset']:error['offset']+error['length']],
                                                      f"**{error['context'][error['offset']:error['offset']+error['length']]}**")
                    report_file.write(f"- **Erreur**: {error['message']}\n")

                    report_file.write(f"- **Erreur {i+1}**: {error['message']}\n")
                    report_file.write(f"  - **Contexte**: {context}\n")

                    # Ajouter le contexte étendu
                    if 'extended_context' in error:
                        report_file.write(f"  - **Contexte étendu**: ```\n{error['extended_context']}\n```\n")

                    report_file.write(f"  - **Suggestions**: {suggestions_str}\n\n")
            else:
                report_file.write("Aucune erreur grammaticale détectée.\n")
            
            report_file.write("\n---\n\n")
        
        # Écrire le résumé
        report_file.write("## Résumé\n\n")
        report_file.write(f"- **Nombre total de chapitres analysés**: {len(chapters)}\n")
        report_file.write(f"- **Nombre total d'erreurs d'orthographe**: {total_spelling_errors}\n")
        report_file.write(f"- **Nombre total d'erreurs grammaticales**: {total_grammar_errors}\n")
    
    print(f"Rapport d'erreurs généré: {output_path}")

def save_to_csv(chapters, output_path):
    """
    Sauvegarde un résumé des erreurs dans un fichier CSV.
    """
    with open(output_path, 'w', newline='', encoding='utf-8') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow(['Chapitre', 'Erreurs d\'orthographe', 'Erreurs grammaticales', 'Total'])
        
        for chapter_title, chapter_content in chapters.items():
            spelling_errors = check_spelling(chapter_content)
            grammar_errors = check_grammar(chapter_content)
            
            total_errors = len(spelling_errors) + len(grammar_errors)
            writer.writerow([chapter_title, len(spelling_errors), len(grammar_errors), total_errors])
    
    print(f"Résumé des erreurs sauvegardé dans {output_path}")

def main():
    print(f"Analyse du fichier: {fichier_livre}")
    
    # Extraire les chapitres
    chapters = extract_chapters(fichier_livre)
    print(f"Nombre de chapitres trouvés: {len(chapters)}")
    
    # Définir les chemins de sortie
    report_output = f"{args.dossier}/rapport_orthographe_grammaire.md"
    csv_output = f"{args.dossier}/resume_erreurs.csv"
    
    # Générer le rapport d'erreurs
    generate_error_report(chapters, report_output)
    
    # Sauvegarder le résumé en CSV
    save_to_csv(chapters, csv_output)
    
    print("Analyse orthographique et grammaticale terminée avec succès!")

if __name__ == "__main__":
    main()