"""
Système de thèmes visuels pour Web Sentinel GUI
Permet de personnaliser l'apparence de l'application avec différents styles
"""

import tkinter as tk
from tkinter import ttk
from typing import Dict, Any, Optional
from dataclasses import dataclass


@dataclass
class ThemeColors:
    """Définition des couleurs d'un thème."""
    # Couleurs de fond
    bg_primary: str          # Fond principal
    bg_secondary: str        # Fond secondaire (frames, panels)
    bg_accent: str          # Fond accentué (boutons, highlights)
    bg_hover: str           # Survol
    
    # Couleurs de texte
    fg_primary: str         # Texte principal
    fg_secondary: str       # Texte secondaire
    fg_accent: str          # Texte accentué
    fg_disabled: str        # Texte désactivé
    
    # Couleurs fonctionnelles
    success: str            # Succès (vert)
    warning: str            # Avertissement (orange)
    error: str              # Erreur (rouge)
    info: str               # Information (bleu)
    
    # Couleurs de sévérité (pour les findings)
    critical_bg: str
    critical_fg: str
    high_bg: str
    high_fg: str
    medium_bg: str
    medium_fg: str
    low_bg: str
    low_fg: str
    info_severity_bg: str
    info_severity_fg: str
    
    # Bordures et séparateurs
    border: str
    separator: str
    
    # Éléments interactifs
    button_bg: str
    button_fg: str
    button_hover: str
    button_active: str
    
    # Entrées de texte
    entry_bg: str
    entry_fg: str
    entry_border: str
    entry_focus: str


