import os
import sys

# Add the directory containing utils.tooltip_manager.py to sys.path
script_dir = os.path.dirname(__file__)
utils_dir = os.path.abspath(os.path.join(script_dir, "utils"))
sys.path.insert(0, utils_dir) # Insert utils directory first

import customtkinter as ctk
from utils.tooltip_manager import Tooltip
from utils import dependency_checker
from tkinter import messagebox

# Importar todos los frames de la UI
from ui.frame_osint import OSINTFrame
from ui.frame_web import WebFrame
from ui.frame_network import NetworkFrame
from ui.frame_exploit import ExploitFrame
from ui.frame_forensics import ForensicsFrame
from ui.frame_wifi import WifiFrame
from ui.frame_custom_utils import CustomUtilsFrame
from ui.frame_reports import ReportsFrame
from ui.frame_anonymity import AnonymityFrame # Nuevo
from ui.frame_help import HelpFrame
from ui.frame_bug_report import BugReportFrame # New import
from ui.frame_settings import SettingsFrame # New import
from ui.frame_settings import SettingsFrame # New import

class DependencyCheckWindow(ctk.CTkToplevel):
    # ... (El código de esta clase no cambia)
    def __init__(self, parent, missing_deps):
        super().__init__(parent)
        self.transient(parent)
        self.title("Verificación de Dependencias")
        self.geometry("700x450")
        self.update_idletasks() # Ensure the window is fully rendered before grab_set
        self.grab_set()
        self.protocol("WM_DELETE_WINDOW", self.exit_app)
        label = ctk.CTkLabel(self, text="¡Atención! Faltan Herramientas Esenciales", font=ctk.CTkFont(size=18, weight="bold")); label.pack(pady=(20, 10))
        info_label = ctk.CTkLabel(self, text="Cyber-Godfather depende de herramientas externas. Faltan las siguientes:", justify="center"); info_label.pack(pady=(0, 10))
        textbox = ctk.CTkTextbox(self, width=650, height=250); textbox.pack(pady=10); textbox.configure(state="normal")
        install_commands = dependency_checker.get_install_commands(missing_deps)
        textbox.insert("0.0", "Herramientas Faltantes y Comandos de Instalación (Sugeridos para Debian/Ubuntu/Kali):\n\n")
        for tool, command in install_commands.items():
            textbox.insert("end", f"-> {tool}:\n{command}\n\n")
        textbox.configure(state="disabled")
        button_frame = ctk.CTkFrame(self); button_frame.pack(pady=20)
        continue_button = ctk.CTkButton(button_frame, text="Continuar de Todas Formas", command=self.destroy); continue_button.pack(side="left", padx=10)
        exit_button = ctk.CTkButton(button_frame, text="Salir", command=self.exit_app, fg_color="red"); exit_button.pack(side="left", padx=10)
    def exit_app(self):
        self.master.destroy()
        sys.exit()

from ui.frame_network import NetworkFrame

