import streamlit as st
import pandas as pd
import re
from io import BytesIO
from typing import List, Dict, Any, Optional
import time

# Seitenkonfiguration
st.set_page_config(
    page_title="Excel Filter Tool",
    page_icon=None,
    layout="wide",
    initial_sidebar_state="expanded"
)

# --- Regex Bausteine ---
REGEX_BRICKS = {
    "Exakter Text": {
        "regex": "{}", 
        "desc": "Findet den exakten Text, den du eingibst. Sonderzeichen werden automatisch maskiert.", 
        "needs_input": True,
        "allows_quantifier": True
    },
    "Ziffer (0-9)": {
        "regex": r"\d", 
        "desc": "Findet eine einzelne Ziffer von 0 bis 9.", 
        "needs_input": False,
        "allows_quantifier": True
    },
    "Buchstabe (A-Z, a-z)": {
        "regex": r"[a-zA-Z]", 
        "desc": "Findet einen einzelnen Buchstaben des deutschen Alphabets, sowohl Groß- als auch Kleinschreibung. Achtung, gilt nicht für Umlaute!", 
        "needs_input": False,
        "allows_quantifier": True
    },
    "Leerzeichen": {
        "regex": r"\s", 
        "desc": "Findet Leerzeichen, Tabulatoren und Zeilenumbrüche.", 
        "needs_input": False,
        "allows_quantifier": True
    },
    "Beliebiges einzelnes Zeichen": {
        "regex": r".", 
        "desc": "Findet genau ein beliebiges Zeichen (Buchstabe, Ziffer, Symbol oder Leerzeichen).", 
        "needs_input": False,
        "allows_quantifier": True
    },
    "Beliebige Zeichenfolge": {
        "regex": r".*", 
        "desc": "Findet null oder mehr beliebige Zeichen. Nützlich als breiter Platzhalter.", 
        "needs_input": False,
        "allows_quantifier": False
    },
    "ODER (Alternative)": {
        "regex": r"|", 
        "desc": "Funktioniert als logischer ODER-Operator. Das Muster findet entweder den Ausdruck davor oder danach.", 
        "needs_input": False,
        "allows_quantifier": False
    },
    "Zeilenanfang": {
        "regex": r"^", 
        "desc": "Verankert den Treffer am Anfang einer Zeile oder Zeichenkette.", 
        "needs_input": False,
        "allows_quantifier": False
    },
    "Zeilenende": {
        "regex": r"$", 
        "desc": "Verankert den Treffer am Ende einer Zeile oder Zeichenkette.", 
        "needs_input": False,
        "allows_quantifier": False
    }
}

QUANTIFIERS = {
    "Genau 1 (Standard)": "",
    "1 oder mehr (+)": "+",
    "0 oder mehr (*)": "*",
    "Optional: 0 oder 1 (?)": "?"
}

def get_pattern_presets() -> Dict[str, str]:
    return {
        "Fehler & Warnungen": r"error|warning|critical|fehler|warnung",
        "Nur Fehler": r"error|fehler",
        "Nur Warnungen": r"warning|warnung",
        "Kritische Fehler": r"critical|kritisch",
        "E-Mail-Adressen": r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
        "Telefonnummern": r"\+?[0-9\s-]{10,}",
        "Datum (JJJJ-MM-TT)": r"\d{4}-\d{2}-\d{2}",
    }

def init_session_state():
    defaults = {
        "df": None,
        "sheets": [],
        "selected_sheet": None,
        "columns": [],
        "filtered_df": None,
        "stats": None,
        "regex_enabled": True,
        "numeric_enabled": False,
        "column_selection_enabled": False,
        "selected_columns": [],
        "regex_pattern": "",
        "regex_test_text": "",
        "regex_blocks": [],
        "temp_block_val": "",
        "temp_quantifier": "Genau 1 (Standard)"
    }
    for key, val in defaults.items():
        if key not in st.session_state:
            st.session_state[key] = val