class Theme:
    """Classe de base pour un thème."""
    
    def __init__(self, name: str, colors: ThemeColors):
        self.name = name
        self.colors = colors
    
    def apply(self, root: tk.Tk, style: ttk.Style):
        """Applique le thème à l'application."""
        # Configuration du thème tkinter
        style.theme_use('clam')
        
        # Configuration du fond principal
        root.configure(bg=self.colors.bg_primary)
        
        # Configuration des styles ttk
        self._configure_frame_styles(style)
        self._configure_label_styles(style)
        self._configure_button_styles(style)
        self._configure_entry_styles(style)
        self._configure_treeview_styles(style)
        self._configure_progressbar_styles(style)
        self._configure_checkbutton_styles(style)
        self._configure_notebook_styles(style)
        self._configure_labelframe_styles(style)
        
        # Forcer la mise à jour de tous les widgets existants
        self._update_existing_widgets(root)
    
    def _update_existing_widgets(self, widget):
        """Met à jour récursivement tous les widgets existants."""
        try:
            # Mettre à jour les widgets tk natifs (non-ttk)
            widget_type = widget.winfo_class()
            
            if widget_type == 'Frame':
                try:
                    widget.configure(bg=self.colors.bg_primary)
                except:
                    pass
            elif widget_type == 'Label':
                try:
                    widget.configure(bg=self.colors.bg_primary, fg=self.colors.fg_primary)
                except:
                    pass
            elif widget_type == 'Text':
                try:
                    widget.configure(bg=self.colors.entry_bg, fg=self.colors.entry_fg)
                except:
                    pass
            elif widget_type == 'Listbox':
                try:
                    widget.configure(bg=self.colors.bg_secondary, fg=self.colors.fg_primary)
                except:
                    pass
            elif widget_type == 'Canvas':
                try:
                    widget.configure(bg=self.colors.bg_primary)
                except:
                    pass
            
            # Récursion sur les enfants
            for child in widget.winfo_children():
                self._update_existing_widgets(child)
        except:
            pass
    
    def _configure_frame_styles(self, style: ttk.Style):
        """Configure les styles de Frame."""
        style.configure("TFrame",
                       background=self.colors.bg_primary,
                       borderwidth=0)
        
        style.configure("Card.TFrame",
                       background=self.colors.bg_secondary,
                       relief="flat",
                       borderwidth=1)
        
        style.configure("Accent.TFrame",
                       background=self.colors.bg_accent,
                       borderwidth=0)
    
    def _configure_label_styles(self, style: ttk.Style):
        """Configure les styles de Label."""
        style.configure("TLabel",
                       background=self.colors.bg_primary,
                       foreground=self.colors.fg_primary,
                       borderwidth=0)
        
        style.configure("Title.TLabel",
                       background=self.colors.bg_primary,
                       foreground=self.colors.fg_accent,
                       font=("Arial", 16, "bold"),
                       borderwidth=0)
        
        style.configure("Subtitle.TLabel",
                       background=self.colors.bg_primary,
                       foreground=self.colors.fg_secondary,
                       font=("Arial", 12, "bold"),
                       borderwidth=0)
        
        style.configure("Secondary.TLabel",
                       background=self.colors.bg_primary,
                       foreground=self.colors.fg_secondary,
                       font=("Arial", 9),
                       borderwidth=0)
        
        style.configure("Success.TLabel",
                       background=self.colors.bg_primary,
                       foreground=self.colors.success,
                       font=("Arial", 10, "bold"),
                       borderwidth=0)
        
        style.configure("Error.TLabel",
                       background=self.colors.bg_primary,
                       foreground=self.colors.error,
                       font=("Arial", 10, "bold"),
                       borderwidth=0)
    
    def _configure_button_styles(self, style: ttk.Style):
        """Configure les styles de Button."""
        style.configure("TButton",
                       background=self.colors.button_bg,
                       foreground=self.colors.button_fg,
                       borderwidth=1,
                       focuscolor=self.colors.entry_focus,
                       lightcolor=self.colors.bg_secondary,
                       darkcolor=self.colors.border,
                       relief="flat",
                       font=("Arial", 10))
        
        style.map("TButton",
                 background=[("active", self.colors.button_hover),
                           ("pressed", self.colors.button_active)],
                 foreground=[("disabled", self.colors.fg_disabled)])
        
        style.configure("Accent.TButton",
                       background=self.colors.bg_accent,
                       foreground=self.colors.fg_accent,
                       font=("Arial", 10, "bold"))
        
        style.map("Accent.TButton",
                 background=[("active", self.colors.button_hover),
                           ("pressed", self.colors.button_active)])
        
        style.configure("Success.TButton",
                       background=self.colors.success,
                       foreground="white",
                       font=("Arial", 10, "bold"))
        
        style.configure("Danger.TButton",
                       background=self.colors.error,
                       foreground="white",
                       font=("Arial", 10, "bold"))
    
    def _configure_entry_styles(self, style: ttk.Style):
        """Configure les styles d'Entry."""
        style.configure("TEntry",
                       fieldbackground=self.colors.entry_bg,
                       foreground=self.colors.entry_fg,
                       bordercolor=self.colors.entry_border,
                       lightcolor=self.colors.entry_focus,
                       darkcolor=self.colors.entry_border)
        
        style.map("TEntry",
                 bordercolor=[("focus", self.colors.entry_focus)],
                 lightcolor=[("focus", self.colors.entry_focus)])
    
    def _configure_treeview_styles(self, style: ttk.Style):
        """Configure les styles de Treeview."""
        style.configure("Treeview",
                       background=self.colors.bg_secondary,
                       foreground=self.colors.fg_primary,
                       fieldbackground=self.colors.bg_secondary,
                       borderwidth=1,
                       relief="flat")
        
        style.configure("Treeview.Heading",
                       background=self.colors.bg_accent,
                       foreground=self.colors.fg_accent,
                       borderwidth=1,
                       relief="flat",
                       font=("Arial", 10, "bold"))
        
        style.map("Treeview",
                 background=[("selected", self.colors.bg_accent)],
                 foreground=[("selected", self.colors.fg_accent)])
    
    def _configure_progressbar_styles(self, style: ttk.Style):
        """Configure les styles de Progressbar."""
        style.configure("TProgressbar",
                       background=self.colors.success,
                       troughcolor=self.colors.bg_secondary,
                       bordercolor=self.colors.border,
                       lightcolor=self.colors.success,
                       darkcolor=self.colors.success)
    
    def _configure_checkbutton_styles(self, style: ttk.Style):
        """Configure les styles de Checkbutton."""
        style.configure("TCheckbutton",
                       background=self.colors.bg_primary,
                       foreground=self.colors.fg_primary,
                       indicatorcolor=self.colors.entry_bg,
                       focuscolor=self.colors.entry_focus)
        
        style.map("TCheckbutton",
                 background=[("active", self.colors.bg_hover)],
                 indicatorcolor=[("selected", self.colors.bg_accent)])
    
    def _configure_notebook_styles(self, style: ttk.Style):
        """Configure les styles de Notebook (onglets)."""
        style.configure("TNotebook",
                       background=self.colors.bg_primary,
                       borderwidth=0)
        
        style.configure("TNotebook.Tab",
                       background=self.colors.bg_secondary,
                       foreground=self.colors.fg_secondary,
                       padding=[20, 10],
                       borderwidth=0,
                       font=("Arial", 10))
        
        style.map("TNotebook.Tab",
                 background=[("selected", self.colors.bg_accent)],
                 foreground=[("selected", self.colors.fg_accent)],
                 expand=[("selected", [1, 1, 1, 0])])
    
    def _configure_labelframe_styles(self, style: ttk.Style):
        """Configure les styles de LabelFrame."""
        style.configure("TLabelframe",
                       background=self.colors.bg_primary,
                       borderwidth=2,
                       relief="groove")
        
        style.configure("TLabelframe.Label",
                       background=self.colors.bg_primary,
                       foreground=self.colors.fg_accent,
                       font=("Arial", 10, "bold"))