class CyberGodfatherApp(ctk.CTk):
    APP_PADX = 15
    APP_PADY_TOP = 20
    APP_PADY_BOTTOM = 20
    BUTTON_PADY = 8

    def __init__(self):
        super().__init__()
        self.title("Ordasin Tools")
        self.geometry("1280x800")
        self.minsize(900, 650)
        ctk.set_appearance_mode("Dark")
        ctk.set_default_color_theme("Cyber-Godfather/themes/cyber_godfather_theme.json")
        self.grid_columnconfigure(1, weight=1)
        self.grid_rowconfigure(0, weight=1)
        self.withdraw()
        self.current_session_name = None # To keep track of the currently active session
        self.current_visible_frame = None # To keep track of the currently visible UI frame
        self._load_custom_fonts()
        self.check_dependencies_on_startup()

    def _load_custom_fonts(self):
        """Loads custom fonts from the assets directory."""
        font_path = os.path.join(script_dir, "assets")
        self.fira_code_regular = ctk.CTkFont(family=os.path.join(font_path, "FiraCode-Regular.ttf"), size=14)
        self.fira_code_bold = ctk.CTkFont(family=os.path.join(font_path, "FiraCode-Bold.ttf"), size=20, weight="bold")


    def get_available_themes(self):
        """Scans the themes directory and returns a list of available theme names."""
        themes_dir = os.path.join(script_dir, "themes")
        if not os.path.exists(themes_dir):
            return []
        
        theme_files = [f for f in os.listdir(themes_dir) if f.endswith(".json")]
        # Extract theme names without the .json extension
        return [os.path.splitext(f)[0] for f in theme_files]

    def set_theme(self, theme_name):
        """Sets the application theme to the specified theme name."""
        theme_file_path = os.path.join(script_dir, "themes", f"{theme_name}.json")
        if os.path.exists(theme_file_path):
            ctk.set_default_color_theme(theme_file_path)
            # Due to CustomTkinter's nature, theme changes might not apply instantly to all widgets.
            # Inform the user to restart the application for full theme application.
            print(f"Tema cambiado a: {theme_name}. Por favor, reinicia la aplicación para aplicar el tema completamente.")
            messagebox.showinfo(
                "Cambio de Tema",
                f"El tema ha sido cambiado a '{theme_name}'. Por favor, reinicia la aplicación para que los cambios se apliquen completamente."
            )
        else:
            print(f"Error: No se encontró el archivo de tema: {theme_name}.json")


    def set_current_session(self, session_name):
        """Sets the currently active session name in the main app."""
        self.current_session_name = session_name
        print(f"Sesión activa establecida en: {session_name}") # For debugging

    def check_dependencies_on_startup(self):
        missing = dependency_checker.check_dependencies()
        if missing:
            self.deiconify() # Ensure main window is visible before showing the warning
            warning_window = DependencyCheckWindow(self, missing)
            self.wait_window(warning_window)
        self.setup_main_ui()

    def setup_main_ui(self):
        # ---- Panel de Navegación ----
        self.nav_frame = ctk.CTkFrame(self, width=240, corner_radius=0, fg_color="#2b2b2b")
        self.nav_frame.grid(row=0, column=0, sticky="nsew")
        self.logo_label = ctk.CTkLabel(self.nav_frame, text="Ordasin Tools", font=self.fira_code_bold)
        self.logo_label.grid(row=0, column=0, padx=self.APP_PADX, pady=(self.APP_PADY_TOP, self.APP_PADY_BOTTOM))

        # ---- Diccionario de Frames ----
        self.frames = {}
        self.nav_buttons = {}
        
        # Define el orden y el texto de los botones
        frame_map = {
            "OSINT": OSINTFrame,
            "Hacking Web": WebFrame,
            "Red": NetworkFrame, # Nuevo Frame para herramientas de red
            "Explotación": ExploitFrame,
            "Forense": ForensicsFrame,
            "Hacking Wi-Fi": WifiFrame,
            "Utilidades": CustomUtilsFrame,
            "Reportes": ReportsFrame,
            "Anonimato": AnonymityFrame,
            "Configuración": SettingsFrame, # New settings frame
            "Ayuda": HelpFrame,
            "Reportar Fallo": BugReportFrame # New Frame for bug reporting
        }

        icon_map = {
            "OSINT": "🌐",
            "Hacking Web": "🕸️",
            "Red": "📡", # Icono para el nuevo frame
            "Explotación": "💥",
            "Forense": "🔬",
            "Hacking Wi-Fi": "📶",
            "Utilidades": "🛠️",
            "Reportes": "📄",
            "Anonimato": "👻",
            "Configuración": "⚙️", # Icon for settings
            "Ayuda": "❓",
            "Reportar Fallo": "🐞" # Icon for bug report frame
        }

        self.nav_frame.grid_rowconfigure(len(frame_map) + 1, weight=1)

        # Crea los botones y los frames
        for i, (name, frame_class) in enumerate(frame_map.items()):
            frame_args = {}
            if name in ["OSINT", "Hacking Web", "Red", "Explotación", "Forense", "Hacking Wi-Fi", "Reportes", "Reportar Fallo"]:
                frame_args["set_session_callback"] = self.set_current_session
            
            # Pass fonts to frames that are expected to use them for their internal widgets
            # This needs to be done explicitly for each frame that will consume these fonts
            if name in ["OSINT", "Hacking Web", "Red", "Explotación", "Forense", "Hacking Wi-Fi", "Utilidades", "Reportes", "Anonimato", "Ayuda", "Reportar Fallo", "Configuración"]:
                frame_args["heading_font"] = self.fira_code_bold
                frame_args["text_font"] = self.fira_code_regular

            if name == "Configuración":
                frame_args["get_themes_callback"] = self.get_available_themes
                frame_args["set_theme_callback"] = self.set_theme
            
            frame = frame_class(self, **frame_args)
            self.frames[name] = frame
            frame.grid(row=0, column=1, sticky="nsew") # Coloca todos en el mismo lugar
            
            button_text = f"{icon_map.get(name, '')} {name}".strip()
            button = ctk.CTkButton(self.nav_frame, text=button_text, command=lambda n=name: self.show_frame(n), font=self.fira_code_regular)
            button.grid(row=i+1, column=0, padx=self.APP_PADX, pady=12, sticky="ew")
            self.nav_buttons[name] = button

            # Add tooltip to navigation button
            tooltip_text = f"Navegar a la sección de {name}"
            Tooltip(button, tooltip_text, 
                    fg_color=("#333333", "#1e1e1e"), # (light mode color, dark mode color)
                    text_color=("gray10", "white"),
                    default_font=self.fira_code_regular)

        # Separator
        separator = ctk.CTkFrame(self.nav_frame, height=1, fg_color="gray30")
        separator.grid(row=len(frame_map) + 2, column=0, sticky="ew", padx=self.APP_PADX, pady=self.BUTTON_PADY)

        # Botón de Salir al final
        exit_button = ctk.CTkButton(self.nav_frame, text="Salir", command=self.quit, fg_color="red", font=self.fira_code_regular)
        exit_button.grid(row=len(frame_map) + 3, column=0, padx=self.APP_PADX, pady=(self.BUTTON_PADY, self.APP_PADY_TOP), sticky="ew")
        
        # ---- Muestra el primer frame ----
        self.show_frame("OSINT")

        if not self.winfo_viewable():
            self.deiconify()

    def show_frame(self, frame_name):
        """ Muestra un frame y oculta los demás con una sutil transición. """
        new_frame = self.frames[frame_name]

        # Lower the currently visible frame first, if any
        if self.current_visible_frame and self.current_visible_frame != new_frame:
            # We don't actually need to "lower" it if we just tkraise the new one
            # But for a subtle flicker effect, we can ensure old one is lowered
            # or simply let the tkraise handle the stacking.
            # For a "transition" without true fading, just ensuring correct stacking and then updating current_visible_frame is key.
            pass # No explicit lower needed here, tkraise handles stacking.

        new_frame.tkraise() # Bring the new frame to the front
        self.current_visible_frame = new_frame # Update the currently visible frame
        
        # Actualiza la apariencia de los botones de navegación
        for name, button in self.nav_buttons.items():
            if name == frame_name:
                button.configure(
                    fg_color=ctk.ThemeManager.theme["CTkSegmentedButton"]["selected_color"],
                    text_color="white",
                    border_width=2,
                    border_color=ctk.ThemeManager.theme["CTkSegmentedButton"]["selected_color"]
                )
            else:
                button.configure(
                    fg_color=ctk.ThemeManager.theme["CTkFrame"]["fg_color"], # Use frame background color
                    text_color=ctk.ThemeManager.theme["CTkButton"]["text_color"],
                    hover_color="gray25", # Custom hover color for unselected buttons
                    border_width=1, # Add border for unselected buttons
                    border_color="#404040" # Subtle border color
                )

if __name__ == "__main__":
    app = CyberGodfatherApp()
    app.mainloop()