def load_excel_file(uploaded_file) -> tuple:
    try:
        file_bytes = BytesIO(uploaded_file.getvalue())
        xls = pd.ExcelFile(file_bytes)
        sheets = xls.sheet_names
        file_bytes.seek(0)
        df = pd.read_excel(file_bytes, sheet_name=sheets[0])
        return df, sheets, None
    except Exception as e:
        return None, [], str(e)

def apply_filters(df: pd.DataFrame, pattern: Optional[str] = None, regex_column: Optional[str] = None, numeric_filter: Optional[Dict[str, Any]] = None, selected_columns: Optional[List[str]] = None) -> tuple:
    start_time = time.time()
    input_rows = len(df)
    input_columns = len(df.columns)
    filtered_df = df.copy()
    filters_applied = []
    
    if pattern and pattern.strip():
        try:
            columns_to_search = [regex_column] if regex_column and regex_column != "Alle Spalten" else df.columns.tolist()
            regex = re.compile(pattern, re.IGNORECASE)
            mask = filtered_df.apply(lambda row: any(regex.search(str(row[col])) for col in columns_to_search if col in row and pd.notna(row[col])), axis=1)
            filtered_df = filtered_df[mask]
            filters_applied.append("Regex")
        except re.error as e:
            return None, None, f"Ungültiges Regex-Muster: {e}"
            
    if numeric_filter and numeric_filter.get("column"):
        try:
            column = numeric_filter["column"]
            operator = numeric_filter["operator"]
            value = numeric_filter["value"]
            
            # Helper function to apply operator comparison safely
            def apply_operator(series, op, val):
                if op == ">":
                    return series > val
                elif op == "<":
                    return series < val
                elif op == ">=":
                    return series >= val
                elif op == "<=":
                    return series <= val
                elif op == "=":
                    return series == val
                else:
                    raise ValueError(f"Unbekannter Operator: {op}")
            
            if column == "Alle Spalten":
                combined_mask = pd.Series([False] * len(filtered_df), index=filtered_df.index)
                for col in filtered_df.columns:
                    num_series = pd.to_numeric(filtered_df[col], errors='coerce')
                    col_mask = apply_operator(num_series, operator, value)
                    combined_mask = combined_mask | col_mask
                filtered_df = filtered_df[combined_mask]
            else:
                num_series = pd.to_numeric(filtered_df[column], errors='coerce')
                filtered_df = filtered_df[apply_operator(num_series, operator, value)]
            filters_applied.append("Numerisch")
        except Exception as e:
            return None, None, f"Fehler beim Anwenden des numerischen Filters: {e}"
            
    if selected_columns:
        available_columns = [col for col in selected_columns if col in filtered_df.columns]
        if available_columns:
            filtered_df = filtered_df[available_columns]
            
    end_time = time.time()
    stats = {
        "input_rows": input_rows,
        "input_columns": input_columns,
        "output_rows": len(filtered_df),
        "output_columns": len(filtered_df.columns),
        "rows_removed": input_rows - len(filtered_df),
        "processing_time": end_time - start_time,
        "filters_applied": filters_applied,
        "retention_rate": (len(filtered_df) / input_rows * 100) if input_rows > 0 else 0
    }
    return filtered_df, stats, None