# ============================================================================
# THÈMES PRÉDÉFINIS
# ============================================================================

# Thème par défaut (existant - style clair classique)
DEFAULT_THEME = Theme(
    name="Default",
    colors=ThemeColors(
        # Fond
        bg_primary="#f3f4f6",
        bg_secondary="#ffffff",
        bg_accent="#3b82f6",
        bg_hover="#e5e7eb",
        
        # Texte
        fg_primary="#111827",
        fg_secondary="#6b7280",
        fg_accent="#ffffff",
        fg_disabled="#9ca3af",
        
        # Fonctionnel
        success="#10b981",
        warning="#f59e0b",
        error="#ef4444",
        info="#3b82f6",
        
        # Sévérité
        critical_bg="#fee2e2",
        critical_fg="#991b1b",
        high_bg="#fed7aa",
        high_fg="#9a3412",
        medium_bg="#fef3c7",
        medium_fg="#92400e",
        low_bg="#dbeafe",
        low_fg="#1e3a8a",
        info_severity_bg="#f3f4f6",
        info_severity_fg="#374151",
        
        # Bordures
        border="#d1d5db",
        separator="#e5e7eb",
        
        # Boutons
        button_bg="#3b82f6",
        button_fg="#ffffff",
        button_hover="#2563eb",
        button_active="#1d4ed8",
        
        # Entrées
        entry_bg="#ffffff",
        entry_fg="#111827",
        entry_border="#d1d5db",
        entry_focus="#3b82f6"
    )
)


# Thème Dark (sombre élégant)
DARK_THEME = Theme(
    name="Dark",
    colors=ThemeColors(
        # Fond
        bg_primary="#1a1a1a",
        bg_secondary="#2d2d2d",
        bg_accent="#4f46e5",
        bg_hover="#3a3a3a",
        
        # Texte
        fg_primary="#e5e7eb",
        fg_secondary="#9ca3af",
        fg_accent="#ffffff",
        fg_disabled="#6b7280",
        
        # Fonctionnel
        success="#10b981",
        warning="#f59e0b",
        error="#ef4444",
        info="#3b82f6",
        
        # Sévérité
        critical_bg="#7f1d1d",
        critical_fg="#fecaca",
        high_bg="#7c2d12",
        high_fg="#fed7aa",
        medium_bg="#78350f",
        medium_fg="#fef3c7",
        low_bg="#1e3a8a",
        low_fg="#dbeafe",
        info_severity_bg="#374151",
        info_severity_fg="#d1d5db",
        
        # Bordures
        border="#404040",
        separator="#3a3a3a",
        
        # Boutons
        button_bg="#4f46e5",
        button_fg="#ffffff",
        button_hover="#4338ca",
        button_active="#3730a3",
        
        # Entrées
        entry_bg="#2d2d2d",
        entry_fg="#e5e7eb",
        entry_border="#404040",
        entry_focus="#4f46e5"
    )
)


