import os
import subprocess
import tempfile
import logging
from datetime import datetime

logger = logging.getLogger(__name__)

class ContractGenerator:
    def __init__(self):
        self.template_dir = "templates"
        self.output_dir = "contracts"
        # Créer les dossiers s'ils n'existent pas
        os.makedirs(self.template_dir, exist_ok=True)
        os.makedirs(self.output_dir, exist_ok=True)
    
    def create_latex_template(self):
        """Crée le template LaTeX pour l'attestation sur l'honneur"""
        template_content = r"""\documentclass[11pt, a4paper]{article}

% --- PREAMBULE ---
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[french]{babel}
\usepackage{geometry}
\geometry{left=2.5cm, right=2.5cm, top=3cm, bottom=3cm}
\usepackage{lmodern}

% --- DEBUT DU DOCUMENT ---
\begin{document}

\pagestyle{empty} % Pas de numérotation de page pour une attestation

\begin{center}
    \vspace*{2cm} % Espace en haut de la page
    \LARGE{\textbf{ATTESTATION SUR L'HONNEUR}}
    \vspace{2.5cm}
\end{center}

Je soussigné, ##PRENOM_NOM##, demeurant au ##ADRESSE_COMPLETE##,

\vspace{1cm}

atteste sur l'honneur être l'unique auteur-réalisateur et producteur de l'œuvre audiovisuelle dont l'URL est :

\vspace{0.5cm}

\begin{center}
    \large{\textbf{##URL_OEUVRE##}}
\end{center}

\vspace{0.5cm}

Cette œuvre a été diffusée initialement sur mon compte @##PSEUDONYME## le \textbf{##DATE_PUBLICATION##}.

\vspace{1cm}

En conséquence, je certifie détenir l'intégralité des droits d'auteur et des droits de producteur sur cette œuvre.

\vspace{2cm}

Fait pour valoir ce que de droit.

\vspace{2.5cm}

\begin{flushright}
    Fait à ##VILLE_SIGNATURE##, le \textbf{##DATE_SIGNATURE##}.
    
    \vspace{3cm} % Espace visuel avant la signature
    
    \noindent\makebox[6cm]{\hrulefill} \\ % Ligne de signature de 6cm de large
    ##PRENOM_NOM##
    
\end{flushright}

\end{document}"""
        
        template_path = os.path.join(self.template_dir, "attestation_template.tex")
        
        # Écrire avec encodage UTF-8 strict
        try:
            with open(template_path, 'w', encoding='utf-8', newline='\n') as f:
                f.write(template_content)
        except Exception as e:
            # Fallback avec ASCII pur si UTF-8 échoue
            logger.warning(f"⚠️ Écriture UTF-8 échouée, fallback ASCII: {e}")
            ascii_content = template_content.encode('ascii', errors='ignore').decode('ascii')
            with open(template_path, 'w', encoding='ascii', newline='\n') as f:
                f.write(ascii_content)
        
        return template_path
    
    def generate_contract(self, user_data, video_data, creator_pseudo="", video_url=""):
        """Génère un contrat PDF à partir des données utilisateur et vidéo"""
        try:
            # Créer le template s'il n'existe pas
            template_path = os.path.join(self.template_dir, "attestation_template.tex")
            if not os.path.exists(template_path):
                template_path = self.create_latex_template()
            
            # Lire le template avec gestion d'erreurs d'encodage
            try:
                with open(template_path, 'r', encoding='utf-8') as f:
                    template_content = f.read()
            except UnicodeDecodeError:
                logger.warning("⚠️ Erreur UTF-8, tentative avec encodage latin-1")
                with open(template_path, 'r', encoding='latin-1') as f:
                    template_content = f.read()
            
            # Préparer les données de remplacement avec nettoyage des caractères spéciaux
            def clean_text(text):
                """Nettoie le texte pour éviter les problèmes d'encodage LaTeX"""
                if not text:
                    logger.debug("🧹 clean_text: texte vide ou None")
                    return ""
                
                # Conversion robuste en string si nécessaire
                original_text = str(text)
                logger.debug(f"🧹 clean_text: texte original = {repr(original_text)}")
                
                # Analyser les caractères problématiques AVANT nettoyage
                problematic_chars = []
                for i, char in enumerate(original_text):
                    if ord(char) > 127:
                        problematic_chars.append(f"{char}(U+{ord(char):04X})@{i}")
                
                if problematic_chars:
                    logger.info(f"⚠️ Caractères non-ASCII détectés: {', '.join(problematic_chars[:10])}")
                    if len(problematic_chars) > 10:
                        logger.info(f"   ... et {len(problematic_chars) - 10} autres")
                
                text = original_text
                
                # Remplacer UNIQUEMENT les caractères LaTeX spéciaux (gardons les accents français !)
                replacements = {
                    # Caractères LaTeX spéciaux uniquement
                    '\\': ' ',  # Remplacer backslash par espace
                    '&': ' et ',
                    '%': ' pour cent ',
                    '$': ' dollars ',
                    '#': ' diese ',
                    '_': ' ',  # Remplacer underscore par espace
                    '^': ' ',
                    '~': ' ',
                    '{': '(',
                    '}': ')',
                    
                    # Garder les accents français ! Ils fonctionnent avec UTF-8
                    # On supprime seulement les emojis et caractères très spéciaux
                }
                
                # Appliquer les remplacements avec logs
                replaced_count = 0
                for old, new in replacements.items():
                    if old in text:
                        old_count = text.count(old)
                        text = text.replace(old, new)
                        replaced_count += old_count
                        logger.debug(f"🔄 Remplacement: {repr(old)} → {repr(new)} ({old_count} fois)")
                
                if replaced_count > 0:
                    logger.info(f"🔄 Total remplacements de caractères spéciaux: {replaced_count}")
                
                # Supprimer les émojis et caractères Unicode problématiques
                import re
                emoji_pattern = re.compile(
                    "["
                    "\U0001F600-\U0001F64F"  # emoticons
                    "\U0001F300-\U0001F5FF"  # symbols & pictographs
                    "\U0001F680-\U0001F6FF"  # transport & map symbols
                    "\U0001F1E0-\U0001F1FF"  # flags (iOS)
                    "\U00002702-\U000027B0"
                    "\U000024C2-\U0001F251"
                    "]+", flags=re.UNICODE
                )
                
                emoji_found = emoji_pattern.findall(text)
                if emoji_found:
                    logger.info(f"🔍 Émojis détectés: {emoji_found[:5]}")  # Limiter l'affichage
                    text = emoji_pattern.sub(' ', text)
                    logger.info(f"🧹 {len(emoji_found)} émojis supprimés")
                
                # Les caractères français sont OK avec UTF-8 + babel[french]
                # On ne supprime que les émojis et caractères vraiment problématiques
                logger.debug("✅ Texte nettoyé - caractères français préservés")
                
                if text != original_text:
                    logger.info(f"🧹 Texte modifié: {repr(original_text[:50])}... → {repr(text[:50])}...")
                
                return text
            
            prenom_nom = clean_text(f"{user_data['prenom']} {user_data['nom']}")
            adresse_complete = clean_text(f"{user_data['rue']}, {user_data['code_postal']} {user_data['ville']}")
            
            # Utiliser l'URL au lieu du titre de la vidéo
            url_oeuvre = clean_text(video_url or video_data.get('url', 'URL non disponible'))
            plateforme = clean_text(video_data.get('platform', 'YouTube'))
            date_publication = clean_text(video_data.get('published_date', 'Non spécifiée'))
            ville_signature = clean_text(user_data['ville'])
            
            # Date de signature (aujourd'hui)
            date_signature = datetime.now().strftime("%d/%m/%Y")
            
            # Pseudonyme du créateur avec nettoyage
            if not creator_pseudo:
                creator_pseudo = "MON_PSEUDONYME"
            creator_pseudo = clean_text(creator_pseudo)
            
            # Remplacer les placeholders (utilisation de ##URL_OEUVRE## au lieu de ##TITRE_OEUVRE##)
            replacements = {
                '##PRENOM_NOM##': prenom_nom,
                '##ADRESSE_COMPLETE##': adresse_complete,
                '##URL_OEUVRE##': url_oeuvre,  # Changé de TITRE_OEUVRE à URL_OEUVRE
                '##PLATEFORME##': plateforme,
                '##PSEUDONYME##': creator_pseudo,
                '##DATE_PUBLICATION##': date_publication,
                '##VILLE_SIGNATURE##': ville_signature,
                '##DATE_SIGNATURE##': date_signature
            }
            
            # Appliquer les remplacements
            contract_content = template_content
            for placeholder, value in replacements.items():
                contract_content = contract_content.replace(placeholder, value)
                logger.debug(f"🔄 Remplacement: {placeholder} -> {repr(value[:50])}...")
            
            logger.info(f"📝 Contenu contrat préparé: {len(contract_content)} caractères")
            
            # Analyser le contenu final pour les caractères problématiques
            problematic_final = []
            for i, char in enumerate(contract_content):
                if ord(char) > 127:
                    problematic_final.append(f"{char}(U+{ord(char):04X})@{i}")
            
            if problematic_final:
                logger.warning(f"⚠️ Caractères non-ASCII dans le contenu final: {len(problematic_final)} trouvés")
                logger.info(f"   Premiers 10: {', '.join(problematic_final[:10])}")
            else:
                logger.info("✅ Contenu final entièrement ASCII-compatible")
            
            # Générer un nom de fichier unique
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename_base = f"attestation_{user_data['nom'].lower()}_{timestamp}"
            
            logger.info(f"📁 Nom de fichier base: {filename_base}")
            
            # Créer un fichier temporaire pour LaTeX avec gestion d'erreur d'encodage robuste
            temp_tex_path = None
            try:
                logger.info("📝 Tentative de création du fichier temporaire avec UTF-8...")
                # Essayer d'abord avec UTF-8
                with tempfile.NamedTemporaryFile(mode='w', suffix='.tex', delete=False, encoding='utf-8') as temp_file:
                    temp_file.write(contract_content)
                    temp_tex_path = temp_file.name
                logger.info(f"✅ Fichier temporaire créé avec UTF-8: {temp_tex_path}")
                
                # Vérifier que le fichier est bien écrit
                with open(temp_tex_path, 'r', encoding='utf-8') as verify_file:
                    verify_content = verify_file.read()
                    logger.info(f"🔍 Vérification fichier: {len(verify_content)} caractères lus")
                    
            except (UnicodeEncodeError, UnicodeDecodeError) as ue:
                logger.warning(f"⚠️ Erreur UTF-8, tentative avec ASCII: {ue}")
                # Fallback avec ASCII si UTF-8 échoue
                try:
                    if temp_tex_path and os.path.exists(temp_tex_path):
                        os.unlink(temp_tex_path)
                    
                    # Nettoyer le contenu pour ASCII pur
                    logger.info("🧹 Nettoyage ASCII du contenu...")
                    safe_content = contract_content.encode('ascii', errors='ignore').decode('ascii')
                    removed_chars = len(contract_content) - len(safe_content)
                    logger.warning(f"🗑️ {removed_chars} caractères supprimés pour compatibilité ASCII")
                    
                    with tempfile.NamedTemporaryFile(mode='w', suffix='.tex', delete=False, encoding='ascii') as temp_file:
                        temp_file.write(safe_content)
                        temp_tex_path = temp_file.name
                    logger.info(f"✅ Fichier temporaire créé avec ASCII: {temp_tex_path}")
                except Exception as final_error:
                    logger.error(f"❌ Impossible de créer le fichier temporaire: {final_error}")
                    return {
                        'success': False,
                        'error': f"Erreur création fichier temporaire: {final_error}"
                    }
            except Exception as general_error:
                logger.error(f"❌ Erreur générale création fichier: {general_error}")
                return {
                    'success': False,
                    'error': f"Erreur inattendue: {general_error}"
                }
            
            # Compiler avec pdflatex
            output_dir = os.path.abspath(self.output_dir)
            pdf_filename = f"{filename_base}.pdf"
            pdf_path = os.path.join(output_dir, pdf_filename)
            
            logger.info(f"📁 Répertoire de sortie: {output_dir}")
            logger.info(f"📄 Nom fichier PDF: {pdf_filename}")
            logger.info(f"📍 Chemin PDF complet: {pdf_path}")
            
            # Vérifier les permissions du répertoire de sortie
            if not os.path.exists(output_dir):
                logger.warning(f"⚠️ Répertoire de sortie n'existe pas: {output_dir}")
                try:
                    os.makedirs(output_dir, exist_ok=True)
                    logger.info(f"✅ Répertoire créé: {output_dir}")
                except Exception as dir_error:
                    logger.error(f"❌ Impossible de créer le répertoire: {dir_error}")
            
            # Vérifier les permissions d'écriture
            if not os.access(output_dir, os.W_OK):
                logger.error(f"❌ Pas de permission d'écriture dans: {output_dir}")
            else:
                logger.info(f"✅ Permissions d'écriture OK dans: {output_dir}")
            
            # Commande pdflatex
            compile_cmd = [
                'pdflatex',
                '-interaction=nonstopmode',
                f'-output-directory={output_dir}',
                f'-jobname={filename_base}',
                temp_tex_path
            ]
            
            # Exécuter la compilation
            logger.info(f"🔄 Exécution de pdflatex: {' '.join(compile_cmd)}")
            logger.info(f"📂 Répertoire de travail: {os.getcwd()}")
            
            try:
                result = subprocess.run(compile_cmd, capture_output=True, timeout=60, cwd=output_dir)
                
                # Debug détaillé - gérer l'encodage proprement
                logger.info(f"📊 Code de retour pdflatex: {result.returncode}")
                
                # Décoder stdout avec gestion d'erreurs
                try:
                    stdout_text = result.stdout.decode('utf-8', errors='replace')
                except UnicodeDecodeError:
                    stdout_text = result.stdout.decode('latin1', errors='replace')
                except Exception:
                    stdout_text = str(result.stdout)
                
                if stdout_text:
                    stdout_lines = stdout_text.split('\n')
                    logger.info(f"📤 STDOUT ({len(stdout_lines)} lignes):")
                    for i, line in enumerate(stdout_lines[:20]):  # Premières 20 lignes
                        if line.strip():
                            logger.info(f"   {i+1}: {line}")
                
                # Décoder stderr avec gestion d'erreurs
                try:
                    stderr_text = result.stderr.decode('utf-8', errors='replace')
                except UnicodeDecodeError:
                    stderr_text = result.stderr.decode('latin1', errors='replace')
                except Exception:
                    stderr_text = str(result.stderr)
                
                if stderr_text:
                    stderr_lines = stderr_text.split('\n')
                    logger.warning(f"📥 STDERR ({len(stderr_lines)} lignes):")
                    for i, line in enumerate(stderr_lines[:20]):  # Premières 20 lignes
                        if line.strip():
                            logger.warning(f"   {i+1}: {line}")
                    if len(stdout_lines) > 20:
                        logger.info(f"   ... et {len(stdout_lines) - 20} lignes supplémentaires")
                        
                        # Chercher les erreurs dans le reste
                        error_lines = [line for line in stdout_lines if 'error' in line.lower() or 'failed' in line.lower()]
                        if error_lines:
                            logger.error("❌ Erreurs trouvées dans STDOUT:")
                            for error in error_lines[:10]:  # Max 10 erreurs
                                logger.error(f"   {error}")
                
                if result.stderr:
                    logger.warning(f"⚠️ STDERR: {result.stderr}")
                
                # Vérifier le fichier log LaTeX
                log_path = os.path.join(output_dir, f"{filename_base}.log")
                if os.path.exists(log_path):
                    logger.info(f"📋 Fichier log LaTeX créé: {log_path}")
                    try:
                        with open(log_path, 'r', encoding='utf-8', errors='ignore') as log_file:
                            log_content = log_file.read()
                            
                            # Chercher les erreurs spécifiques
                            if "! Package inputenc Error" in log_content:
                                logger.error("❌ Erreur inputenc détectée dans le log LaTeX")
                            if "! LaTeX Error" in log_content:
                                logger.error("❌ Erreur LaTeX générale détectée")
                            if "Emergency stop" in log_content:
                                logger.error("❌ Arrêt d'urgence LaTeX détecté")
                                
                            # Extraire les lignes d'erreur (en excluant les messages informatifs de Babel)
                            log_lines = log_content.split('\n')
                            error_context = []
                            for i, line in enumerate(log_lines):
                                # Ignorer les messages informatifs de Babel qui sont normaux
                                if ('babel Info:' in line or 
                                    'Package babel Info:' in line or
                                    'FBguill@level=' in line):
                                    continue
                                    
                                if '!' in line or 'error' in line.lower():
                                    # Prendre le contexte autour de l'erreur
                                    start = max(0, i-2)
                                    end = min(len(log_lines), i+3)
                                    context = log_lines[start:end]
                                    error_context.extend([f"Line {start+j+1}: {context[j]}" for j in range(len(context))])
                                    
                            if error_context:
                                logger.error("❌ Contexte des erreurs dans le log:")
                                for error_line in error_context[:20]:  # Max 20 lignes
                                    logger.error(f"   {error_line}")
                            else:
                                logger.debug("✅ Aucune erreur LaTeX détectée (messages Babel ignorés)")
                                    
                    except Exception as log_error:
                        logger.warning(f"⚠️ Impossible de lire le fichier log: {log_error}")
                else:
                    logger.warning(f"⚠️ Fichier log LaTeX non trouvé: {log_path}")
                    
            except subprocess.TimeoutExpired:
                logger.error("❌ Timeout lors de la compilation LaTeX (60s)")
                return {
                    'success': False,
                    'error': "Timeout de compilation LaTeX"
                }
            except Exception as compile_error:
                logger.error(f"❌ Erreur lors de l'exécution de pdflatex: {compile_error}")
                return {
                    'success': False,
                    'error': f"Erreur compilation: {compile_error}"
                }
            
            # Nettoyer le fichier temporaire
            if temp_tex_path and os.path.exists(temp_tex_path):
                os.unlink(temp_tex_path)
            
            if result.returncode == 0:
                # Nettoyer les fichiers auxiliaires
                aux_extensions = ['.aux', '.log', '.out']
                for ext in aux_extensions:
                    aux_file = os.path.join(output_dir, f"{filename_base}{ext}")
                    if os.path.exists(aux_file):
                        os.unlink(aux_file)
                
                logger.info(f"✅ Contrat PDF généré: {pdf_path}")
                return {
                    'success': True,
                    'pdf_path': pdf_path,
                    'filename': pdf_filename
                }
            else:
                # Afficher les erreurs LaTeX détaillées
                logger.error(f"❌ Erreur compilation LaTeX (code {result.returncode}):")
                logger.error(f"STDOUT: {result.stdout}")
                logger.error(f"STDERR: {result.stderr}")
                
                # Essayer de lire le fichier .log pour plus de détails
                log_file = os.path.join(output_dir, f"{filename_base}.log")
                if os.path.exists(log_file):
                    try:
                        with open(log_file, 'r', encoding='utf-8', errors='ignore') as f:
                            log_content = f.read()
                            logger.error(f"LOG FILE: {log_content[-1000:]}")  # Dernières 1000 chars
                    except Exception as log_error:
                        logger.error(f"Impossible de lire le log: {log_error}")
                
                return {
                    'success': False,
                    'error': f"Erreur compilation LaTeX (code {result.returncode}): {result.stderr}"
                }
                
        except Exception as e:
            logger.error(f"❌ Erreur génération contrat: {e}")
            return {
                'success': False,
                'error': str(e)
            }
    
    def check_latex_installation(self):
        """Vérifie si LaTeX est installé"""
        try:
            # Essayer d'abord pdflatex avec le chemin complet
            import shutil
            pdflatex_path = shutil.which('pdflatex')
            if pdflatex_path:
                result = subprocess.run([pdflatex_path, '--version'], capture_output=True, text=True, timeout=10)
                if result.returncode == 0:
                    logger.info(f"✅ LaTeX détecté: {pdflatex_path}")
                    return True
                else:
                    logger.warning(f"⚠️ pdflatex trouvé mais erreur: {result.stderr}")
            else:
                logger.warning("⚠️ pdflatex non trouvé avec shutil.which")
            
            # Fallback: essayer avec le chemin complet standard
            for path in ['/usr/bin/pdflatex', '/usr/local/bin/pdflatex', 'pdflatex']:
                try:
                    result = subprocess.run([path, '--version'], capture_output=True, text=True, timeout=10)
                    if result.returncode == 0:
                        logger.info(f"✅ LaTeX détecté avec fallback: {path}")
                        return True
                except (FileNotFoundError, subprocess.TimeoutExpired):
                    continue
            
            logger.error("❌ LaTeX non détecté avec tous les fallbacks")
            return False
            
        except Exception as e:
            logger.error(f"❌ Erreur vérification LaTeX: {e}")
            return False
    
    def generate_generic_contract(self, contract_info):
        """Génère un contrat générique avec des placeholders à compléter"""
        try:
            # Template de contrat générique
            generic_contract = f"""ATTESTATION SUR L'HONNEUR

Je soussigné, [VOTRE PRÉNOM ET NOM], demeurant au [VOTRE ADRESSE COMPLÈTE],

atteste sur l'honneur être l'unique auteur-réalisateur et producteur de l'œuvre audiovisuelle intitulée :

    "{contract_info.get('title', 'TITRE DE LA VIDÉO')}"

Cette œuvre a été diffusée initialement sur mon compte @{contract_info.get('platform', 'PLATEFORME')} le {contract_info.get('published_date', 'DATE DE PUBLICATION')}.

En conséquence, je certifie détenir l'intégralité des droits d'auteur et des droits de producteur sur cette œuvre.

Fait pour valoir ce que de droit.

Fait à [VOTRE VILLE], le [DATE D'AUJOURD'HUI].

                                        [VOTRE SIGNATURE]
                                        [VOTRE PRÉNOM ET NOM]

URL de la vidéo : {contract_info.get('url', 'URL_VIDEO')}

---
⚠️ ATTENTION : Ce contrat contient des placeholders entre [crochets] à compléter avec vos informations personnelles.
📝 Utilisez la commande /register pour enregistrer vos données et générer un contrat PDF personnalisé automatiquement."""
            
            return generic_contract
            
        except Exception as e:
            logger.error(f"❌ Erreur génération contrat générique: {e}")
            return f"Erreur génération du contrat générique: {str(e)}"

    def install_latex_packages(self):
        """Guide pour installer les packages LaTeX nécessaires"""
        packages_info = """
Pour générer les contrats PDF, vous devez installer LaTeX avec les packages suivants :

Ubuntu/Debian :
sudo apt-get install texlive-latex-base texlive-fonts-recommended texlive-latex-extra texlive-lang-french

CentOS/RHEL :
sudo yum install texlive-latex texlive-collection-fontsrecommended texlive-collection-latexextra

Packages LaTeX requis :
- inputenc (UTF-8)
- fontenc (T1)
- babel (french)
- geometry
- lmodern
"""
        return packages_info