def explain_regex_german(blocks: List[Dict]) -> str:
    """Übersetzt die Regex-Bausteine in einen deutschen Satz."""
    if not blocks:
        return "Muster ist leer."
        
    explanations = []
    for block in blocks:
        b_type = block["key"]
        val = block.get("value", "")
        q_key = block.get("quantifier_key", "Genau 1 (Standard)")
        
        # 1. Grundbegriff
        if "Exakter Text" in b_type: noun = f"den exakten Text '{val}'"
        elif "Ziffer" in b_type: noun = "eine Ziffer (0-9)"
        elif "Buchstabe" in b_type: noun = "einen Buchstaben (A-Z oder a-z)"
        elif "Leerzeichen" in b_type: noun = "ein Leerzeichen"
        elif "Beliebiges einzelnes Zeichen" in b_type: noun = "ein beliebiges einzelnes Zeichen"
        elif "Beliebige Zeichenfolge" in b_type: noun = "eine beliebige Zeichenfolge"
        elif "ODER" in b_type: noun = "ODER"
        elif "Zeilenanfang" in b_type: noun = "den Anfang der Zeichenkette"
        elif "Zeilenende" in b_type: noun = "das Ende der Zeichenkette"
        else: noun = "ein Element"
        
        # 2. Quantoren anwenden
        if noun not in ["ODER", "den Anfang der Zeichenkette", "das Ende der Zeichenkette", "eine beliebige Zeichenfolge"]:
            if "1 oder mehr" in q_key:
                noun = f"eine oder mehr {noun.replace('eine ', '').replace('einen ', '').replace('ein ', '').replace('den ', '').replace('das ', '')}en" if any(noun.startswith(x) for x in ["eine ", "einen ", "ein ", "den ", "das "]) else f"ein oder mehr {noun}"
            elif "0 oder mehr" in q_key:
                noun = f"null oder mehr {noun.replace('eine ', '').replace('einen ', '').replace('ein ', '').replace('den ', '').replace('das ', '')}en" if any(noun.startswith(x) for x in ["eine ", "einen ", "ein ", "den ", "das "]) else f"null oder mehr {noun}"
            elif "Optional" in q_key:
                noun = f"ein optionales {noun.replace('eine ', '').replace('einen ', '').replace('ein ', '').replace('den ', '').replace('das ', '')}" if any(noun.startswith(x) for x in ["eine ", "einen ", "ein ", "den ", "das "]) else f"ein optionales {noun}"
        
        explanations.append(noun)
        
    # 3. Zusammenfügen
    sentence = ""
    for i, exp in enumerate(explanations):
        if i == 0:
            sentence += exp
        else:
            if exp == "ODER" or explanations[i-1] == "ODER":
                sentence += f" {exp} "
            else:
                sentence += f", gefolgt von {exp}"
                
    return sentence[:1].upper() + sentence[1:] + "."

def apply_sleek_dark_theme():
    st.markdown("""
    <style>
        h1, h2, h3 { font-weight: 500 !important; letter-spacing: -0.5px; }
        .stApp { background-color: #0F1115; color: #FAFAFA; }
        
        .stTextInput>div>div>input, 
        .stSelectbox>div>div>div, 
        .stNumberInput>div>div>input,
        .stTextArea>div>div>textarea {
            background-color: #1E2028 !important;
            border: 1px solid #2D3342 !important;
            color: #FAFAFA !important;
            border-radius: 6px !important;
            padding: 8px 12px !important;
        }
        
        .section-header {
            font-size: 1.4rem;
            font-weight: 600;
            color: #FFFFFF;
            margin-top: 2.5rem;
            margin-bottom: 1.5rem;
            padding-bottom: 0.5rem;
            border-bottom: 1px solid #2D3342;
        }
        
        .success-box {
            background-color: #1A3B2B;
            color: #4ADE80;
            padding: 1rem 1.25rem;
            border-radius: 6px;
            font-size: 0.95rem;
            margin-bottom: 1.5rem;
            border: 1px solid #224D38;
        }
        
        .info-box {
            background-color: #1a233a;
            color: #8fa1c4;
            padding: 0.75rem 1rem;
            border-radius: 6px;
            font-size: 0.9rem;
            margin-bottom: 1rem;
            border: 1px solid #2d3748;
        }
        
        .translation-box {
            background-color: #2D241E;
            color: #E29A5B;
            padding: 1rem;
            border-radius: 6px;
            font-size: 1rem;
            margin-bottom: 1.5rem;
            border: 1px solid #5C3D22;
            line-height: 1.5;
        }
        
        .block-brick {
            background-color: #1E2028;
            border: 1px solid #3B4252;
            border-left: 4px solid #F03E3E;
            color: #FAFAFA;
            padding: 0.75rem 1rem;
            border-radius: 4px;
            font-size: 0.95rem;
            margin-bottom: 0.5rem;
            display: flex;
            align-items: center;
        }
        
        [data-testid="stSidebar"] {
            background-color: #161A23 !important;
            border-right: 1px solid #2D3342;
        }
        hr { border-color: #2D3342 !important; }
        
        [data-testid="stMetric"] {
            background-color: transparent !important;
            border: none !important;
            padding: 0 !important;
        }
        [data-testid="stMetricValue"] { color: #FFFFFF !important; font-size: 1.8rem !important; }
        
        .stTabs [data-baseweb="tab-list"] { gap: 24px; background-color: transparent; }
        .stTabs [data-baseweb="tab"] { color: #A0AEC0; padding-top: 10px; padding-bottom: 10px; }
        .stTabs [aria-selected="true"] { color: #FFFFFF !important; }
    </style>
    """, unsafe_allow_html=True)

