import customtkinter as ctk
from core.process_runner import ProcessRunner
from core import reporting
import threading
from tkinter import filedialog
import os

class ForensicsFrame(ctk.CTkFrame):
    def __init__(self, master, set_session_callback=None, heading_font=None, text_font=None):
        super().__init__(master)
        self.set_session_callback = set_session_callback
        self.heading_font = heading_font if heading_font else ctk.CTkFont(size=18, weight="bold")
        self.text_font = text_font if text_font else ctk.CTkFont(size=12)
        self.monospace_font = ctk.CTkFont(family="Fira Code", size=12) # For output textboxes
        self.grid_columnconfigure(0, weight=1)
        self.grid_rowconfigure(1, weight=1)

        title = ctk.CTkLabel(self, text="Sección de Forense", font=self.heading_font)
        title.grid(row=0, column=0, padx=20, pady=(20, 10), sticky="ew")

        self.tab_view = ctk.CTkTabview(self)
        self.tab_view.grid(row=1, column=0, padx=20, pady=10, sticky="nsew")

        self.tab_view.add("ExifTool")
        self.tab_view.add("Strings")
        self.tab_view.add("Binwalk")

        self.exiftool_process_runner = None
        self.strings_process_runner = None
        self.binwalk_process_runner = None
        self.current_session_name = None

        self.setup_exiftool_tab()
        self.setup_strings_tab()
        self.setup_binwalk_tab()

    def setup_exiftool_tab(self):
        tab = self.tab_view.tab("ExifTool")
        tab.grid_columnconfigure(0, weight=1)
        tab.grid_rowconfigure(4, weight=1)

        # ---- Controles ----
        controls_frame = ctk.CTkFrame(tab)
        controls_frame.grid(row=0, column=0, padx=10, pady=10, sticky="ew")
        controls_frame.grid_columnconfigure(0, weight=1)
        controls_frame.grid_columnconfigure(1, weight=3)

        # Target File
        target_file_frame = ctk.CTkFrame(controls_frame, fg_color="transparent")
        target_file_frame.grid(row=0, column=0, columnspan=2, padx=5, pady=5, sticky="ew")
        target_file_frame.grid_columnconfigure(0, weight=1)

        self.exiftool_file_entry = ctk.CTkEntry(target_file_frame, placeholder_text="Ruta al archivo a analizar (ej: /path/to/image.jpg)")
        self.exiftool_file_entry.grid(row=0, column=0, padx=(5, 5), sticky="ew")
        self.exiftool_file_button = ctk.CTkButton(target_file_frame, text="Seleccionar Archivo", command=self.select_exiftool_file, width=120)
        self.exiftool_file_button.grid(row=0, column=1, padx=(10, 0))

        # Extra Arguments
        self.exiftool_extra_args_label = ctk.CTkLabel(controls_frame, text="Argumentos Extra (ej: -gps -a):")
        self.exiftool_extra_args_label.grid(row=1, column=0, padx=10, pady=8, sticky="w")
        self.exiftool_extra_args_entry = ctk.CTkEntry(controls_frame, placeholder_text="ej: -all -s -G")
        self.exiftool_extra_args_entry.grid(row=1, column=1, padx=10, pady=8, sticky="ew")

        # Start/Stop Buttons
        buttons_frame = ctk.CTkFrame(tab)
        buttons_frame.grid(row=1, column=0, padx=10, pady=10, sticky="ew")
        buttons_frame.grid_columnconfigure(0, weight=1)
        buttons_frame.grid_columnconfigure(1, weight=1)

        self.exiftool_start_button = ctk.CTkButton(buttons_frame, text="Iniciar ExifTool", command=self.start_exiftool_analysis)
        self.exiftool_start_button.grid(row=0, column=0, padx=10, pady=12, sticky="ew")

        self.exiftool_stop_button = ctk.CTkButton(buttons_frame, text="Detener", command=self.stop_exiftool_analysis, fg_color="red", state="disabled")
        self.exiftool_stop_button.grid(row=0, column=1, padx=10, pady=12, sticky="ew")
        
        # ---- Output ----
        self.exiftool_output_textbox = ctk.CTkTextbox(tab, state="disabled", font=self.monospace_font)
        self.exiftool_output_textbox.grid(row=4, column=0, padx=10, pady=10, sticky="nsew")

    def select_exiftool_file(self):
        filepath = filedialog.askopenfilename(title="Seleccionar archivo para ExifTool")
        if filepath:
            self.exiftool_file_entry.delete(0, "end")
            self.exiftool_file_entry.insert(0, filepath)

    def start_exiftool_analysis(self):
        target_file = self.exiftool_file_entry.get()
        extra_args = self.exiftool_extra_args_entry.get().split()

        if not target_file:
            return

        self.exiftool_start_button.configure(state="disabled")
        self.exiftool_stop_button.configure(state="normal")
        
        self.current_session_name = reporting.create_session(f"exiftool_{os.path.basename(target_file)}")
        if self.set_session_callback:
            self.set_session_callback(self.current_session_name)
        
        command = ["exiftool"]
        command.extend(extra_args)
        command.append(target_file)

        self.exiftool_output_textbox.configure(state="normal")
        self.exiftool_output_textbox.delete("1.0", "end")
        self.exiftool_output_textbox.insert("1.0", f"--- Iniciando ExifTool ---\nComando: {' '.join(command)}\n\n")
        self.exiftool_output_textbox.configure(state="disabled")

        self.exiftool_process_runner = ProcessRunner(command, self.exiftool_output_textbox)
        self.exiftool_process_runner.start()
        
        threading.Thread(target=self.wait_and_save_exiftool, daemon=True).start()

    def stop_exiftool_analysis(self):
        if self.exiftool_process_runner:
            self.exiftool_process_runner.stop()
            self.exiftool_start_button.configure(state="normal")
            self.exiftool_stop_button.configure(state="disabled")

    def wait_and_save_exiftool(self):
        if self.exiftool_process_runner:
            self.exiftool_process_runner.thread.join()

        full_output = self.exiftool_output_textbox.get("1.0", "end")
        reporting.log_tool_output(self.current_session_name, "ExifTool Analysis", full_output, output_format="txt")
        
        self.master.after(0, self._reset_exiftool_buttons)

    def _reset_exiftool_buttons(self):
        self.exiftool_start_button.configure(state="normal")
        self.exiftool_stop_button.configure(state="disabled")

    def setup_strings_tab(self):
        tab = self.tab_view.tab("Strings")
        tab.grid_columnconfigure(0, weight=1)
        tab.grid_rowconfigure(4, weight=1)

        # ---- Controles ----
        controls_frame = ctk.CTkFrame(tab)
        controls_frame.grid(row=0, column=0, padx=10, pady=10, sticky="ew")
        controls_frame.grid_columnconfigure(0, weight=1)
        controls_frame.grid_columnconfigure(1, weight=3)

        # Target File
        target_file_frame = ctk.CTkFrame(controls_frame, fg_color="transparent")
        target_file_frame.grid(row=0, column=0, columnspan=2, padx=5, pady=5, sticky="ew")
        target_file_frame.grid_columnconfigure(0, weight=1)

        self.strings_file_entry = ctk.CTkEntry(target_file_frame, placeholder_text="Ruta al archivo a analizar (ej: /path/to/binary)")
        self.strings_file_entry.grid(row=0, column=0, padx=(5, 5), sticky="ew")
        self.strings_file_button = ctk.CTkButton(target_file_frame, text="Seleccionar Archivo", command=self.select_strings_file, width=120)
        self.strings_file_button.grid(row=0, column=1, padx=(10, 0))

        # Extra Arguments
        self.strings_extra_args_label = ctk.CTkLabel(controls_frame, text="Argumentos Extra (ej: -n 8):")
        self.strings_extra_args_label.grid(row=1, column=0, padx=10, pady=8, sticky="w")
        self.strings_extra_args_entry = ctk.CTkEntry(controls_frame, placeholder_text="ej: -a -n 8")
        self.strings_extra_args_entry.grid(row=1, column=1, padx=10, pady=8, sticky="ew")

        # Start/Stop Buttons
        buttons_frame = ctk.CTkFrame(tab)
        buttons_frame.grid(row=1, column=0, padx=10, pady=10, sticky="ew")
        buttons_frame.grid_columnconfigure(0, weight=1)
        buttons_frame.grid_columnconfigure(1, weight=1)

        self.strings_start_button = ctk.CTkButton(buttons_frame, text="Iniciar Strings", command=self.start_strings_analysis)
        self.strings_start_button.grid(row=0, column=0, padx=10, pady=12, sticky="ew")

        self.strings_stop_button = ctk.CTkButton(buttons_frame, text="Detener", command=self.stop_strings_analysis, fg_color="red", state="disabled")
        self.strings_stop_button.grid(row=0, column=1, padx=10, pady=12, sticky="ew")
        
        # ---- Output ----
        self.strings_output_textbox = ctk.CTkTextbox(tab, state="disabled", font=self.monospace_font)
        self.strings_output_textbox.grid(row=4, column=0, padx=10, pady=10, sticky="nsew")

    def select_strings_file(self):
        filepath = filedialog.askopenfilename(title="Seleccionar archivo para Strings")
        if filepath:
            self.strings_file_entry.delete(0, "end")
            self.strings_file_entry.insert(0, filepath)

    def start_strings_analysis(self):
        target_file = self.strings_file_entry.get()
        extra_args = self.strings_extra_args_entry.get().split()

        if not target_file:
            return

        self.strings_start_button.configure(state="disabled")
        self.strings_stop_button.configure(state="normal")
        
        self.current_session_name = reporting.create_session(f"strings_{os.path.basename(target_file)}")
        if self.set_session_callback:
            self.set_session_callback(self.current_session_name)
        
        command = ["strings"]
        command.extend(extra_args)
        command.append(target_file)

        self.strings_output_textbox.configure(state="normal")
        self.strings_output_textbox.delete("1.0", "end")
        self.strings_output_textbox.insert("1.0", f"--- Iniciando Strings ---\nComando: {' '.join(command)}\n\n")
        self.strings_output_textbox.configure(state="disabled")

        self.strings_process_runner = ProcessRunner(command, self.strings_output_textbox)
        self.strings_process_runner.start()
        
        threading.Thread(target=self.wait_and_save_strings, daemon=True).start()

    def stop_strings_analysis(self):
        if self.strings_process_runner:
            self.strings_process_runner.stop()
            self.strings_start_button.configure(state="normal")
            self.strings_stop_button.configure(state="disabled")

    def wait_and_save_strings(self):
        if self.strings_process_runner:
            self.strings_process_runner.thread.join()

        full_output = self.strings_output_textbox.get("1.0", "end")
        reporting.log_tool_output(self.current_session_name, "Strings Analysis", full_output, output_format="txt")
        
        self.master.after(0, self._reset_strings_buttons)

    def _reset_strings_buttons(self):
        self.strings_start_button.configure(state="normal")
        self.strings_stop_button.configure(state="disabled")

    def setup_binwalk_tab(self):
        tab = self.tab_view.tab("Binwalk")
        tab.grid_columnconfigure(0, weight=1)
        tab.grid_rowconfigure(4, weight=1)

        # ---- Controles ----
        controls_frame = ctk.CTkFrame(tab)
        controls_frame.grid(row=0, column=0, padx=10, pady=10, sticky="ew")
        controls_frame.grid_columnconfigure(0, weight=1)
        controls_frame.grid_columnconfigure(1, weight=3)

        # Target File
        target_file_frame = ctk.CTkFrame(controls_frame, fg_color="transparent")
        target_file_frame.grid(row=0, column=0, columnspan=2, padx=5, pady=5, sticky="ew")
        target_file_frame.grid_columnconfigure(0, weight=1)

        self.binwalk_file_entry = ctk.CTkEntry(target_file_frame, placeholder_text="Ruta al archivo de firmware o binario (ej: /path/to/firmware.bin)")
        self.binwalk_file_entry.grid(row=0, column=0, padx=(5, 5), sticky="ew")
        self.binwalk_file_button = ctk.CTkButton(target_file_frame, text="Seleccionar Archivo", command=self.select_binwalk_file, width=120)
        self.binwalk_file_button.grid(row=0, column=1, padx=(10, 0))

        # Extra Arguments
        self.binwalk_extra_args_label = ctk.CTkLabel(controls_frame, text="Argumentos Extra (ej: -Me):")
        self.binwalk_extra_args_label.grid(row=1, column=0, padx=10, pady=8, sticky="w")
        self.binwalk_extra_args_entry = ctk.CTkEntry(controls_frame, placeholder_text="ej: -Me (extract, carve)")
        self.binwalk_extra_args_entry.grid(row=1, column=1, padx=10, pady=8, sticky="ew")

        # Start/Stop Buttons
        buttons_frame = ctk.CTkFrame(tab)
        buttons_frame.grid(row=1, column=0, padx=10, pady=10, sticky="ew")
        buttons_frame.grid_columnconfigure(0, weight=1)
        buttons_frame.grid_columnconfigure(1, weight=1)

        self.binwalk_start_button = ctk.CTkButton(buttons_frame, text="Iniciar Binwalk", command=self.start_binwalk_analysis)
        self.binwalk_start_button.grid(row=0, column=0, padx=10, pady=12, sticky="ew")

        self.binwalk_stop_button = ctk.CTkButton(buttons_frame, text="Detener", command=self.stop_binwalk_analysis, fg_color="red", state="disabled")
        self.binwalk_stop_button.grid(row=0, column=1, padx=10, pady=12, sticky="ew")
        
        # ---- Output ----
        self.binwalk_output_textbox = ctk.CTkTextbox(tab, state="disabled", font=self.monospace_font)
        self.binwalk_output_textbox.grid(row=4, column=0, padx=10, pady=10, sticky="nsew")

    def select_binwalk_file(self):
        filepath = filedialog.askopenfilename(title="Seleccionar archivo para Binwalk")
        if filepath:
            self.binwalk_file_entry.delete(0, "end")
            self.binwalk_file_entry.insert(0, filepath)

    def start_binwalk_analysis(self):
        target_file = self.binwalk_file_entry.get()
        extra_args = self.binwalk_extra_args_entry.get().split()

        if not target_file:
            return

        self.binwalk_start_button.configure(state="disabled")
        self.binwalk_stop_button.configure(state="normal")
        
        self.current_session_name = reporting.create_session(f"binwalk_{os.path.basename(target_file)}")
        if self.set_session_callback:
            self.set_session_callback(self.current_session_name)
        
        command = ["binwalk"]
        command.extend(extra_args)
        command.append(target_file)

        self.binwalk_output_textbox.configure(state="normal")
        self.binwalk_output_textbox.delete("1.0", "end")
        self.binwalk_output_textbox.insert("1.0", f"--- Iniciando Binwalk ---\nComando: {' '.join(command)}\n\n")
        self.binwalk_output_textbox.configure(state="disabled")

        self.binwalk_process_runner = ProcessRunner(command, self.binwalk_output_textbox)
        self.binwalk_process_runner.start()
        
        threading.Thread(target=self.wait_and_save_binwalk, daemon=True).start()

    def stop_binwalk_analysis(self):
        if self.binwalk_process_runner:
            self.binwalk_process_runner.stop()
            self.binwalk_start_button.configure(state="normal")
            self.binwalk_stop_button.configure(state="disabled")

    def wait_and_save_binwalk(self):
        if self.binwalk_process_runner:
            self.binwalk_process_runner.thread.join()

        full_output = self.binwalk_output_textbox.get("1.0", "end")
        reporting.log_tool_output(self.current_session_name, "Binwalk Analysis", full_output, output_format="txt")
        
        self.master.after(0, self._reset_binwalk_buttons)

    def _reset_binwalk_buttons(self):
        self.binwalk_start_button.configure(state="normal")
        self.binwalk_stop_button.configure(state="disabled")