"""
Configuration tab component for the Excel Filter GUI
Matches the original layout with two-column design and configuration at top
"""

import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import tkinter.font as tkfont
import subprocess
import sys
import os

# Update the import to use absolute path
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from translations import Translations


class ConfigTab:
    """
    Configuration tab component that matches the original UI layout
    """

    def __init__(self, parent_frame, win11_colors, pattern_presets, pattern_descriptions, translations=None, scale_factor=1.0):
        """
        Initialize the configuration tab

        Args:
            parent_frame: Parent frame to attach to
            win11_colors: Windows 11 color palette dictionary
            pattern_presets: Dictionary of pattern presets
            pattern_descriptions: Dictionary of pattern descriptions
            translations: Translations object for internationalization
            scale_factor: DPI scaling factor for high-resolution displays
        """
        self.frame = ttk.Frame(parent_frame)
        self.win11_colors = win11_colors
        # Store references to the main GUI's preset dictionaries
        self.pattern_presets = pattern_presets
        self.pattern_descriptions = pattern_descriptions
        self.translations = translations or Translations()
        self.scale_factor = scale_factor
        
        # Variables for input fields
        self.input_file_var = tk.StringVar()
        self.output_file_var = tk.StringVar()
        self.pattern_var = tk.StringVar(value="error|warning|critical")
        self.sheet_var = tk.StringVar(value="Sheet1")
        self.columns_var = tk.StringVar()
        self.status_var = tk.StringVar(value=self.translations["status_ready"])
        self.regex_column_var = tk.StringVar(value=self.translations.get("all_columns", "Alle Spalten"))
        self.pattern_description_var = tk.StringVar()
        self.regex_enabled_var = tk.BooleanVar(value=True)  # Regex mode enabled by default
        self.column_selection_enabled = tk.BooleanVar(value=False)  # Column selection disabled by default (all columns selected)
        self.columns_vars = {}  # Dictionary to track selected columns

        # UI helpers
        self._tooltip_after_id = None
        self._tooltip_text_var = tk.StringVar(value="")

        # NEW: Numeric filtering variables
        self.numeric_filter_enabled = tk.BooleanVar(value=False)
        self.numeric_column_var = tk.StringVar(value="")
        self.numeric_operator_var = tk.StringVar(value=">")
        self.numeric_value_var = tk.StringVar(value="")
        self.numeric_filter_description_var = tk.StringVar(value="")
        
        # Reference to execution tab for logging (will be set later)
        self.execution_tab = None
        
        # Callback for column selection changes
        self.on_columns_changed = None
        
        self.create_widgets()
    
    def create_widgets(self):
        """
        Create all widgets for the configuration tab - matches original layout
        """
        # ===== UI metrics (Windows-like spacing & typography) =====
        # Keep sizes DPI-aware but consistent.
        pad_outer = int(12 * self.scale_factor)
        pad_section_y = int(10 * self.scale_factor)
        pad_cell_x = int(8 * self.scale_factor)
        pad_cell_y = int(6 * self.scale_factor)
        # Readability: enforce minimum size 12 for all visible text
        min_font_size = 12

        base_family = 'Segoe UI' if 'Segoe UI' in tkfont.families() else 'Helvetica'
        font_base = (base_family, max(int(10 * self.scale_factor), min_font_size))
        font_label = (base_family, max(int(10 * self.scale_factor), min_font_size))
        font_section = (base_family, max(int(10 * self.scale_factor), min_font_size), 'bold')
        font_hint = (base_family, max(int(9 * self.scale_factor), min_font_size), 'italic')
        font_info = (base_family, max(int(11 * self.scale_factor), min_font_size), 'bold')

        def _grid(widget, row, column, **kw):
            """Small helper to ensure consistent grid padding."""
            if 'padx' not in kw:
                kw['padx'] = pad_cell_x
            if 'pady' not in kw:
                kw['pady'] = pad_cell_y
            widget.grid(row=row, column=column, **kw)

        # ===== Styles =====
        style = ttk.Style()

        # Base widget fonts (keeps controls uniform)
        try:
            style.configure('TLabel', font=font_label)
            style.configure('TEntry', font=font_base)
            style.configure('TCheckbutton', font=font_label)
            style.configure('TButton', font=font_base)
            style.configure('TCombobox', font=font_base)
        except Exception:
            pass

        # Ensure combobox dropdown list uses readable font
        try:
            self.frame.option_add('*TCombobox*Listbox.font', font_base)
            self.frame.option_add('*ComboboxPopdownFrame*Listbox.font', font_base)
            self.frame.option_add('*Menu.font', font_base)
        except Exception:
            pass

        # Main container with two-column layout
        config_main_frame = ttk.Frame(self.frame, padding=str(pad_outer))
        config_main_frame.pack(fill=tk.BOTH, expand=True, padx=pad_outer, pady=pad_outer)

        # Left frame for input fields
        left_frame = ttk.Frame(config_main_frame)
        left_frame.grid(row=0, column=0, padx=(0, pad_outer), pady=0, sticky=tk.NSEW)

        # Right frame for sheet and columns selection
        right_frame = ttk.Frame(config_main_frame)
        right_frame.grid(row=0, column=1, padx=(pad_outer, 0), pady=0, sticky=tk.NSEW)

        # No vertical separator here: spacing between the columns is enough and
        # looks more native on Windows.
        
        # Column configuration
        config_main_frame.columnconfigure(0, weight=1)
        config_main_frame.columnconfigure(1, weight=1)
        config_main_frame.rowconfigure(0, weight=1)
        
        # Column configuration
        right_frame.columnconfigure(0, weight=1)
        right_frame.columnconfigure(1, weight=1)
        right_frame.rowconfigure(6, weight=1)

        # Left frame grid configuration
        left_frame.columnconfigure(0, weight=0)
        left_frame.columnconfigure(1, weight=1)
        left_frame.columnconfigure(2, weight=0)
        
        # ===== LEFT FRAME CONTENT =====
        
        # Configuration section at the top (moved from bottom)
        config_section = ttk.LabelFrame(left_frame, text=self.translations["config_section"], padding=str(int(10 * self.scale_factor)))
        _grid(config_section, row=0, column=0, columnspan=3, sticky=tk.W+tk.E, pady=(0, pad_section_y))

        # Add info tooltip for config section
        # Header line with info
        config_title_frame = ttk.Frame(config_section)
        config_title_frame.pack(fill=tk.X, pady=(0, pad_cell_y))

        header_label = ttk.Label(config_title_frame, text=self.translations["config_section"], font=font_section)
        header_label.pack(side=tk.LEFT)

        config_info = ttk.Label(config_title_frame, text="ⓘ", foreground=self.win11_colors.get('primary', 'blue'), font=font_info)
        config_info.pack(side=tk.LEFT, padx=(6, 0))
        self._bind_tooltip(config_info, "Du kannst Konfigurationen speichern und laden, statt alles jedes Mal neu einzugeben.")

        # Config buttons frame
        config_buttons_frame = ttk.Frame(config_section)
        config_buttons_frame.pack(fill=tk.X, pady=(0, pad_cell_y))

        load_button = ttk.Button(config_buttons_frame, text=self.translations["load_button"], command=self.load_config)
        load_button.pack(side=tk.LEFT, padx=(0, int(5 * self.scale_factor)))

        save_button = ttk.Button(config_buttons_frame, text=self.translations["save_button"], command=self.save_config)
        save_button.pack(side=tk.LEFT)

        # Status text inside config section
        config_status_label = ttk.Label(config_section, textvariable=self.status_var, foreground=self.win11_colors.get('primary', 'blue'))
        config_status_label.pack(anchor=tk.W)

        # Input file
        input_label = ttk.Label(left_frame, text=self.translations["input_file"])
        _grid(input_label, row=1, column=0, sticky=tk.W)

        input_entry = ttk.Entry(left_frame, textvariable=self.input_file_var)
        _grid(input_entry, row=1, column=1, sticky=tk.W+tk.E)

        input_button = ttk.Button(left_frame, text=self.translations["browse_button"])
        _grid(input_button, row=1, column=2, sticky=tk.E)
        # Command will be set in the main GUI after initialization

        # Output file
        output_label = ttk.Label(left_frame, text=self.translations["output_file"])
        _grid(output_label, row=2, column=0, sticky=tk.W)

        output_entry = ttk.Entry(left_frame, textvariable=self.output_file_var)
        _grid(output_entry, row=2, column=1, sticky=tk.W+tk.E)

        output_button = ttk.Button(left_frame, text=self.translations["browse_button"])
        _grid(output_button, row=2, column=2, sticky=tk.E)
        # Command will be set in the main GUI after initialization

        # Sheet selection - MOVED HERE from right column to group with file inputs
        sheet_label = ttk.Label(left_frame, text=self.translations.get("sheet", "Arbeitsblatt"), font=font_label)
        _grid(sheet_label, row=3, column=0, sticky=tk.W)

        self.sheet_combobox = ttk.Combobox(left_frame, textvariable=self.sheet_var, width=35)
        _grid(self.sheet_combobox, row=3, column=1, columnspan=2, sticky=tk.W+tk.E)
        self.sheet_combobox.bind("<<ComboboxSelected>>", self.on_sheet_selected)

        # No regex checkbox - NEW FEATURE (moved to top for better visibility)
        no_regex_frame = ttk.Frame(left_frame)
        _grid(no_regex_frame, row=4, column=0, columnspan=3, sticky=tk.W)

        regex_checkbox = ttk.Checkbutton(
            no_regex_frame,
            text="Regex-Filter aktivieren",
            variable=self.regex_enabled_var,
            command=self.toggle_regex_mode
        )
        regex_checkbox.pack(side=tk.LEFT, padx=int(5 * self.scale_factor))

        # Info tooltip for no regex mode
        no_regex_info = ttk.Label(no_regex_frame, text="ⓘ", foreground=self.win11_colors.get('primary', 'blue'), font=font_info)
        no_regex_info.pack(side=tk.LEFT, padx=int(5 * self.scale_factor))
        self._bind_tooltip(no_regex_info, "Wenn aktiviert, werden Regex-Muster für die Filterung verwendet")
        
        # Regex Options Box - GROUPED AND DISABLEABLE
        self.regex_options_frame = ttk.LabelFrame(
            left_frame,
            text=" Regex-Optionen ",
            padding="10",
            style='Regex.TLabelframe'
        )
        _grid(self.regex_options_frame, row=5, column=0, columnspan=3, sticky=tk.W+tk.E, pady=(0, pad_section_y))

        self.regex_options_frame.columnconfigure(0, weight=0)
        self.regex_options_frame.columnconfigure(1, weight=1)
        
        # Regex pattern (inside the box)
        pattern_label = ttk.Label(self.regex_options_frame, text="Regex-Muster:")
        pattern_label.grid(row=0, column=0, sticky=tk.W, pady=5)

        pattern_entry = ttk.Entry(self.regex_options_frame, textvariable=self.pattern_var)
        pattern_entry.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W+tk.E)

        # Pattern presets (inside the box)
        pattern_preset_label = ttk.Label(self.regex_options_frame, text="Voreingestellte Muster:")
        pattern_preset_label.grid(row=1, column=0, sticky=tk.W, pady=5)

        self.pattern_preset_combobox = ttk.Combobox(
            self.regex_options_frame,
            values=list(self.pattern_presets.keys()),
            state="readonly",
            width=35
        )
        self.pattern_preset_combobox.grid(row=1, column=1, padx=5, pady=5, sticky=tk.W+tk.E)
        self.pattern_preset_combobox.bind("<<ComboboxSelected>>", self.on_pattern_preset_selected)

        # Pattern description (inside the box)
        pattern_description_label = ttk.Label(
            self.regex_options_frame,
            textvariable=self.pattern_description_var,
            foreground="gray"
        )
        pattern_description_label.grid(row=2, column=0, columnspan=2, sticky=tk.W, pady=5)

        # Regex column selection (inside the box)
        regex_column_label = ttk.Label(self.regex_options_frame, text="Regex auf Spalte anwählen:")
        regex_column_label.grid(row=3, column=0, sticky=tk.W, pady=5)

        self.regex_column_combobox = ttk.Combobox(
            self.regex_options_frame,
            textvariable=self.regex_column_var,
            state="readonly",
            width=35
        )
        self.regex_column_combobox.grid(row=3, column=1, padx=5, pady=5, sticky=tk.W+tk.E)

        # Presets manager button at the end of regex options
        presets_button_frame = ttk.Frame(self.regex_options_frame)
        presets_button_frame.grid(row=4, column=0, columnspan=2, pady=(10, 0), sticky=tk.W+tk.E)

        presets_button = ttk.Button(presets_button_frame, text="Muster verwalten…", command=self.manage_presets, style='Outlined.TButton')
        presets_button.pack(side=tk.RIGHT)

        # Style the presets button with outline
        style.configure('Outlined.TButton',
                       font=font_base,
                       borderwidth=2,
                       relief='solid',
                       bordercolor=self.win11_colors['border'])
        style.map('Outlined.TButton',
                 background=[('active', self.win11_colors['hover'])],
                 bordercolor=[('active', self.win11_colors['primary'])])

        # Style the regex options box with Windows 11 styling
        style.configure('Regex.TLabelframe',
                       background=self.win11_colors['surface'],
                       borderwidth=1,
                       relief='groove',
                       bordercolor=self.win11_colors['border'])
        style.configure('Regex.TLabelframe.Label',
                       foreground=self.win11_colors['primary'],
                       background=self.win11_colors['surface'],
                       font=font_section)

        # ===== RIGHT FRAME CONTENT =====

        # Numeric filter enable checkbox - OUTSIDE the box (above the blue text)
        numeric_enable_frame = ttk.Frame(right_frame)
        _grid(numeric_enable_frame, row=0, column=0, columnspan=2, sticky=tk.W, pady=(0, pad_cell_y))

        numeric_checkbox = ttk.Checkbutton(
            numeric_enable_frame,
            text="Numerische Filter aktivieren",
            variable=self.numeric_filter_enabled,
            command=self.toggle_numeric_mode
        )
        numeric_checkbox.pack(side=tk.LEFT, padx=int(5 * self.scale_factor))

        # NEW: Numeric Filter Options Box - AT TOP OF SECOND COLUMN (below checkbox)
        self.numeric_options_frame = ttk.LabelFrame(
            right_frame,
            text="Numerische Filter",
            padding="10",
            style='Numeric.TLabelframe'
        )
        self.numeric_options_frame.grid(row=1, column=0, columnspan=2, pady=(0, 10), sticky=tk.W+tk.E)

        self.numeric_options_frame.columnconfigure(0, weight=0)
        self.numeric_options_frame.columnconfigure(1, weight=1)

        # Numeric column selection (inside the box)
        numeric_column_label = ttk.Label(self.numeric_options_frame, text="Spalte:")
        numeric_column_label.grid(row=1, column=0, sticky=tk.W, pady=5)

        self.numeric_column_combobox = ttk.Combobox(
            self.numeric_options_frame,
            textvariable=self.numeric_column_var,
            state="readonly",
            width=28
        )
        self.numeric_column_combobox.grid(row=1, column=1, padx=5, pady=5, sticky=tk.W+tk.E)

        # Numeric operator selection
        numeric_operator_label = ttk.Label(self.numeric_options_frame, text="Vergleich:")
        numeric_operator_label.grid(row=2, column=0, sticky=tk.W, pady=5)

        numeric_operator_combobox = ttk.Combobox(
            self.numeric_options_frame,
            textvariable=self.numeric_operator_var,
            values=["> (größer als)", "< (kleiner als)", ">= (größer/gleich)", "<= (kleiner/gleich)", "= (gleich)"],
            state="readonly",
            width=28
        )
        numeric_operator_combobox.grid(row=2, column=1, padx=5, pady=5, sticky=tk.W+tk.E)

        # Numeric value input
        numeric_value_label = ttk.Label(self.numeric_options_frame, text="Wert:")
        numeric_value_label.grid(row=3, column=0, sticky=tk.W, pady=5)

        numeric_value_entry = ttk.Entry(
            self.numeric_options_frame,
            textvariable=self.numeric_value_var,
            width=28
        )
        numeric_value_entry.grid(row=3, column=1, padx=5, pady=5, sticky=tk.W+tk.E)

        # Numeric filter description
        numeric_description_label = ttk.Label(
            self.numeric_options_frame,
            textvariable=self.numeric_filter_description_var,
            foreground=self.win11_colors.get('primary', 'blue'),
            font=font_hint
        )
        numeric_description_label.grid(row=4, column=0, columnspan=2, sticky=tk.W, pady=5)

        # Bind numeric value changes to update description
        self.numeric_value_var.trace_add("write", lambda *args: self.update_numeric_description())
        self.numeric_operator_var.trace_add("write", lambda *args: self.update_numeric_description())
        self.numeric_column_var.trace_add("write", lambda *args: self.update_numeric_description())

        # Style the numeric options box
        style.configure('Numeric.TLabelframe',
                       background=self.win11_colors['surface'],
                       borderwidth=1,
                       relief='groove',
                       bordercolor=self.win11_colors['border'])
        style.configure('Numeric.TLabelframe.Label',
                       foreground=self.win11_colors['primary'],
                       background=self.win11_colors['surface'],
                       font=font_section)

        # Style the columns selection box
        style.configure('Columns.TLabelframe',
                       background=self.win11_colors['surface'],
                       borderwidth=1,
                       relief='groove',
                       bordercolor=self.win11_colors['border'])
        style.configure('Columns.TLabelframe.Label',
                       foreground=self.win11_colors['primary'],
                       background=self.win11_colors['surface'],
                       font=font_section)

        # Initially disable numeric options
        self.toggle_numeric_mode()

        # Regex builder info
        regex_builder_info = ttk.Label(
            left_frame,
            text="Eigene Muster zur Filterung können um Regex-Builder erstellt werden.",
            foreground=self.win11_colors['primary'],
            font=font_hint
        )
        _grid(regex_builder_info, row=6, column=0, columnspan=3, sticky=tk.W, pady=(pad_section_y, 0))

        # Column selection enable checkbox - OUTSIDE the box (above the blue text)
        column_enable_frame = ttk.Frame(right_frame)
        _grid(column_enable_frame, row=2, column=0, columnspan=2, sticky=tk.W, pady=(0, pad_cell_y))

        column_checkbox = ttk.Checkbutton(
            column_enable_frame,
            text="Spaltenauswahl aktivieren",
            variable=self.column_selection_enabled,
            command=self.toggle_column_selection_mode
        )
        column_checkbox.pack(side=tk.LEFT, padx=int(5 * self.scale_factor))

        # Columns selection frame with consistent styling
        self.columns_frame = ttk.LabelFrame(right_frame, text="Spaltenauswahl", padding="8", style='Columns.TLabelframe')
        self.columns_frame.grid(row=3, column=0, columnspan=2, pady=(0, pad_section_y), sticky=tk.W+tk.E)


        # Column selection buttons
        select_button_frame = ttk.Frame(self.columns_frame)
        select_button_frame.grid(row=1, column=0, columnspan=2, sticky=tk.W+tk.E, pady=(0, 5))

        select_all_button = ttk.Button(
            select_button_frame,
            text="Alle auswählen",
            command=self.select_all_columns
        )
        select_all_button.pack(side=tk.LEFT, padx=(0, 6))

        deselect_all_button = ttk.Button(
            select_button_frame,
            text="Alle abwählen",
            command=self.deselect_all_columns
        )
        deselect_all_button.pack(side=tk.LEFT)

        # Columns container
        self.columns_container = ttk.Frame(self.columns_frame)
        self.columns_container.grid(row=2, column=0, columnspan=2, sticky=tk.W+tk.E)
        self.columns_container.columnconfigure(0, weight=1)
        self.columns_container.columnconfigure(1, weight=1)
        self.columns_container.columnconfigure(2, weight=1)

        # Initially disable column selection
        self.toggle_column_selection_mode()
        
        # Process button
        button_frame = ttk.Frame(right_frame)
        button_frame.grid(row=4, column=0, columnspan=2, pady=(pad_section_y, 0), sticky=tk.EW)
        
        process_button = ttk.Button(
            button_frame,
            text="Weiter zur Ausführung",
            command=self.navigate_to_execution_tab
        )
        process_button.pack(side=tk.RIGHT, ipadx=18, ipady=10)
        
        # Style the process button
        process_button.configure(style='Accent.TButton')
        style.configure('Accent.TButton', 
                       font=(base_family, max(int(10 * self.scale_factor), min_font_size), 'bold'),
                       padding=int(10 * self.scale_factor),
                       borderwidth=1)
        style.map('Accent.TButton',
                 foreground=[('active', 'white'), ('disabled', 'gray')],
                 background=[('active', self.win11_colors['primary']), ('disabled', self.win11_colors['background'])],
                 lightcolor=[('active', self.win11_colors['primary_light'])],
                 darkcolor=[('active', self.win11_colors['primary_dark'])])

        # Variable tracing for validation
        self.input_file_var.trace_add("write", lambda *args: self.validate_process_button())
        self.output_file_var.trace_add("write", lambda *args: self.validate_process_button())
        self.pattern_var.trace_add("write", lambda *args: self.validate_process_button())
        self.regex_enabled_var.trace_add("write", lambda *args: self.validate_process_button())

        # Initial validation
        self.validate_process_button()
    
    def browse_input_file(self):
        """Browse for input file"""
        file_path = filedialog.askopenfilename(
            title="Eingabedatei auswählen",
            filetypes=[("Excel Dateien", "*.xlsx"), ("Alle Dateien", "*.*")]
        )
        if file_path:
            self.input_file_var.set(file_path)
            self.log_message(f"Eingabedatei ausgewählt: {file_path}")
            # Update sheet and column selection when input file is chosen
            self.update_sheet_selection()
            self.update_columns_selection()
    
    def browse_output_file(self):
        """Browse for output file"""
        file_path = filedialog.asksaveasfilename(
            title="Ausgabedatei speichern",
            defaultextension=".xlsx",
            filetypes=[("Excel Dateien", "*.xlsx"), ("Alle Dateien", "*.*")]
        )
        if file_path:
            self.output_file_var.set(file_path)
            self.log_message(f"Ausgabedatei ausgewählt: {file_path}")

    def browse_config_file(self):
        """Browse for config file location"""
        file_path = filedialog.asksaveasfilename(
            title="Konfigurationsdatei auswählen",
            defaultextension=".json",
            filetypes=[("JSON Dateien", "*.json"), ("Alle Dateien", "*.*")]
        )
        if file_path:
            self.config_file_var.set(file_path)
            self.log_message(f"Konfigurationsdatei ausgewählt: {file_path}")
    
    def on_pattern_preset_selected(self, event):
        """Handle pattern preset selection"""
        selected_pattern = event.widget.get()
        if selected_pattern in self.pattern_presets:
            self.pattern_var.set(self.pattern_presets[selected_pattern])
            self.pattern_description_var.set(self.pattern_descriptions.get(selected_pattern, ""))

    def toggle_regex_mode(self):
        """Toggle between regex enabled/disabled mode"""
        if self.regex_enabled_var.get():
            # Regex mode enabled - enable regex options box
            self.log_message("Modus: Regex-Filterung aktiviert")
            # Set a default pattern if empty
            if not self.pattern_var.get():
                self.pattern_var.set("error|warning|critical")

            # Enable all widgets in the regex options frame
            for child in self.regex_options_frame.winfo_children():
                if isinstance(child, (ttk.Entry, ttk.Combobox)):
                    child.config(state=tk.NORMAL)
                elif isinstance(child, ttk.Label):
                    child.config(foreground="black")

            # Restore the frame style
            style = ttk.Style()
            style.configure('Regex.TLabelframe', background=self.win11_colors['surface'])

        else:
            # Regex mode disabled - disable regex options box
            self.log_message("Modus: Nur Spalten filtern (kein Regex)")
            self.pattern_var.set("")  # Clear pattern when regex is disabled

            # Disable all widgets in the regex options frame
            for child in self.regex_options_frame.winfo_children():
                if isinstance(child, (ttk.Entry, ttk.Combobox)):
                    child.config(state=tk.DISABLED)
                elif isinstance(child, ttk.Label):
                    child.config(foreground="gray")

            # Change the frame style to show it's disabled
            style = ttk.Style()
            style.configure('Regex.TLabelframe', background=self.win11_colors['background'])

    def _bind_tooltip(self, widget, text):
        """Bind Windows-like tooltip behavior to a widget."""
        widget.bind("<Enter>", lambda e, t=text: self.show_tooltip(t))
        widget.bind("<Leave>", lambda e: self.hide_tooltip())

    def show_tooltip(self, text):
        """Show tooltip text."""
        # Delay slightly to avoid flicker when moving the mouse quickly.
        self._tooltip_text_var.set(text)
        if self._tooltip_after_id is not None:
            try:
                self.frame.after_cancel(self._tooltip_after_id)
            except Exception:
                pass
            self._tooltip_after_id = None

        self._tooltip_after_id = self.frame.after(350, self._show_tooltip_now)

    def _show_tooltip_now(self):
        text = self._tooltip_text_var.get()
        if not text:
            return

        # Create tooltip if it doesn't exist
        if not hasattr(self, 'tooltip_window'):
            self.tooltip_window = tk.Toplevel(self.frame)
            self.tooltip_window.overrideredirect(True)
            self.tooltip_window.attributes('-topmost', True)

            tooltip_frame = ttk.Frame(self.tooltip_window, padding=6)
            tooltip_frame.pack(fill=tk.BOTH, expand=True)

            tooltip_label = ttk.Label(
                tooltip_frame,
                textvariable=self._tooltip_text_var,
                background="#FFFFE1",  # classic tooltip yellow
                relief="solid",
                borderwidth=1
            )
            tooltip_label.pack()

        # Position tooltip near mouse
        try:
            x = self.frame.winfo_pointerx() + 12
            y = self.frame.winfo_pointery() + 16
            self.tooltip_window.geometry(f"+{x}+{y}")
            self.tooltip_window.deiconify()
        except Exception:
            pass

    def hide_tooltip(self):
        """Hide tooltip"""
        if self._tooltip_after_id is not None:
            try:
                self.frame.after_cancel(self._tooltip_after_id)
            except Exception:
                pass
            self._tooltip_after_id = None

        if hasattr(self, 'tooltip_window'):
            try:
                self.tooltip_window.withdraw()
            except Exception:
                self.tooltip_window.destroy()
                del self.tooltip_window
    
    def on_sheet_selected(self, event):
        """Handle sheet selection"""
        selected_sheet = event.widget.get()
        self.sheet_var.set(selected_sheet)
        self.update_columns_selection()

    def update_sheet_selection(self):
        """Update sheet selection from the Excel file"""
        input_file = self.input_file_var.get()
        if not input_file:
            messagebox.showerror("Fehler", "Bitte geben Sie eine Eingabedatei an")
            return
        
        try:
            # Import pandas for Excel file reading
            import pandas as pd
            
            # Read Excel file to get sheet names
            xls = pd.ExcelFile(input_file)
            sheets = xls.sheet_names
            
            # Update sheet combobox
            self.sheet_combobox['values'] = sheets
            if sheets:
                self.sheet_combobox.current(0)
                self.sheet_var.set(sheets[0])
            
            self.log_message(f"Arbeitsblattauswahl aktualisiert: {sheets}")
            
        except Exception as e:
            self.log_error(f"Fehler beim Aktualisieren der Arbeitsblattauswahl: {e}")
            messagebox.showerror("Fehler", f"Fehler beim Aktualisieren der Arbeitsblattauswahl: {e}")
    
    def update_columns_selection(self, selected_columns=None):
        """
        Update columns selection from the Excel file

        Args:
            selected_columns: List of column names that should be initially selected
        """
        input_file = self.input_file_var.get()
        if not input_file:
            messagebox.showerror("Fehler", "Bitte geben Sie eine Eingabedatei an")
            return

        try:
            # Import pandas for Excel file reading
            import pandas as pd

            # Get current sheet
            sheet_name = self.sheet_var.get()

            # Read Excel file to get columns
            if sheet_name:
                df = pd.read_excel(input_file, sheet_name=sheet_name)
            else:
                df = pd.read_excel(input_file)

            columns = df.columns.tolist()

            # Handle columns without names
            for i, column in enumerate(columns):
                if pd.isna(column) or column == "":
                    # Find first non-empty value in the column
                    for value in df.iloc[:, i]:
                        if pd.notna(value) and value != "":
                            columns[i] = str(value)[:10]  # Limit to 10 characters
                            break
                    else:
                        columns[i] = f"Spalte_{i+1}"  # If all values are empty

            # Clear existing columns
            for widget in self.columns_container.winfo_children():
                widget.destroy()

            # Update regex column combobox
            self.regex_column_combobox['values'] = ["Alle Spalten"] + columns
            self.regex_column_combobox.current(0)

            # Create new column checkboxes
            self.columns_vars = {}
            for i, column in enumerate(columns):
                var = tk.IntVar()
                # If selected_columns is provided and column is in it, select the checkbox
                if selected_columns and column in selected_columns:
                    var.set(1)
                self.columns_vars[column] = var
                # Add command to trigger callback when checkbox state changes
                checkbox = ttk.Checkbutton(
                    self.columns_container,
                    text=column,
                    variable=var,
                    command=self._column_selection_changed
                )
                checkbox.grid(row=i // 3, column=i % 3, sticky=tk.W, padx=5, pady=2)

            self.log_message(f"Spaltenauswahl aktualisiert: {columns}")

            # Notify listeners that columns have changed
            if self.on_columns_changed:
                self.on_columns_changed()

        except Exception as e:
            self.log_error(f"Fehler beim Aktualisieren der Spaltenauswahl: {e}")
            messagebox.showerror("Fehler", f"Fehler beim Aktualisieren der Spaltenauswahl: {e}")
    
    def select_all_columns(self):
        """Select all columns"""
        if self.columns_vars:
            for var in self.columns_vars.values():
                var.set(1)
            self.log_message("Alle Spalten ausgewählt")
            if self.on_columns_changed:
                self.on_columns_changed()
        else:
            self.log_message("Keine Spalten verfügbar zum Auswählen")
    
    def deselect_all_columns(self):
        """Deselect all columns"""
        if self.columns_vars:
            for var in self.columns_vars.values():
                var.set(0)
            self.log_message("Alle Spalten abgewählt")
            if self.on_columns_changed:
                self.on_columns_changed()
        else:
            self.log_message("Keine Spalten verfügbar zum Abwählen")

    def toggle_column_selection_mode(self):
        """Toggle between column selection enabled/disabled"""
        if self.column_selection_enabled.get():
            # Column selection enabled - enable column selection UI
            self.log_message("Spaltenauswahl aktiviert")

            # Enable all widgets in the columns frame
            for child in self.columns_frame.winfo_children():
                if isinstance(child, (ttk.Button, ttk.Checkbutton)):
                    child.config(state=tk.NORMAL)
                elif isinstance(child, ttk.Label):
                    child.config(foreground="black")

            # Restore the frame style
            style = ttk.Style()
            style.configure('Columns.TLabelframe', background=self.win11_colors['surface'])

        else:
            # Column selection disabled - select all columns automatically
            self.log_message("Spaltenauswahl deaktiviert - alle Spalten werden ausgewählt")

            # Select all columns
            if self.columns_vars:
                for var in self.columns_vars.values():
                    var.set(1)

            # Disable all widgets in the columns frame (except we want to show them as selected)
            for child in self.columns_frame.winfo_children():
                if isinstance(child, ttk.Button):
                    child.config(state=tk.DISABLED)
                elif isinstance(child, ttk.Checkbutton):
                    child.config(state=tk.DISABLED)
                elif isinstance(child, ttk.Label):
                    child.config(foreground="gray")

            # Change the frame style to show it's disabled
            style = ttk.Style()
            style.configure('Columns.TLabelframe', background=self.win11_colors['background'])

    def get_selected_columns(self):
        """
        Gibt die ausgewählten Spalten zurück
        Wenn Spaltenauswahl deaktiviert ist, werden alle Spalten zurückgegeben
        """
        # If column selection is disabled, return all columns
        if not self.column_selection_enabled.get():
            return list(self.columns_vars.keys()) if self.columns_vars else None

        # Otherwise, return only selected columns
        selected_columns = []
        for column, var in self.columns_vars.items():
            if var.get():
                selected_columns.append(column)
        return selected_columns if selected_columns else None
    
    def validate_process_button(self):
        """Validate process button state"""
        # Validation logic
        has_input = bool(self.input_file_var.get())
        has_output = bool(self.output_file_var.get())
        
        # In regex mode, pattern is required; in non-regex mode, pattern is not required
        regex_enabled = self.regex_enabled_var.get()
        has_pattern = bool(self.pattern_var.get()) if regex_enabled else True
        
        # Enable button if:
        # - Input and output files are specified
        # - Either: regex mode with pattern OR no regex mode
        should_enable = has_input and has_output and has_pattern
        
        # Get the process button (it's in the right frame)
        for child in self.frame.winfo_children():
            if isinstance(child, ttk.Frame):
                for subchild in child.winfo_children():
                    if isinstance(subchild, ttk.Frame) and subchild.grid_info()["column"] == 1:
                        for button in subchild.winfo_children():
                            if isinstance(button, ttk.Frame):
                                for btn in button.winfo_children():
                                    if isinstance(btn, ttk.Button) and "VERARBEITEN" in btn.cget("text"):
                                        if should_enable:
                                            btn.config(state=tk.NORMAL)
                                        else:
                                            btn.config(state=tk.DISABLED)
    
    def process_file(self):
        """
        Verarbeitet die Excel-Datei
        """
        input_file = self.input_file_var.get()
        output_file = self.output_file_var.get()
        pattern = self.pattern_var.get()
        sheet_name = self.sheet_var.get()
        regex_column = self.regex_column_var.get()
        
        # Validierung
        if not input_file or not output_file:
            self.status_var.set('Bitte Eingabe- und Ausgabedatei angeben')
            self.log_message('Fehler: Eingabe- und/oder Ausgabedatei fehlt')
            self.log_error('Fehler: Eingabe- und/oder Ausgabedatei fehlt')
            messagebox.showerror("Fehler", "Bitte Eingabe- und Ausgabedatei angeben")
            return
        
        # Check if regex is enabled or if pattern is provided
        regex_enabled = self.regex_enabled_var.get() and pattern.strip()

        if not regex_enabled:
            self.log_message('Kein Regex-Muster verwendet - es werden nur die ausgewählten Spalten kopiert')

        # Warn if no columns are selected and no regex is provided
        columns = self.get_selected_columns()
        if not regex_enabled and not columns:
            self.status_var.set('Warnung: Kein Regex-Muster und keine Spalten ausgewählt')
            self.log_message('Warnung: Kein Regex-Muster und keine Spalten ausgewählt - alle Daten werden kopiert')
            if not messagebox.askyesno("Warnung", "Kein Regex-Muster und keine Spalten ausgewählt. Möchten Sie alle Daten kopieren?"):
                return

        columns = self.get_selected_columns()

        try:
            self.status_var.set('Verarbeitung läuft...')
            self.log_message('Verarbeitung gestartet...')

            # Import ExcelFilter using relative import (same as main GUI)
            from ..filter import ExcelFilter
            import pandas as pd

            # Handle the case where regex is not enabled
            if not regex_enabled:
                # Just copy the selected columns (or all columns if none selected)
                try:
                    # Read the Excel file
                    if sheet_name:
                        df = pd.read_excel(input_file, sheet_name=sheet_name)
                    else:
                        df = pd.read_excel(input_file)
                    
                    # Select columns if specified
                    if columns:
                        # Only keep the selected columns
                        available_columns = [col for col in columns if col in df.columns]
                        df = df[available_columns]
                        self.log_message(f'Kopiere ausgewählte Spalten: {available_columns}')
                    else:
                        # Keep all columns
                        self.log_message('Kopiere alle Spalten')
                    
                    # Write to output file
                    df.to_excel(output_file, index=False)
                    self.log_message(f'Erfolgreich geschrieben: {output_file}')
                    
                    # Ask if the output file should be opened
                    if messagebox.askyesno("Erfolg", "Möchten Sie die Ausgabedatei öffnen?"):
                        self.open_file(output_file)
                    
                    self.status_var.set('Verarbeitung erfolgreich!')
                    self.log_message('Verarbeitung erfolgreich abgeschlossen')
                    return
                    
                except Exception as e:
                    self.status_var.set(f'Fehler: {e}')
                    self.log_message(f'Fehler: {e}')
                    self.log_error(f'Fehler: {e}')
                    messagebox.showerror("Fehler", f'Fehler: {e}')
                    return
            
            # Create ExcelFilter instance for regex filtering
            if regex_column == "Alle Spalten":
                excel_filter = ExcelFilter(
                    input_file=input_file,
                    output_file=output_file,
                    pattern=pattern,
                    sheet_name=sheet_name if sheet_name else None,
                    columns=columns if columns else None
                )
            else:
                excel_filter = ExcelFilter(
                    input_file=input_file,
                    output_file=output_file,
                    pattern=pattern,
                    sheet_name=sheet_name if sheet_name else None,
                    columns=[regex_column] if regex_column else None
                )
            
            # Process the file with regex filtering
            success = excel_filter.process()
            
            if success:
                self.status_var.set('Verarbeitung erfolgreich!')
                self.log_message('Verarbeitung erfolgreich abgeschlossen')
                messagebox.showinfo("Erfolg", "Verarbeitung erfolgreich abgeschlossen!")
                
                # Ask if the output file should be opened
                if messagebox.askyesno("Erfolg", "Möchten Sie die Ausgabedatei öffnen?"):
                    self.open_file(output_file)
            else:
                self.status_var.set('Verarbeitung fehlgeschlagen')
                self.log_message('Verarbeitung fehlgeschlagen')
                self.log_error('Verarbeitung fehlgeschlagen')
                messagebox.showerror("Fehler", "Verarbeitung fehlgeschlagen")
                
        except Exception as e:
            self.status_var.set(f'Fehler: {e}')
            self.log_message(f'Fehler: {e}')
            self.log_error(f'Fehler: {e}')
            messagebox.showerror("Fehler", f'Fehler: {e}')

    def open_file(self, file_path):
        """
        Öffnet eine Datei mit dem Standardprogramm
        """
        try:
            if sys.platform == 'win32':
                os.startfile(file_path)
            elif sys.platform == 'darwin':
                subprocess.run(['open', file_path])
            else:
                subprocess.run(['xdg-open', file_path])
        except Exception as e:
            self.log_message(f'Konnte Datei nicht öffnen: {e}')
            messagebox.showerror("Fehler", f'Konnte Datei nicht öffnen: {e}')
    
    def save_config(self):
        """Save current configuration - prompts user for save location"""
        try:
            import json
            import os

            config = {
                'input_file': self.input_file_var.get(),
                'output_file': self.output_file_var.get(),
                'pattern': self.pattern_var.get(),
                'sheet_name': self.sheet_var.get(),
                'columns': [col for col, var in self.columns_vars.items() if var.get()]
            }

            # Prompt user to choose save location
            config_file = filedialog.asksaveasfilename(
                title="Konfiguration speichern",
                defaultextension=".json",
                filetypes=[("JSON Dateien", "*.json"), ("Alle Dateien", "*.*")],
                initialfile="config.json"
            )

            if not config_file:  # User cancelled
                return

            with open(config_file, 'w') as f:
                json.dump(config, f, indent=2)

            self.status_var.set('Konfiguration gespeichert')
            self.log_message(f'Konfiguration gespeichert: {config_file}')

        except Exception as e:
            self.status_var.set(f'Fehler beim Speichern: {e}')
            self.log_message(f'Fehler beim Speichern: {e}')
            self.log_error(f'Fehler beim Speichern: {e}')
    
    def load_config(self):
        """Load configuration - prompts user for file to load"""
        try:
            import json
            import os

            # Prompt user to choose file to load
            config_file = filedialog.askopenfilename(
                title="Konfiguration laden",
                filetypes=[("JSON Dateien", "*.json"), ("Alle Dateien", "*.*")],
                initialfile="config.json"
            )

            if not config_file:  # User cancelled
                return

            if os.path.exists(config_file):
                with open(config_file, 'r') as f:
                    config = json.load(f)

                self.input_file_var.set(config.get('input_file', ''))
                self.output_file_var.set(config.get('output_file', ''))
                self.pattern_var.set(config.get('pattern', 'error|warning|critical'))
                self.sheet_var.set(config.get('sheet_name', 'Sheet1'))

                self.status_var.set('Konfiguration geladen')
                self.log_message(f'Konfiguration geladen: {config_file}')

                # Update sheet and column selection if input file is set
                if config.get('input_file', ''):
                    self.update_sheet_selection()
                    # Pass saved columns to update_columns_selection to restore selections
                    saved_columns = config.get('columns', [])
                    self.update_columns_selection(selected_columns=saved_columns)
            else:
                self.status_var.set('Konfigurationsdatei nicht gefunden')
                self.log_message(f'Konfigurationsdatei nicht gefunden: {config_file}')

        except Exception as e:
            self.status_var.set(f'Fehler beim Laden: {e}')
            self.log_message(f'Fehler beim Laden: {e}')
            self.log_error(f'Fehler beim Laden: {e}')
    
    def log_message(self, message):
        """Log a message to the log text widget"""
        if self.execution_tab and hasattr(self.execution_tab, 'log_message'):
            # Redirect to execution tab
            self.execution_tab.log_message(message)
        else:
            # Fallback to status bar if execution tab not available
            self.status_var.set(message)
    
    def log_error(self, message):
        """Log an error message to the log text widget"""
        if self.execution_tab and hasattr(self.execution_tab, 'log_message'):
            # Redirect to execution tab with error formatting
            self.execution_tab.log_message(f"FEHLER: {message}")
        else:
            # Fallback to status bar if execution tab not available
            self.status_var.set(f"FEHLER: {message}")
    
    def set_execution_tab(self, execution_tab):
        """
        Set the reference to the execution tab for logging
        
        Args:
            execution_tab: Reference to the execution tab component
        """
        self.execution_tab = execution_tab
    
    def set_main_gui(self, main_gui):
        """
        Set the reference to the main GUI for accessing management functions

        Args:
            main_gui: Reference to the main GUI instance
        """
        self.main_gui = main_gui
    
    def set_on_columns_changed(self, callback):
        """
        Set a callback to be called when column selection changes

        Args:
            callback: Function to call when columns change
        """
        self.on_columns_changed = callback

    def _column_selection_changed(self):
        """
        Handle column selection changes and notify listeners
        """
        if self.on_columns_changed:
            self.on_columns_changed()
        # Also update execution tab directly if available
        if hasattr(self, 'execution_tab') and self.execution_tab:
            self.execution_tab.update_command_display()
    
    def navigate_to_execution_tab(self):
        """
        Navigate to the execution tab
        """
        if hasattr(self, 'main_gui') and self.main_gui and hasattr(self.main_gui, 'main_window'):
            # Find the notebook and select the execution tab
            notebook = self.main_gui.main_window.notebook
            if notebook:
                # Find the execution tab index
                tabs = notebook.tabs()
                execution_tab_name = self.translations["tab_execution"] if self.translations else "Ausführung"
                for i, tab_id in enumerate(tabs):
                    tab_text = notebook.tab(i, 'text')
                    if tab_text == execution_tab_name:
                        notebook.select(i)
                        break
    
    def toggle_numeric_mode(self):
        """Toggle between numeric filter enabled/disabled"""
        if self.numeric_filter_enabled.get():
            # Enable numeric filter options
            self.log_message("Numerische Filter aktiviert")

            # Enable all widgets in the numeric options frame
            for child in self.numeric_options_frame.winfo_children():
                if isinstance(child, (ttk.Entry, ttk.Combobox)):
                    child.config(state=tk.NORMAL)
                elif isinstance(child, ttk.Label):
                    child.config(foreground="black")

            # Restore the frame style
            style = ttk.Style()
            style.configure('Numeric.TLabelframe', background=self.win11_colors['surface'])

            # Update the column combobox with available columns
            self.update_numeric_columns()

        else:
            # Disable numeric filter options
            self.log_message("Numerische Filter deaktiviert")

            # Disable all widgets in the numeric options frame
            for child in self.numeric_options_frame.winfo_children():
                if isinstance(child, (ttk.Entry, ttk.Combobox)):
                    child.config(state=tk.DISABLED)
                elif isinstance(child, ttk.Label):
                    child.config(foreground="gray")

            # Change the frame style to show it's disabled
            style = ttk.Style()
            style.configure('Numeric.TLabelframe', background=self.win11_colors['background'])

            # Clear numeric filter values
            self.numeric_column_var.set("")
            self.numeric_value_var.set("")
            self.numeric_filter_description_var.set("")

    def update_numeric_columns(self):
        """Update the numeric column combobox with available columns"""
        input_file = self.input_file_var.get()
        if not input_file:
            return

        try:
            import pandas as pd

            # Get current sheet
            sheet_name = self.sheet_var.get()

            # Read Excel file to get columns
            if sheet_name:
                df = pd.read_excel(input_file, sheet_name=sheet_name)
            else:
                df = pd.read_excel(input_file)

            columns = df.columns.tolist()

            # Handle columns without names
            for i, column in enumerate(columns):
                if pd.isna(column) or column == "":
                    # Find first non-empty value in the column
                    for value in df.iloc[:, i]:
                        if pd.notna(value) and value != "":
                            columns[i] = str(value)[:10]  # Limit to 10 characters
                            break
                    else:
                        columns[i] = f"Spalte_{i+1}"  # If all values are empty

            # Update numeric column combobox with "Alle Spalten" option
            self.numeric_column_combobox['values'] = ["Alle Spalten"] + columns
            self.numeric_column_combobox.current(0)  # Default to "Alle Spalten"
            self.numeric_column_var.set("Alle Spalten")

        except Exception as e:
            self.log_error(f"Fehler beim Aktualisieren der numerischen Spalten: {e}")

    def update_numeric_description(self):
        """Update the numeric filter description"""
        if not self.numeric_filter_enabled.get():
            self.numeric_filter_description_var.set("")
            return

        column = self.numeric_column_var.get()
        operator = self.numeric_operator_var.get()
        value = self.numeric_value_var.get()

        if not column or not operator or not value:
            self.numeric_filter_description_var.set("Konfiguration unvollständig")
            return

        # Extract operator symbol
        operator_map = {
            "> (größer als)": ">",
            "< (kleiner als)": "<",
            ">= (größer/gleich)": ">=",
            "<= (kleiner/gleich)": "<=",
            "= (gleich)": "="
        }

        operator_symbol = operator_map.get(operator, operator)

        try:
            # Validate numeric value
            float(value)
            description = f"Filter: {column} {operator_symbol} {value}"
            self.numeric_filter_description_var.set(description)
        except ValueError:
            self.numeric_filter_description_var.set("❌ Ungültiger numerischer Wert")

    def get_numeric_filter_settings(self):
        """
        Get the current numeric filter settings

        Returns:
            dict: Numeric filter configuration or None if disabled
        """
        if not self.numeric_filter_enabled.get():
            return None

        column = self.numeric_column_var.get()
        operator = self.numeric_operator_var.get()
        value = self.numeric_value_var.get()

        if not column or not operator or not value:
            return None

        # Convert display operator to symbol
        operator_map = {
            "> (größer als)": ">",
            "< (kleiner als)": "<",
            ">= (größer/gleich)": ">=",
            "<= (kleiner/gleich)": "<=",
            "= (gleich)": "="
        }

        operator_symbol = operator_map.get(operator, operator)

        try:
            # Validate and convert value
            numeric_value = float(value)
            return {
                'column': column,
                'operator': operator_symbol,
                'value': numeric_value
            }
        except ValueError:
            return None

    def manage_presets(self):
        """
        Open presets management dialog
        """
        # Get main GUI reference to access manage_presets method
        if hasattr(self, 'main_gui') and self.main_gui and hasattr(self.main_gui, 'manage_presets'):
            self.main_gui.manage_presets()

    def refresh_preset_combobox(self):
        """
        Refresh the preset combobox with current preset values
        """
        if hasattr(self, 'pattern_preset_combobox'):
            self.pattern_preset_combobox['values'] = list(self.pattern_presets.keys())

    def get_frame(self):
        """
        Get the frame for this tab

        Returns:
            The frame containing all widgets
        """
        return self.frame
