"""
Configuration manager for Web Sentinel GUI
Supports multiple domain profiles and scan configurations.
"""

import json
import yaml
from pathlib import Path
from typing import Dict, List, Any, Optional
from dataclasses import dataclass, asdict, field
from datetime import datetime


@dataclass
class ScanProfile:
    """Profil de configuration pour un scan."""
    name: str
    domains: List[str] = field(default_factory=list)
    modules: List[str] = field(default_factory=lambda: ["tls", "headers", "static-analysis"])
    timeout: float = 5.0
    allow_invasive: bool = False
    description: str = ""
    created_at: str = field(default_factory=lambda: datetime.now().isoformat())
    last_used: Optional[str] = None


@dataclass
class GuiConfig:
    """Configuration principale de l'interface."""
    profiles: Dict[str, ScanProfile] = field(default_factory=dict)
    default_profile: str = "default"
    window_geometry: str = "1000x700"
    last_export_path: str = ""
    auto_save: bool = True
    theme: str = "clam"
    max_concurrent_scans: int = 3


class ConfigManager:
    """Gestionnaire de configuration pour Web Sentinel GUI."""
    
    def __init__(self, config_dir: Optional[Path] = None):
        self.config_dir = config_dir or (Path.home() / ".web-sentinel")
        self.config_dir.mkdir(parents=True, exist_ok=True)
        
        self.config_file = self.config_dir / "gui-config.json"
        self.profiles_dir = self.config_dir / "profiles"
        self.profiles_dir.mkdir(exist_ok=True)
        
        self.config = self.load_config()
        
    def load_config(self) -> GuiConfig:
        """Charger la configuration principale."""
        try:
            if self.config_file.exists():
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    
                # Charger les profils
                profiles = {}
                for profile_name in data.get('profiles', {}):
                    profile = self.load_profile(profile_name)
                    if profile:
                        profiles[profile_name] = profile
                        
                config = GuiConfig(**{k: v for k, v in data.items() if k != 'profiles'})
                config.profiles = profiles
                return config
            else:
                # Configuration par défaut
                default_profile = ScanProfile(
                    name="default",
                    description="Profil de scan par défaut",
                    domains=[],
                    modules=["tls", "headers", "static-analysis", "injection", "third-party"]
                )
                config = GuiConfig()
                config.profiles["default"] = default_profile
                return config
                
        except Exception as e:
            print(f"Erreur lors du chargement de la configuration: {e}")
            # Configuration de secours
            return GuiConfig()
            
    def save_config(self) -> bool:
        """Sauvegarder la configuration principale."""
        try:
            # Sauvegarder les profils individuellement
            for profile_name, profile in self.config.profiles.items():
                self.save_profile(profile)
                
            # Sauvegarder la configuration principale
            config_data = asdict(self.config)
            config_data['profiles'] = list(self.config.profiles.keys())
            
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config_data, f, indent=2, ensure_ascii=False)
                
            return True
            
        except Exception as e:
            print(f"Erreur lors de la sauvegarde de la configuration: {e}")
            return False
            
    def load_profile(self, profile_name: str) -> Optional[ScanProfile]:
        """Charger un profil spécifique."""
        profile_file = self.profiles_dir / f"{profile_name}.json"
        try:
            if profile_file.exists():
                with open(profile_file, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    return ScanProfile(**data)
        except Exception as e:
            print(f"Erreur lors du chargement du profil {profile_name}: {e}")
        return None
        
    def save_profile(self, profile: ScanProfile) -> bool:
        """Sauvegarder un profil."""
        try:
            profile_file = self.profiles_dir / f"{profile.name}.json"
            with open(profile_file, 'w', encoding='utf-8') as f:
                json.dump(asdict(profile), f, indent=2, ensure_ascii=False)
            return True
        except Exception as e:
            print(f"Erreur lors de la sauvegarde du profil {profile.name}: {e}")
            return False
            
    def create_profile(self, name: str, domains: List[str], **kwargs) -> ScanProfile:
        """Créer un nouveau profil."""
        profile = ScanProfile(name=name, domains=domains, **kwargs)
        self.config.profiles[name] = profile
        self.save_profile(profile)
        return profile
        
    def delete_profile(self, profile_name: str) -> bool:
        """Supprimer un profil."""
        if profile_name == "default":
            return False  # Ne pas supprimer le profil par défaut
            
        if profile_name in self.config.profiles:
            del self.config.profiles[profile_name]
            
            # Supprimer le fichier
            profile_file = self.profiles_dir / f"{profile_name}.json"
            if profile_file.exists():
                profile_file.unlink()
                
            return True
        return False
        
    def get_profile(self, profile_name: str) -> Optional[ScanProfile]:
        """Récupérer un profil."""
        return self.config.profiles.get(profile_name)
        
    def list_profiles(self) -> List[str]:
        """Lister tous les profils disponibles."""
        return list(self.config.profiles.keys())
        
    def update_profile_usage(self, profile_name: str):
        """Mettre à jour la date de dernière utilisation d'un profil."""
        if profile_name in self.config.profiles:
            self.config.profiles[profile_name].last_used = datetime.now().isoformat()
            self.save_profile(self.config.profiles[profile_name])
            
    def import_domains_from_file(self, filepath: Path) -> List[str]:
        """Importer des domaines depuis différents formats de fichiers."""
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                if filepath.suffix.lower() == '.json':
                    data = json.load(f)
                    if isinstance(data, list):
                        return [str(item).strip() for item in data if str(item).strip()]
                    elif isinstance(data, dict):
                        # Plusieurs formats possibles
                        if 'domains' in data:
                            return [str(d).strip() for d in data['domains'] if str(d).strip()]
                        elif 'targets' in data:
                            return [str(d).strip() for d in data['targets'] if str(d).strip()]
                        elif 'hosts' in data:
                            return [str(d).strip() for d in data['hosts'] if str(d).strip()]
                            
                elif filepath.suffix.lower() in ['.yml', '.yaml']:
                    data = yaml.safe_load(f)
                    if isinstance(data, list):
                        return [str(item).strip() for item in data if str(item).strip()]
                    elif isinstance(data, dict):
                        if 'domains' in data:
                            return [str(d).strip() for d in data['domains'] if str(d).strip()]
                            
                else:
                    # Fichier texte simple
                    lines = f.readlines()
                    domains = []
                    for line in lines:
                        line = line.strip()
                        if line and not line.startswith('#'):
                            # Gérer différents formats de lignes
                            if ',' in line:
                                domains.extend([d.strip() for d in line.split(',') if d.strip()])
                            else:
                                domains.append(line)
                    return domains
                    
        except Exception as e:
            print(f"Erreur lors de l'import du fichier {filepath}: {e}")
            
        return []
        
    def export_profile_to_file(self, profile_name: str, filepath: Path, format_type: str = "json") -> bool:
        """Exporter un profil vers un fichier."""
        profile = self.get_profile(profile_name)
        if not profile:
            return False
            
        try:
            with open(filepath, 'w', encoding='utf-8') as f:
                if format_type.lower() == 'json':
                    export_data = {
                        "profile_name": profile.name,
                        "description": profile.description,
                        "domains": profile.domains,
                        "modules": profile.modules,
                        "settings": {
                            "timeout": profile.timeout,
                            "allow_invasive": profile.allow_invasive
                        },
                        "exported_at": datetime.now().isoformat()
                    }
                    json.dump(export_data, f, indent=2, ensure_ascii=False)
                    
                elif format_type.lower() in ['yml', 'yaml']:
                    export_data = {
                        "profile": {
                            "name": profile.name,
                            "description": profile.description
                        },
                        "domains": profile.domains,
                        "modules": profile.modules,
                        "settings": {
                            "timeout": profile.timeout,
                            "allow_invasive": profile.allow_invasive
                        }
                    }
                    yaml.dump(export_data, f, default_flow_style=False, allow_unicode=True)
                    
                else:
                    # Format texte simple (domaines seulement)
                    f.write(f"# Profil: {profile.name}\n")
                    f.write(f"# Description: {profile.description}\n")
                    f.write(f"# Exporté le: {datetime.now().isoformat()}\n\n")
                    for domain in profile.domains:
                        f.write(f"{domain}\n")
                        
            return True
            
        except Exception as e:
            print(f"Erreur lors de l'export du profil {profile_name}: {e}")
            return False
            
    def get_recent_profiles(self, limit: int = 5) -> List[ScanProfile]:
        """Récupérer les profils récemment utilisés."""
        profiles = [p for p in self.config.profiles.values() if p.last_used]
        profiles.sort(key=lambda x: x.last_used or "", reverse=True)
        return profiles[:limit]
        
    def create_profile_from_template(self, template_name: str, new_name: str) -> Optional[ScanProfile]:
        """Créer un profil basé sur un template prédéfini."""
        templates = {
            "web_basic": {
                "description": "Scan basique pour sites web",
                "modules": ["tls", "headers", "static-analysis"],
                "timeout": 5.0,
                "allow_invasive": False
            },
            "web_complete": {
                "description": "Scan complet pour sites web",
                "modules": ["tls", "headers", "static-analysis", "injection", "third-party"],
                "timeout": 10.0,
                "allow_invasive": True
            },
            "api_security": {
                "description": "Scan spécialisé pour API REST",
                "modules": ["tls", "headers", "injection"],
                "timeout": 15.0,
                "allow_invasive": True
            },
            "monitoring": {
                "description": "Surveillance continue légère",
                "modules": ["tls", "headers"],
                "timeout": 3.0,
                "allow_invasive": False
            }
        }
        
        if template_name not in templates:
            return None
            
        template = templates[template_name]
        profile = ScanProfile(name=new_name, **template)
        self.config.profiles[new_name] = profile
        self.save_profile(profile)
        return profile