# Thème Cyberpunk (néon futuriste)
CYBERPUNK_THEME = Theme(
    name="Cyberpunk",
    colors=ThemeColors(
        # Fond
        bg_primary="#0a0e27",
        bg_secondary="#151934",
        bg_accent="#00ff9f",
        bg_hover="#1a1f3a",
        
        # Texte
        fg_primary="#00ff9f",
        fg_secondary="#7dd3fc",
        fg_accent="#0a0e27",
        fg_disabled="#475569",
        
        # Fonctionnel
        success="#00ff9f",
        warning="#fbbf24",
        error="#ff006e",
        info="#00d4ff",
        
        # Sévérité
        critical_bg="#3d0021",
        critical_fg="#ff006e",
        high_bg="#3d1f00",
        high_fg="#fbbf24",
        medium_bg="#1e2d00",
        medium_fg="#a3e635",
        low_bg="#001f3d",
        low_fg="#00d4ff",
        info_severity_bg="#1a1f3a",
        info_severity_fg="#7dd3fc",
        
        # Bordures
        border="#00ff9f",
        separator="#1a1f3a",
        
        # Boutons
        button_bg="#00ff9f",
        button_fg="#0a0e27",
        button_hover="#00d4ff",
        button_active="#00b380",
        
        # Entrées
        entry_bg="#151934",
        entry_fg="#00ff9f",
        entry_border="#00ff9f",
        entry_focus="#00d4ff"
    )
)


# Thème Nord (inspiration palette Nord)
NORD_THEME = Theme(
    name="Nord",
    colors=ThemeColors(
        # Fond
        bg_primary="#2e3440",
        bg_secondary="#3b4252",
        bg_accent="#88c0d0",
        bg_hover="#434c5e",
        
        # Texte
        fg_primary="#eceff4",
        fg_secondary="#d8dee9",
        fg_accent="#2e3440",
        fg_disabled="#4c566a",
        
        # Fonctionnel
        success="#a3be8c",
        warning="#ebcb8b",
        error="#bf616a",
        info="#81a1c1",
        
        # Sévérité
        critical_bg="#3b1f1f",
        critical_fg="#bf616a",
        high_bg="#3b2f1f",
        high_fg="#d08770",
        medium_bg="#3b3b1f",
        medium_fg="#ebcb8b",
        low_bg="#1f2f3b",
        low_fg="#81a1c1",
        info_severity_bg="#3b4252",
        info_severity_fg="#d8dee9",
        
        # Bordures
        border="#4c566a",
        separator="#434c5e",
        
        # Boutons
        button_bg="#88c0d0",
        button_fg="#2e3440",
        button_hover="#8fbcbb",
        button_active="#81a1c1",
        
        # Entrées
        entry_bg="#3b4252",
        entry_fg="#eceff4",
        entry_border="#4c566a",
        entry_focus="#88c0d0"
    )
)


# Thème Ocean (bleu apaisant)
OCEAN_THEME = Theme(
    name="Ocean",
    colors=ThemeColors(
        # Fond
        bg_primary="#0c2d48",
        bg_secondary="#145374",
        bg_accent="#2e8bc0",
        bg_hover="#1a5980",
        
        # Texte
        fg_primary="#e8f1f5",
        fg_secondary="#b1d4e0",
        fg_accent="#ffffff",
        fg_disabled="#2e5266",
        
        # Fonctionnel
        success="#06d6a0",
        warning="#ffd23f",
        error="#ff5a5f",
        info="#4cc9f0",
        
        # Sévérité
        critical_bg="#2d1215",
        critical_fg="#ff5a5f",
        high_bg="#2d2112",
        high_fg="#ffd23f",
        medium_bg="#1f2d12",
        medium_fg="#06d6a0",
        low_bg="#12212d",
        low_fg="#4cc9f0",
        info_severity_bg="#145374",
        info_severity_fg="#b1d4e0",
        
        # Bordures
        border="#2e8bc0",
        separator="#1a5980",
        
        # Boutons
        button_bg="#2e8bc0",
        button_fg="#ffffff",
        button_hover="#4ca3d9",
        button_active="#1f6fa0",
        
        # Entrées
        entry_bg="#145374",
        entry_fg="#e8f1f5",
        entry_border="#2e8bc0",
        entry_focus="#4cc9f0"
    )
)