def render_pipeline_tab():
    st.markdown('<div class="section-header">Schritt 1: Datei auswählen</div>', unsafe_allow_html=True)
    uploaded_file = st.file_uploader("Lade eine Excel-Datei hoch (.xlsx, .xls)", type=["xlsx", "xls"], label_visibility="collapsed")
    
    if uploaded_file:
        if uploaded_file != st.session_state.get("last_uploaded"):
            st.session_state.last_uploaded = uploaded_file
            with st.spinner("Lade..."):
                df, sheets, error = load_excel_file(uploaded_file)
            if error:
                st.error(f"Fehler: {error}")
            else:
                st.session_state.df = df
                st.session_state.sheets = sheets
                st.session_state.selected_sheet = sheets[0]
                st.session_state.columns = df.columns.tolist()
                st.session_state.filtered_df = None
                st.session_state.stats = None
                st.session_state.selected_columns = list(df.columns)
                
        st.markdown(f'<div class="success-box">Datei geladen: {uploaded_file.name}</div>', unsafe_allow_html=True)
        col1, _ = st.columns([1, 2])
        with col1:
            current_idx = st.session_state.sheets.index(st.session_state.selected_sheet) if st.session_state.selected_sheet in st.session_state.sheets else 0
            selected_sheet = st.selectbox("Arbeitsblatt auswählen", st.session_state.sheets, index=current_idx)
            if selected_sheet != st.session_state.selected_sheet:
                st.session_state.selected_sheet = selected_sheet
                st.session_state.df = pd.read_excel(BytesIO(st.session_state.last_uploaded.getvalue()), sheet_name=selected_sheet)
                st.session_state.columns = st.session_state.df.columns.tolist()
                st.session_state.selected_columns = list(st.session_state.df.columns)
                st.rerun()

    if st.session_state.df is not None:
        st.markdown('<div class="section-header">Schritt 2: Filter konfigurieren</div>', unsafe_allow_html=True)
        filter_tabs = st.tabs(["Regex-Filter", "Numerischer Filter", "Spaltenauswahl"])
        
        with filter_tabs[0]:
            st.write("")
            st.session_state.regex_enabled = st.checkbox("Regex-Filter aktivieren", value=st.session_state.regex_enabled)
            if st.session_state.regex_enabled:
                col1, col2 = st.columns([2, 1])
                with col1:
                    presets = get_pattern_presets()
                    preset_names = ["-- Vorlagen --"] + list(presets.keys())
                    def on_preset_change():
                        sel = st.session_state.preset_selector
                        if sel != preset_names[0] and sel in presets:
                            st.session_state.regex_pattern = presets[sel]
                    st.selectbox("Vorlage laden", preset_names, key="preset_selector", on_change=on_preset_change)
                    st.session_state.regex_pattern = st.text_input("Aktives Regex-Muster (Nutze den 'Regex-Builder' zum visuellen Erstellen)", value=st.session_state.regex_pattern, placeholder="z.B. ^Fehler.*")
                with col2:
                    regex_column = st.selectbox("Spalte für Regex-Filter", ["Alle Spalten"] + st.session_state.columns)

        with filter_tabs[1]:
            st.write("")
            st.session_state.numeric_enabled = st.checkbox("Numerischen Filter aktivieren", value=st.session_state.numeric_enabled)
            if st.session_state.numeric_enabled:
                col1, col2, col3 = st.columns([2, 2, 1])
                with col1:
                    numeric_column = st.selectbox("Spalte", ["Alle Spalten"] + st.session_state.columns)
                with col2:
                    ops = {">": ">", "<": "<", ">=": ">=", "<=": "<=", "=": "="}
                    selected_op = st.selectbox("Vergleichsoperator", list(ops.values()))
                    numeric_operator = [k for k, v in ops.items() if v == selected_op][0]
                with col3:
                    numeric_value = st.text_input("Wert")

        with filter_tabs[2]:
            st.write("")
            st.session_state.column_selection_enabled = st.checkbox("Spaltenauswahl aktivieren", value=st.session_state.column_selection_enabled)
            if st.session_state.column_selection_enabled:
                col_btn1, col_btn2, _ = st.columns([1, 1, 3])
                with col_btn1:
                    if st.button("Alle auswählen", use_container_width=True):
                        st.session_state.selected_columns = list(st.session_state.columns)
                        st.rerun()
                with col_btn2:
                    if st.button("Alle abwählen", use_container_width=True):
                        st.session_state.selected_columns = []
                        st.rerun()
                st.session_state.selected_columns = st.multiselect("Spalten auswählen", st.session_state.columns, default=st.session_state.get("selected_columns", st.session_state.columns))

        st.markdown('<div class="section-header">Schritt 3: Ergebnisse & Export</div>', unsafe_allow_html=True)
        if st.button("Filter anwenden", type="primary"):
            val_error = None
            if st.session_state.regex_enabled and not st.session_state.regex_pattern: val_error = "Bitte gib ein Regex-Muster ein"
            if st.session_state.numeric_enabled and not numeric_value: val_error = "Bitte gib einen numerischen Wert ein"
            
            if val_error:
                st.error(val_error)
            else:
                num_dict = {"column": numeric_column, "operator": numeric_operator, "value": float(numeric_value)} if (st.session_state.numeric_enabled and numeric_value) else None
                cols = st.session_state.selected_columns if st.session_state.column_selection_enabled else None
                with st.spinner("Verarbeite..."):
                    filtered_df, stats, err = apply_filters(st.session_state.df, pattern=st.session_state.regex_pattern if st.session_state.regex_enabled else None, regex_column=regex_column if st.session_state.regex_enabled else None, numeric_filter=num_dict, selected_columns=cols)
                if err:
                    st.error(f"Fehler: {err}")
                else:
                    st.session_state.filtered_df = filtered_df
                    st.session_state.stats = stats
                    st.success("Filter erfolgreich angewendet.")

        if st.session_state.filtered_df is not None and st.session_state.stats is not None:
            st.divider()
            sc1, sc2, sc3, sc4 = st.columns(4)
            sc1.metric("Eingabezeilen", f"{st.session_state.stats['input_rows']:,}")
            sc2.metric("Ausgabezeilen", f"{st.session_state.stats['output_rows']:,}")
            sc3.metric("Entfernte Zeilen", f"{st.session_state.stats['rows_removed']:,}")
            sc4.metric("Trefferquote", f"{st.session_state.stats['retention_rate']:.1f}%")
            
            st.write("")
            st.dataframe(st.session_state.filtered_df.head(100), use_container_width=True, height=300)
            st.caption(f"Zeige {min(100, len(st.session_state.filtered_df))} von {len(st.session_state.filtered_df)} Zeilen")
            
            out_buf = BytesIO()
            with pd.ExcelWriter(out_buf, engine='openpyxl') as writer:
                st.session_state.filtered_df.to_excel(writer, index=False)
            out_buf.seek(0)
            st.download_button("Gefilterte Datei herunterladen", out_buf, "gefilterte_ausgabe.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", type="primary")

