"""
Module d'analyse des emails de sauvegarde
Extrait les informations importantes et détermine le statut
Version améliorée pour mieux extraire les noms de sauvegardes
"""
import logging
import re
from datetime import datetime, timedelta, timezone
from config import BACKUP_TYPES, STATUS_PATTERNS, MONITORING_CONFIG
from html import unescape
from bs4 import BeautifulSoup

logger = logging.getLogger(__name__)

class BackupAnalyzer:
    """Analyseur d'emails de sauvegarde"""
    
    def __init__(self):
        """Initialise l'analyseur"""
        self.backup_status = {}
        
    def clean_html(self, html_content):
        """
        Nettoie le contenu HTML et extrait le texte
        
        Args:
            html_content: Contenu HTML brut
            
        Returns:
            str: Texte nettoyé
        """
        try:
            soup = BeautifulSoup(html_content, 'html.parser')
            text = soup.get_text(separator=' ', strip=True)
            text = unescape(text)
            text = re.sub(r'\s+', ' ', text)
            return text
        except Exception as e:
            logger.error(f"Erreur lors du nettoyage HTML: {str(e)}")
            return html_content
    
    def extract_backup_info(self, email):
        """
        Extrait les informations de sauvegarde d'un email
        
        Args:
            email: Dictionnaire contenant l'email
            
        Returns:
            dict: Informations extraites
        """
        try:
            info = {
                'id': email.get('id'),
                'received_date': email.get('receivedDateTime'),
                'subject': email.get('subject', ''),
                'status': 'unknown',
                'backup_type': 'unknown',
                'backup_name': '',
                'size': '',
                'duration': '',
                'start_time': None,
                'end_time': None,
                'details': {}
            }
            
            # Nettoyer le contenu du body
            body_content = email.get('body', {}).get('content', '')
            clean_body = self.clean_html(body_content)
            
            # Combiner sujet et body pour l'analyse
            full_text = f"{info['subject']} {clean_body}"
            
            # Déterminer le statut
            info['status'] = self.detect_status(full_text)
            
            # Déterminer le type de sauvegarde
            info['backup_type'] = self.detect_backup_type(full_text)
            
            # NOUVELLE LOGIQUE : Extraire le nom depuis le body en priorité
            info['backup_name'] = self.extract_backup_name_improved(info['subject'], clean_body, full_text)
            
            # Extraire la taille si disponible
            info['size'] = self.extract_size(full_text)
            
            # Extraire les dates/heures
            info['start_time'] = self.extract_start_time(full_text)
            info['end_time'] = self.extract_end_time(full_text)
            
            # Calculer la durée si possible
            if info['start_time'] and info['end_time']:
                try:
                    start = datetime.fromisoformat(info['start_time'].replace('Z', '+00:00'))
                    end = datetime.fromisoformat(info['end_time'].replace('Z', '+00:00'))
                    duration = end - start
                    info['duration'] = str(duration)
                except:
                    pass
            
            # Extraire des détails supplémentaires
            if 'Microsoft 365' in full_text or 'Microsoft365' in full_text:
                info['details'] = self.extract_microsoft365_details(full_text)
            elif 'NAS' in info['backup_type']:
                info['details'] = self.extract_nas_details(full_text)
            elif 'PC' in info['backup_type']:
                info['details'] = self.extract_pc_details(full_text)
            
            logger.info(f"Analysé: {info['backup_name']} - {info['status']} - {info['backup_type']}")
            return info
            
        except Exception as e:
            logger.error(f"Erreur lors de l'extraction des infos: {str(e)}")
            return None
    
    def extract_backup_name_improved(self, subject, body, full_text):
        """
        NOUVELLE VERSION : Extraction améliorée du nom de sauvegarde
        Priorité : body > sujet
        
        Args:
            subject: Sujet de l'email
            body: Corps nettoyé de l'email
            full_text: Texte complet
            
        Returns:
            str: Nom de la sauvegarde
        """
        # ========================================
        # PATTERNS SPÉCIFIQUES - PRIORITÉ MAXIMALE
        # ========================================
        
        # 1. Sauvegardes Microsoft 365
        # Pattern: La tâche de sauvegarde [SauvMicrosoft365...]
        match = re.search(r'tâche de sauvegarde \[([^\]]+Microsoft365[^\]]+)\]', body, re.IGNORECASE)
        if match:
            name = match.group(1).strip()
            # Nettoyer et formater
            name = re.sub(r'^Sauv', '', name)
            name = re.sub(r'[_\s]+', '_', name)
            return name
        
        # 2. Sauvegardes PC sur NAS (Active Backup for Business)
        # Pattern: La tâche de sauvegarde SAUV_PC_XXX sur NASXXX
        match = re.search(r'tâche de sauvegarde (SAUV_PC_\w+|Sauvegarde PC \w+) sur (\w+)', body, re.IGNORECASE)
        if match:
            backup_name = match.group(1)
            nas_name = match.group(2)
            
            # Extraire le nom du PC
            if 'SAUV_PC_' in backup_name.upper():
                pc_name = re.sub(r'SAUV_PC_', '', backup_name, flags=re.IGNORECASE)
                return f"PC_{pc_name}"
            elif 'Sauvegarde PC' in backup_name:
                pc_name = re.sub(r'Sauvegarde PC\s*', '', backup_name, flags=re.IGNORECASE)
                return f"PC_{pc_name.replace(' ', '_')}"
        
        # 3. Network Backup - SAUVNASXXX
        # Pattern: Network backup - SAUVNASXXX a été effectuée
        match = re.search(r'Network backup\s*-\s*([A-Z0-9_\-]+)\s+a été', body, re.IGNORECASE)
        if match:
            return match.group(1).strip()
        
        # 4. Tâche avec suffixe complet (SQY-T -BackUp4_Temporaire)
        # Pattern: La tâche XXX -YYY est terminée
        match = re.search(r'tâche ([A-Z0-9\-]+)\s*-\s*([A-Z0-9_\-]+)', body, re.IGNORECASE)
        if match:
            part1 = match.group(1).strip()
            part2 = match.group(2).strip()
            return f"{part1}-{part2}"
        
        # 5. Tâche simple entre crochets dans le body
        # Pattern: tâche [XXX] est terminée
        match = re.search(r'tâche \[([A-Z0-9\-_]+)\]', body, re.IGNORECASE)
        if match:
            name = match.group(1).strip()
            if len(name) > 3:
                return name
        
        # ========================================
        # PATTERNS DU SUJET - PRIORITÉ SECONDAIRE
        # ========================================
        
        # 6. Entre crochets dans le sujet
        match = re.search(r'\[([^\]]+)\]', subject)
        if match:
            name = match.group(1).strip()
            # Filtrer les noms non pertinents
            if (len(name) > 3 and 
                name.upper() not in ['FOR', 'VERSION', 'ERROR', 'TEST', 'SOURCE', 'DEST'] and
                not name.endswith('SOURCE') and
                not name.endswith('DEST')):
                # Nettoyer les espaces en fin
                name = name.rstrip()
                return name
        
        # 7. Patterns Synology avec suffixe (SAUVNASSQY-1, etc.)
        match = re.search(r'tâche\s+([A-Z0-9\-_]+)', subject, re.IGNORECASE)
        if match:
            name = match.group(1).strip()
            if len(name) > 4:
                return name
        
        # 8. RS1221 avec suffixe
        match = re.search(r'(RS\d{4}[\-\+]\d+)', subject)
        if match:
            return match.group(1)
        
        # 9. Patterns SAUV* (mais nettoyer)
        match = re.search(r'(SAUV[A-Z0-9\-_]{3,})', subject, re.IGNORECASE)
        if match:
            name = match.group(1)
            if len(name) > 5:
                return name
        
        # 10. "sur XXXX"
        match = re.search(r'sur\s+([A-Z0-9\-_]+)', subject, re.IGNORECASE)
        if match:
            name = match.group(1)
            if len(name) > 4 and name.upper() not in ['NAS', 'SERVER', 'PC']:
                return name
        
        # 11. Mots en majuscules significatifs
        match = re.search(r'\b([A-Z]{3,}[A-Z0-9_\-]{2,})\b', subject)
        if match:
            name = match.group(1)
            # Filtrer les mots génériques
            if name not in ['ACTIVE', 'BACKUP', 'BUSINESS', 'VERSION', 'ERROR', 'FAILED', 'NETWORK', 'SAUVEGARDE']:
                return name
        
        # ========================================
        # DERNIER RECOURS
        # ========================================
        
        # En dernier recours, utiliser une partie nettoyée du sujet
        name = subject[:50].strip()
        name = re.sub(r'[^\w\s\-_]', '', name)
        # Nettoyer les espaces multiples et en fin
        name = re.sub(r'\s+', ' ', name).strip()
        return name if name else 'Unknown'
    
    def detect_status(self, text):
        """
        Détecte le statut de la sauvegarde (succès/échec)
        
        Args:
            text: Texte à analyser
            
        Returns:
            str: 'success', 'failure' ou 'unknown'
        """
        text_lower = text.lower()
        
        # Vérifier les patterns d'échec d'abord (priorité)
        for pattern in STATUS_PATTERNS['failure']:
            if pattern in text_lower:
                return 'failure'
        
        # Ensuite vérifier les patterns de succès
        for pattern in STATUS_PATTERNS['success']:
            if pattern in text_lower:
                return 'success'
        
        return 'unknown'
    
    def detect_backup_type(self, text):
        """
        Détecte le type de sauvegarde
        
        Args:
            text: Texte à analyser
            
        Returns:
            str: Type de sauvegarde détecté
        """
        text_upper = text.upper()
        
        # Vérifier Microsoft 365 en premier
        if 'MICROSOFT 365' in text_upper or 'MICROSOFT365' in text_upper:
            return 'MICROSOFT365'
        
        for backup_type, patterns in BACKUP_TYPES.items():
            for pattern in patterns:
                if pattern in text_upper:
                    return backup_type
        
        return 'UNKNOWN'
    
    def extract_microsoft365_details(self, text):
        """
        Extrait les détails des sauvegardes Microsoft 365
        
        Args:
            text: Texte à analyser
            
        Returns:
            dict: Détails extraits
        """
        details = {}
        
        # Extraire les services et leur statut
        services = {}
        
        # Pattern: - ServiceName : succès : X
        pattern = r'-\s*([^:]+?)\s*:\s*(succès|échec|success|failure)\s*:\s*(\d+)'
        matches = re.findall(pattern, text, re.IGNORECASE)
        
        for service, status, count in matches:
            service_clean = service.strip()
            services[service_clean] = {
                'status': 'success' if 'succès' in status.lower() or 'success' in status.lower() else 'failure',
                'count': int(count)
            }
        
        if services:
            details['services'] = services
            details['total_items'] = sum(s['count'] for s in services.values())
        
        return details
    
    def extract_size(self, text):
        """
        Extrait la taille de la sauvegarde
        
        Args:
            text: Texte à analyser
            
        Returns:
            str: Taille formatée
        """
        patterns = [
            r'(\d+[\.,]?\d*)\s*(GB|GB|MB|TB|Ko|Mo|Go|To)',
            r'Taille\s*transférée?\s*:\s*(\d+[\.,]?\d*\s*\w+)',
            r'Size:\s*(\d+[\.,]?\d*\s*\w+)',
        ]
        
        for pattern in patterns:
            match = re.search(pattern, text, re.IGNORECASE)
            if match:
                return match.group(0)
        
        return ''
    
    def extract_start_time(self, text):
        """Extrait l'heure de début"""
        patterns = [
            r'Heure de début\s*:\s*([\d/\-]+\s+[\d:]+)',
            r'Start time\s*:\s*([\d/\-]+\s+[\d:]+)',
            r'Début\s*:\s*([\w,]+\s+\d+\s+\w+\s+\d+\s+[\d:]+)',
        ]
        
        for pattern in patterns:
            match = re.search(pattern, text, re.IGNORECASE)
            if match:
                return self.parse_date(match.group(1))
        
        return None
    
    def extract_end_time(self, text):
        """Extrait l'heure de fin"""
        patterns = [
            r'Heure de fin\s*:\s*([\d/\-]+\s+[\d:]+)',
            r'End time\s*:\s*([\d/\-]+\s+[\d:]+)',
            r'Fin\s*:\s*([\w,]+\s+\d+\s+\w+\s+\d+\s+[\d:]+)',
        ]
        
        for pattern in patterns:
            match = re.search(pattern, text, re.IGNORECASE)
            if match:
                return self.parse_date(match.group(1))
        
        return None
    
    def parse_date(self, date_str):
        """Parse une date string en format ISO"""
        try:
            formats = [
                '%d/%m/%Y %H:%M',
                '%Y/%m/%d %H:%M',
                '%d-%m-%Y %H:%M',
                '%Y-%m-%d %H:%M',
                '%d/%m/%Y %H:%M:%S',
                '%Y/%m/%d %H:%M:%S',
            ]
            
            for fmt in formats:
                try:
                    dt = datetime.strptime(date_str, fmt)
                    return dt.isoformat()
                except:
                    continue
            
            return date_str
        except Exception:
            return date_str
    
    def extract_nas_details(self, text):
        """Extrait les détails spécifiques aux sauvegardes NAS"""
        details = {}
        
        # Destination
        dest_match = re.search(r'Destination[^:]*:\s*([^\n]+)', text, re.IGNORECASE)
        if dest_match:
            details['destination'] = dest_match.group(1).strip()
        
        # Périphériques
        periph_match = re.search(r'périphériques?\s*:\s*([^\n]+)', text, re.IGNORECASE)
        if periph_match:
            details['peripheriques'] = periph_match.group(1).strip()
        
        return details
    
    def extract_pc_details(self, text):
        """Extrait les détails spécifiques aux sauvegardes PC"""
        details = {}
        
        # Nom du PC/utilisateur
        user_match = re.search(r'SAUV_PC_(\w+)|Sauvegarde PC (\w+)', text, re.IGNORECASE)
        if user_match:
            details['user'] = user_match.group(1) or user_match.group(2)
        
        return details
    
    def check_missing_backups(self, analyzed_emails):
        """
        Vérifie les sauvegardes manquantes (>48h sans nouvelles)
        
        Args:
            analyzed_emails: Liste des emails analysés
            
        Returns:
            dict: Sauvegardes manquantes par type
        """
        missing = {}
        current_time = datetime.now(timezone.utc)
        threshold = timedelta(hours=MONITORING_CONFIG['alert_threshold_hours'])
        
        # Grouper par nom de sauvegarde
        backups_by_name = {}
        for email_info in analyzed_emails:
            if not email_info:
                continue
                
            name = email_info['backup_name']
            if name not in backups_by_name:
                backups_by_name[name] = []
            backups_by_name[name].append(email_info)
        
        # Vérifier chaque sauvegarde
        for backup_name, emails in backups_by_name.items():
            # Trier par date décroissante
            emails.sort(key=lambda x: x['received_date'], reverse=True)
            
            if emails:
                latest = emails[0]
                try:
                    received_date = datetime.fromisoformat(
                        latest['received_date'].replace('Z', '+00:00')
                    )
                    
                    # Vérifier si trop ancien
                    if current_time - received_date > threshold:
                        missing[backup_name] = {
                            'last_seen': latest['received_date'],
                            'hours_ago': int((current_time - received_date).total_seconds() / 3600),
                            'type': latest['backup_type'],
                            'last_status': latest['status']
                        }
                        
                except Exception as e:
                    logger.error(f"Erreur parsing date pour {backup_name}: {str(e)}")
        
        return missing
    
    def get_failed_backups(self, analyzed_emails):
        """
        Récupère les sauvegardes en échec récentes
        
        Args:
            analyzed_emails: Liste des emails analysés
            
        Returns:
            list: Sauvegardes en échec
        """
        failed = []
        
        for email_info in analyzed_emails:
            if email_info and email_info['status'] == 'failure':
                failed.append(email_info)
        
        # Trier par date décroissante
        failed.sort(key=lambda x: x['received_date'], reverse=True)
        
        return failed