# Thème Forest (vert nature)
FOREST_THEME = Theme(
    name="Forest",
    colors=ThemeColors(
        # Fond
        bg_primary="#1b2a1f",
        bg_secondary="#2d4a31",
        bg_accent="#52a86f",
        bg_hover="#3d5a42",
        
        # Texte
        fg_primary="#e8f5e9",
        fg_secondary="#a5d6a7",
        fg_accent="#ffffff",
        fg_disabled="#4a5f4d",
        
        # Fonctionnel
        success="#66bb6a",
        warning="#ffa726",
        error="#ef5350",
        info="#42a5f5",
        
        # Sévérité
        critical_bg="#3d1f1f",
        critical_fg="#ef5350",
        high_bg="#3d2a1f",
        high_fg="#ffa726",
        medium_bg="#2d3d1f",
        medium_fg="#9ccc65",
        low_bg="#1f2a3d",
        low_fg="#42a5f5",
        info_severity_bg="#2d4a31",
        info_severity_fg="#a5d6a7",
        
        # Bordures
        border="#52a86f",
        separator="#3d5a42",
        
        # Boutons
        button_bg="#52a86f",
        button_fg="#ffffff",
        button_hover="#66bb6a",
        button_active="#388e3c",
        
        # Entrées
        entry_bg="#2d4a31",
        entry_fg="#e8f5e9",
        entry_border="#52a86f",
        entry_focus="#66bb6a"
    )
)


# ============================================================================
# GESTIONNAIRE DE THÈMES
# ============================================================================

class ThemeManager:
    """Gestionnaire de thèmes pour l'application."""
    
    _themes: Dict[str, Theme] = {
        "default": DEFAULT_THEME,
        "dark": DARK_THEME,
        "cyberpunk": CYBERPUNK_THEME,
        "nord": NORD_THEME,
        "ocean": OCEAN_THEME,
        "forest": FOREST_THEME,
    }
    
    _current_theme: Optional[Theme] = None
    
    @classmethod
    def get_theme(cls, theme_name: str) -> Optional[Theme]:
        """Récupère un thème par son nom."""
        return cls._themes.get(theme_name.lower())
    
    @classmethod
    def get_all_themes(cls) -> Dict[str, Theme]:
        """Retourne tous les thèmes disponibles."""
        return cls._themes.copy()
    
    @classmethod
    def get_theme_names(cls) -> list[str]:
        """Retourne la liste des noms de thèmes disponibles."""
        return list(cls._themes.keys())
    
    @classmethod
    def apply_theme(cls, root: tk.Tk, style: ttk.Style, theme_name: str = "default"):
        """Applique un thème à l'application."""
        theme = cls.get_theme(theme_name)
        if theme:
            theme.apply(root, style)
            cls._current_theme = theme
        else:
            # Fallback au thème par défaut
            DEFAULT_THEME.apply(root, style)
            cls._current_theme = DEFAULT_THEME
    
    @classmethod
    def get_current_theme(cls) -> Optional[Theme]:
        """Retourne le thème actuellement appliqué."""
        return cls._current_theme
    
    @classmethod
    def register_theme(cls, theme_name: str, theme: Theme):
        """Enregistre un nouveau thème personnalisé."""
        cls._themes[theme_name.lower()] = theme


# Export des thèmes et du gestionnaire
__all__ = [
    "Theme",
    "ThemeColors",
    "ThemeManager",
    "DEFAULT_THEME",
    "DARK_THEME",
    "CYBERPUNK_THEME",
    "NORD_THEME",
    "OCEAN_THEME",
    "FOREST_THEME",
]