def render_regex_builder_tab():
    st.markdown('<div class="section-header">Visueller Regex-Builder</div>', unsafe_allow_html=True)
    st.markdown("Erstelle Suchmuster durch Kombinieren von modularen Bausteinen. Das Muster wird von oben nach unten aufgebaut.")
    st.write("")
    
    col_build, col_test = st.columns([1.2, 1])
    
    with col_build:
        st.markdown("### 1. Bausteine hinzufügen")
        
        selected_block_key = st.selectbox("Wähle einen Bausteintyp:", list(REGEX_BRICKS.keys()))
        block_data = REGEX_BRICKS[selected_block_key]
        
        st.markdown(f'<div class="info-box"><b>Beschreibung:</b> {block_data["desc"]}</div>', unsafe_allow_html=True)
        
        col1, col2 = st.columns(2)
        with col1:
            if block_data["needs_input"]:
                st.text_input("Text zum Suchen:", placeholder="z.B. Fehler", key="temp_block_val")
            else:
                st.session_state.temp_block_val = ""
        with col2:
            if block_data["allows_quantifier"]:
                st.selectbox("Wie oft:", list(QUANTIFIERS.keys()), key="temp_quantifier")
            else:
                st.session_state.temp_quantifier = "Genau 1 (Standard)"

        def add_block_callback():
            st.session_state.regex_blocks.append({
                "key": selected_block_key, 
                "value": st.session_state.temp_block_val if block_data["needs_input"] else "",
                "regex_format": block_data["regex"],
                "quantifier_key": st.session_state.temp_quantifier if block_data["allows_quantifier"] else "Genau 1 (Standard)"
            })
            st.session_state.temp_block_val = ""
            st.session_state.temp_quantifier = "Genau 1 (Standard)"

        st.button("Baustein hinzufügen", use_container_width=True, on_click=add_block_callback)
        
        st.write("---")
        st.markdown("### 2. Bausteine als Reihe")
        if not st.session_state.regex_blocks:
            st.info("Die Bausteinreihe ist leer. Wähle oben einen Baustein und klicke auf Hinzufügen.")
        else:
            for i, block in enumerate(st.session_state.regex_blocks):
                c1, c2 = st.columns([5, 1])
                with c1:
                    val_display = f" <code style='color:#F03E3E; background:transparent;'>{block['value']}</code>" if block['value'] else ""
                    q_key = block.get('quantifier_key', 'Genau 1 (Standard)')
                    q_display = f" &nbsp; <span style='color:#8fa1c4; font-size: 0.8em;'>[ <i>{q_key}</i> ]</span>" if q_key != "Genau 1 (Standard)" else ""
                    
                    st.markdown(f'<div class="block-brick">{block["key"]}{val_display}{q_display}</div>', unsafe_allow_html=True)
                with c2:
                    if st.button("Entfernen", key=f"del_block_{i}", help="Diesen Baustein entfernen"):
                        st.session_state.regex_blocks.pop(i)
                        st.rerun()

        # Kompiliere die visuellen Bausteine zu echtem Regex-Code
        regex_parts = []
        for block in st.session_state.regex_blocks:
            q_val = QUANTIFIERS[block.get("quantifier_key", "Genau 1 (Standard)")]
            if block["value"]:
                safe_val = re.escape(block["value"])
                if q_val:
                    regex_parts.append(f"(?:{safe_val}){q_val}")
                else:
                    regex_parts.append(safe_val)
            else:
                regex_parts.append(f"{block['regex_format']}{q_val}")
                
        generated_regex = "".join(regex_parts)

    with col_test:
        st.markdown("### 3. Muster testen")
        
        st.markdown("**Muster-Erklärung:**")
        german_translation = explain_regex_german(st.session_state.regex_blocks)
        st.markdown(f'<div class="translation-box">"{german_translation}"</div>', unsafe_allow_html=True)
        
        st.markdown("**Generiertes Regex:**")
        st.code(generated_regex if generated_regex else "(leer)", language="regex")
        
        test_text = st.text_input("Testtext", value=st.session_state.regex_test_text, placeholder="Gib einen Beispieltext ein...")
        st.session_state.regex_test_text = test_text
        
        test_btn = st.button("Muster testen", use_container_width=True)
        
        if (test_btn or test_text) and generated_regex and test_text:
            try:
                regex = re.compile(generated_regex, re.IGNORECASE)
                matches = regex.findall(test_text)
                
                if matches:
                    st.success(f"{len(matches)} Treffer gefunden.")
                    highlighted = test_text
                    for match in set(matches):
                        if match: 
                            highlighted = highlighted.replace(match, f"**{match}**")
                    st.markdown(f"> {highlighted}")
                else:
                    st.warning("Keine Treffer gefunden. Passe dein Muster oder den Testtext an.")
            except re.error:
                st.error("Ungültige Mustersyntax. Vervollständige die Musterfolge.")
                
        st.write("")
        if st.button("Auf Excel-Pipeline anwenden", type="primary", use_container_width=True):
            if generated_regex:
                st.session_state.regex_pattern = generated_regex
                st.success("Muster angewendet. Wechsle zum Tab 'Excel-Filter' um deine Daten zu filtern.")
            else:
                st.error("Kann kein leeres Muster anwenden.")

def render_help_tab():
    st.markdown('<div class="section-header">Hilfe</div>', unsafe_allow_html=True)
    
    st.markdown("""
    
    ### Tab: Excel-Pipeline
    
    **Schritt 1: Datei auswählen**
    - Lade Excel-Dateien im Format `.xlsx` oder `.xls` hoch
    - Wähle das zu verarbeitende Arbeitsblatt, falls die Datei mehrere enthält
    
    **Schritt 2: Filter konfigurieren**
    
    *Regex-Filter:*
    - Gib ein reguläres Ausdrucksmuster manuell ein oder nutze den visuellen Regex-Builder
    - Wähle eine bestimmte Spalte oder durchsuche alle Spalten
    - Mustersuche ist standardmäßig Groß-/Kleinschreibung unabhängig
    
    *Numerischer Filter:*
    - Filtere Zeilen basierend auf numerischen Vergleichen (>, <, >=, <=, =)
    - Wende auf eine bestimmte Spalte oder alle (numerischen) Spalten an
    
    *Spaltenauswahl:*
    - Wähle, welche Spalten in der Ausgabe enthalten sein sollen
    - Nutze "Alle auswählen" / "Alle abwählen" für schnelle Auswahl
    
    **Schritt 3: Ergebnisse & Export**
    - Überprüfe die Filterstatistiken (beibehaltene Zeilen, entfernte Zeilen, Trefferquote)
    - Zeige die gefilterten Daten an (erste 100 Zeilen)
    - Lade den gefilterten Datensatz als neue Excel-Datei herunter
    
    ---
    
    ### Tab: Visueller Regex-Builder
    
    Erstelle reguläre Ausdrücke visuell durch Kombinieren modularer Bausteine:
    
    **Verfügbare Bausteine:**
    
    | Baustein | Beschreibung | Regex-Äquivalent |
    |----------|--------------|------------------|
    | Exakter Text | Findet wörtlichen Text | `text` |
    | Ziffer (0-9) | Findet eine einzelne Ziffer | `\d` |
    | Buchstabe (A-Z, a-z) | Findet einen Buchstaben | `[a-zA-Z]` |
    | Leerzeichen | Findet Leerzeichen, Tabs, Zeilenumbrüche | `\s` |
    | Beliebiges einzelnes Zeichen | Platzhalter für ein Zeichen | `.` |
    | Beliebige Zeichenfolge | Platzhalter für beliebigen Inhalt | `.*` |
    | ODER (Alternative) | Findet entweder Ausdruck davor oder danach | `\|` |
    | Zeilenanfang | Verankert am Anfang | `^` |
    | Zeilenende | Verankert am Ende | `$` |
    
    **Quantifizierer:**
    - **Genau 1:** Findet das Element einmal (Standard)
    - **1 oder mehr (+):** Findet ein oder mehr Vorkommen
    - **0 oder mehr (*):** Findet null oder mehr Vorkommen
    - **Optional (?):** Findet null oder ein Vorkommen
    
    **Beispiel: Fehlercodes finden**
    
    Um Zeilen zu finden, die mit "Fehler" beginnen, gefolgt von einem Leerzeichen und Ziffern (z.B. "Fehler 404"):
    
    1. Füge "Zeilenanfang" hinzu - verankert am Zeilenanfang
    2. Füge "Exakter Text" mit Wert "Fehler" hinzu
    3. Füge "Leerzeichen" mit Quantifizierer "1 oder mehr (+)" hinzu
    4. Füge "Ziffer (0-9)" mit Quantifizierer "1 oder mehr (+)" hinzu
    
    Generiertes Muster: `^Fehler\s+\d+`
    
    ---
    
    ### Tipps für effektives Filtern
    
    1. **Teste Muster zuerst:** Nutze die Testfunktion des Regex-Builders, bevor du ihn auf den kompletten Datensatz anwendest
    2. **Kombiniere Filter sorgfältig:** Mehrere Filter können gleichzeitig aktiviert werden; sie arbeiten nacheinander
    3. **Spaltenauswahl reduziert Dateigröße:** Exportiere nur benötigte Spalten um Ergebnisse zu straffen
    4. **Groß-/Kleinschreibung:** Alle Regex-Muster ignorieren standardmäßig Groß-/Kleinschreibung
    5. **Sonderzeichen in exaktem Text:** Der Builder maskiert spezielle Regex-Zeichen automatisch
    
    ---
    
    
    """)

def main():
    init_session_state()
    apply_sleek_dark_theme()
    
    with st.sidebar:
        st.markdown("### Datenübersicht")
        
        if st.session_state.df is not None:
            # Dateiinformationen
            st.markdown("**Infos**")
            st.caption(f"Aktives Blatt: {st.session_state.selected_sheet}")
            
            st.divider()
            
            # Zeilenstatistik
            st.markdown("**Statistik**")
            st.metric("Alle Zeilen", f"{len(st.session_state.df):,}")
            st.metric("Alle Spalten", f"{len(st.session_state.df.columns):,}")
            
            st.divider()
            
            # Datentypen-Zusammenfassung
            st.markdown("**Spaltentypen**")
            dtype_counts = st.session_state.df.dtypes.value_counts()
            for dtype, count in dtype_counts.items():
                st.caption(f"{dtype}: {count} Spalte(n)")
            
            st.divider()
            
            # Filterstatus
            if st.session_state.stats is not None:
                st.markdown("**Filterergebnisse**")
                st.metric("Ausgabezeilen", f"{st.session_state.stats['output_rows']:,}")
                st.metric("Trefferquote", f"{st.session_state.stats['retention_rate']:.1f}%")
                if st.session_state.stats['filters_applied']:
                    st.caption(f"Filter: {', '.join(st.session_state.stats['filters_applied'])}")
            
            st.divider()
            
            # Speicherverbrauch
            memory_mb = st.session_state.df.memory_usage(deep=True).sum() / 1024 / 1024
            st.caption(f"Speicher: {memory_mb:.1f} MB")
            
        else:
            st.info("Lade eine Excel-Datei hoch, um Statistiken anzuzeigen.")
            
            st.divider()
            st.markdown("**Anleitung**")
            st.markdown("""
            1. Excel-Datei hochladen
            2. Filter konfigurieren (optional)
            3. "Filter anwenden" klicken
            4. Ergebnisse herunterladen
            """)
        st.caption("*Version 0.1* ")

    st.title("Excel Filter Tool")
    st.markdown("*Temporäre Session: Es werden keine Daten und Einstellungen gespeichert!* ")
    st.write("")
    
    main_tabs = st.tabs(["Excel-Filter", "Regex-Builder", "Hilfe"])
    with main_tabs[0]: render_pipeline_tab()
    with main_tabs[1]: render_regex_builder_tab()
    with main_tabs[2]: render_help_tab()

if __name__ == "__main__":
    main()