# --- Imports ---
from flask import Blueprint, request, render_template_string
import pandas as pd
import re
from pathlib import Path
import traceback
import sys
import io  # Für das Abfangen von print-Ausgaben

# --- Logging Utility ---
# This helper returns a consistently formatted log entry for UI display and console output.
def _log(level: str, stage: str, message: str) -> str:
    ICONS = {"INFO": "ℹ️", "SUCCESS": "✅", "WARNING": "⚠️", "ERROR": "❌"}
    icon = ICONS.get(level.upper(), "ℹ️")
    return f"{icon} [{stage}] {message}"

# --- Globale Konfiguration & Initialisierung ---
# The Blueprint registers the upload route inside the containing Flask application.
blueprint = Blueprint(__name__.rsplit(".", 1)[-1], __name__)

# The import of IPython.display.display is optional for nicer debugging inside notebooks.
try:
    from IPython.display import display
except ImportError:
    display = print

# This block establishes the project root so that internal modules can be imported reliably.
if "__file__" in globals():
    PROJECT_ROOT_FOR_IMPORTS = Path(__file__).resolve().parent.parent
else:
    if (Path.cwd() / "cache").is_dir() and (Path.cwd() / "models").is_dir():
        PROJECT_ROOT_FOR_IMPORTS = Path.cwd()
    else:
        PROJECT_ROOT_FOR_IMPORTS = Path.cwd().parent
sys.path.append(str(PROJECT_ROOT_FOR_IMPORTS))

# These placeholders are overwritten if the database models can be imported successfully.
MODELS_IMPORTED = False
DealDeal, BaseBase, MysqlManager, Session = None, None, None, None

# The following try-except attempts to load the SQLAlchemy models and a helper for database sessions.
try:
    from models.deal_deal import DealDeal
    from models.base_base import BaseBase
    from manager.MysqlManager import MysqlManager
    from sqlalchemy.orm import Session

    MODELS_IMPORTED = True
    print(_log("SUCCESS", "Startup", "Database modules imported successfully."))
# A failure to import modules results in a warning and disables database operations for the session.
except ImportError as e:
    print(_log("WARNING", "Startup", f"Database modules could not be imported: {e}"))
    print(_log("INFO", "Startup", f"sys.path = {sys.path}"))
    print(_log("INFO", "Startup", f'Assumed project root: "{PROJECT_ROOT_FOR_IMPORTS}"'))
    print(_log("INFO", "Startup", "Database operations will be skipped."))

# --- Reguläre Ausdrücke und Hilfsfunktionen ---
# This regex matches a provider code in reference B files.
CODE_RE_B = re.compile(r"^[A-Z]\d{7}$")
# This regex matches numeric strings that may contain a comma as a decimal separator.
NUM_RE_B = re.compile(r"^\d+(,\d+)?$")

# The helper converts a numeric string from reference B into an integer representation.
def to_int_ref_b(txt: str) -> int:
    txt = str(txt).strip()
    if txt in {"", "-", "–"}:
        return 0
    return int(float(txt.replace(",", "."))) if NUM_RE_B.match(txt) else 0

# The helper validates whether a value can safely be converted to an integer.
def can_be_int_ref_a(value: object) -> bool:
    if pd.isna(value):
        return False
    try:
        float_val = float(value)
        return float_val == int(float_val)
    except (ValueError, TypeError):
        return False

# The helper heuristically detects whether the uploaded file is of reference A type.
def is_referenz_a_file(file_stream) -> bool:
    try:
        file_stream.seek(0)
        xls = pd.ExcelFile(file_stream)
        if "freenet-Tarife" not in xls.sheet_names:
            return False
        file_stream.seek(0)
        df_header = pd.read_excel(file_stream, sheet_name="freenet-Tarife", header=6, nrows=0)
        return df_header.shape[1] >= 22
    except Exception:
        return False

# The helper heuristically detects whether the uploaded file is of reference B type.
def is_referenz_b_file(file_stream) -> bool:
    try:
        file_stream.seek(0)
        df_sample = pd.read_excel(file_stream, sheet_name=0, header=None, nrows=20, dtype=str)
        if df_sample.shape[1] < 13:
            return False
        df_sliced_sample = df_sample.iloc[:, 7:13]
        if df_sliced_sample.shape[1] != 6:
            return False
        match_count = 0
        rows_to_check = min(len(df_sliced_sample), 10)
        if rows_to_check == 0:
            return False
        for i in range(rows_to_check):
            row_values = [str(c).strip() for c in df_sliced_sample.iloc[i].tolist()]
            if len(row_values) == 6:
                if CODE_RE_B.match(row_values[2]) or CODE_RE_B.match(row_values[5]):
                    match_count += 1
        return match_count > 0
    except Exception:
        return False

# --- Reference A Verarbeitung ---
# The loader reads the relevant columns from the reference A Excel file and logs any inconsistencies.
def load_data_ref_a(file_stream) -> tuple[pd.DataFrame | None, list[str]]:
    SHEET_NAME = "freenet-Tarife"
    HEADER_ROW_INDEX = 6
    COL_POS_ID_J, COL_POS_ID_L, COL_POS_ID_N = 9, 11, 13
    COL_POS_GV, COL_POS_AV, COL_POS_PW = 15, 16, 21
    log_ref_a = []

    # This nested helper maps column positions to internal names while collecting warnings.
    def map_pos(all_columns, pos, internal_name, desc):
        if pos < len(all_columns):
            orig_header = all_columns[pos]
            columns_to_select_by_original_name.append(orig_header)
            internal_rename_map[orig_header] = internal_name
        else:
            log_ref_a.append(_log("WARNING", "RefA-Load", f"{desc} (expected pos {pos}) out of range ({len(all_columns)} columns)."))

    try:
        file_stream.seek(0)
        df_full_header = pd.read_excel(file_stream, sheet_name=SHEET_NAME, header=HEADER_ROW_INDEX, nrows=0)
        all_original_columns = df_full_header.columns.tolist()
        columns_to_select_by_original_name: list[str] = []
        internal_rename_map: dict[str, str] = {}

        map_pos(all_original_columns, COL_POS_ID_J, "ID_J_Raw", "ID1")
        map_pos(all_original_columns, COL_POS_ID_L, "ID_L_Raw", "ID2")
        map_pos(all_original_columns, COL_POS_ID_N, "ID_N_Raw", "ID3")
        map_pos(all_original_columns, COL_POS_GV, "Grundvergütung_Raw", "GV")
        map_pos(all_original_columns, COL_POS_AV, "Aktionsvergütung_Raw", "AV")
        map_pos(all_original_columns, COL_POS_PW, "Punktewert_Raw", "PW")

        # An early exit occurs if no usable columns were found.
        if not columns_to_select_by_original_name:
            log_ref_a.append(_log("ERROR", "RefA-Load", "No columns found by position."))
            return None, log_ref_a

        # The loader reads the selected columns and applies the internal rename map.
        columns_to_select_by_original_name = sorted(set(columns_to_select_by_original_name))
        file_stream.seek(0)
        df = pd.read_excel(
            file_stream,
            sheet_name=SHEET_NAME,
            header=HEADER_ROW_INDEX,
            usecols=columns_to_select_by_original_name,
            dtype=str,
        )
        df.rename(columns=internal_rename_map, inplace=True)
        df.dropna(how="all", inplace=True)
        df.reset_index(drop=True, inplace=True)
        log_ref_a.append(
            _log(
                "SUCCESS",
                "RefA-Load",
                f"DataFrame loaded with {df.shape[0]} rows. Columns: {df.columns.tolist()}",
            )
        )
        return df, log_ref_a
    # The catch-all handles any unexpected loader failure.
    except Exception as e:
        log_ref_a.append(_log("ERROR", "RefA-Load", str(e)))
        print(traceback.format_exc())
        return None, log_ref_a

# The transformer converts raw numeric columns and reshapes IDs into a consolidated format.
def transform_data_ref_a(df_loaded: pd.DataFrame) -> tuple[pd.DataFrame | None, list[str]]:
    log_ref_a: list[str] = []

    # An empty or missing DataFrame causes an early exit.
    if df_loaded is None or df_loaded.empty:
        log_ref_a.append(_log("INFO", "RefA-Transform", "Input DataFrame is empty."))
        return pd.DataFrame(), log_ref_a

    df = df_loaded.copy()

    # This loop converts three raw numeric columns into integer provisions.
    for raw_col, final_col in {
        "Grundvergütung_Raw": "provision1",
        "Aktionsvergütung_Raw": "provision4",
    }.items():
        if raw_col in df.columns:
            df[final_col] = pd.to_numeric(df[raw_col], errors="coerce").fillna(0)
            if raw_col != final_col:
                df.drop(columns=[raw_col], inplace=True, errors="ignore")
        else:
            df[final_col] = 0
            log_ref_a.append(
                _log("WARNING", "RefA-Transform", f"Raw column '{raw_col}' missing; set '{final_col}' to 0.")
            )

    # This branch creates a third provision based on the points value if present.
    if "Punktewert_Raw" in df.columns:
        pw_num = pd.to_numeric(df["Punktewert_Raw"], errors="coerce")
        df["provision3"] = pw_num.apply(lambda x: 80 if pd.notna(x) and x > 1 else 0)
        df.drop(columns=["Punktewert_Raw"], inplace=True, errors="ignore")
    # The else branch handles the absence of the points column.
    else:
        df["provision3"] = 0
        log_ref_a.append(
            _log("WARNING", "RefA-Transform", "'Punktewert_Raw' missing; set 'provision3' to 0.")
        )

    id_raw_cols = [c for c in ["ID_J_Raw", "ID_L_Raw", "ID_N_Raw"] if c in df.columns]

    # An early exit is triggered if none of the expected ID columns are present.
    if not id_raw_cols:
        log_ref_a.append(_log("ERROR", "RefA-Transform", "No raw ID columns available for melt operation."))
        return pd.DataFrame(), log_ref_a

    # The melt reshapes each ID column into a single 'id' column, preserving additional data.
    id_vars = [c for c in df.columns if c not in id_raw_cols]
    df_melted = pd.melt(df, id_vars=id_vars, value_vars=id_raw_cols, var_name="_src", value_name="id")
    df_melted.drop(columns=["_src"], inplace=True)
    df_melted.dropna(subset=["id"], inplace=True)

    # This block validates and normalizes the ID column to integer type.
    if "id" in df_melted.columns:
        df_melted["id"] = df_melted["id"].astype(str).str.strip()
        df_melted = df_melted[df_melted["id"] != ""]
        if not df_melted.empty:
            df_melted = df_melted[df_melted["id"].apply(can_be_int_ref_a)]
            if not df_melted.empty:
                try:
                    df_melted["id"] = df_melted["id"].astype(float).astype(int)
                except ValueError:
                    log_ref_a.append(
                        _log("WARNING", "RefA-Transform", "Failed to cast 'id' column to int.")
                    )

    # This line reorders the most important columns to the beginning of the DataFrame.
    order = ["id"] + [p for p in ["provision1", "provision3", "provision4"] if p in df_melted.columns]
    final_cols = order + [c for c in df_melted.columns if c not in order]
    if not df_melted.empty:
        df_melted = df_melted.reindex(columns=final_cols, copy=False)

    log_ref_a.append(
        _log("SUCCESS", "RefA-Transform", f"Transformation completed with {len(df_melted)} records ready for DB.")
    )
    return df_melted, log_ref_a

# The updater synchronizes transformed reference A data into the transactional database.
def update_db_ref_a(df_input: pd.DataFrame, log_ref_a_outer: list[str]) -> list[str]:
    log_ref_a = log_ref_a_outer

    # A missing model import prevents any database interaction.
    if not MODELS_IMPORTED:
        log_ref_a.append(_log("ERROR", "RefA-DB", "Database modules are not available."))
        return log_ref_a

    # An empty DataFrame leads to an informational exit.
    if df_input.empty:
        log_ref_a.append(_log("INFO", "RefA-DB", "Input DataFrame is empty."))
        return log_ref_a

    req_cols = ["id", "provision1", "provision3", "provision4"]

    # Ensuring all required columns exist before proceeding.
    if not all(c in df_input.columns for c in req_cols):
        missing = [c for c in req_cols if c not in df_input.columns]
        log_ref_a.append(_log("ERROR", "RefA-DB", f"Missing columns: {missing}"))
        return log_ref_a

    session: Session = MysqlManager().getSession()
    processed = found_base = not_found_base = checked_deals = updated_deals = 0

    # The outer try-except captures any unexpected database errors.
    try:
        for row_idx, row in df_input.iterrows():
            processed += 1
            current_provider_code_to_query = ""
            try:
                id_as_int = int(float(str(row.id)))
                current_provider_code_to_query = str(id_as_int)
            except ValueError:
                log_ref_a.append(
                    _log(
                        "WARNING",
                        "RefA-DB",
                        f"ID '{row.id}' (row {row_idx}) could not be converted to int. Skipping.",
                    )
                )
                continue

            p1, p3, p4 = row.provision1, row.provision3, row.provision4
            base_recs = session.query(BaseBase).filter_by(providercode_base=current_provider_code_to_query).all()

            # This branch handles the existence of at least one matching base record.
            if base_recs:
                found_base += 1
                deals_found_for_pc = deals_updated_for_pc = 0

                for br in base_recs:
                    deals = session.query(DealDeal).filter_by(base_deal=br.id_base).all()
                    deals_found_for_pc += len(deals)

                    # Each deal is compared and updated if any provision differs.
                    for deal_obj in deals:
                        changed = False
                        if deal_obj.provision1_deal != p1:
                            deal_obj.provision1_deal = p1
                            changed = True
                        if hasattr(deal_obj, "provision3_deal"):
                            if deal_obj.provision3_deal != p3:
                                deal_obj.provision3_deal = p3
                                changed = True
                        elif p3 != 0:
                            log_ref_a.append(
                                _log(
                                    "WARNING",
                                    "RefA-DB",
                                    f"Deal {getattr(deal_obj, 'id_deal', 'N/A')} has no provision3_deal (value {p3}).",
                                )
                            )
                        if deal_obj.provision4_deal != p4:
                            deal_obj.provision4_deal = p4
                            changed = True

                        if changed:
                            deals_updated_for_pc += 1

                checked_deals += deals_found_for_pc
                updated_deals += deals_updated_for_pc

                # This log message summarizes the outcome for the current provider code.
                prefix = f"Code '{current_provider_code_to_query}'"
                status = "SUCCESS" if deals_updated_for_pc else "INFO"
                log_ref_a.append(
                    _log(
                        status,
                        "RefA-DB",
                        f"{prefix}: {deals_updated_for_pc}/{deals_found_for_pc} deals {'updated' if deals_updated_for_pc else 'checked (no change)'}.",
                    )
                )
            # The else branch records the absence of a matching base record.
            else:
                not_found_base += 1
                log_ref_a.append(
                    _log("WARNING", "RefA-DB", f"Code '{current_provider_code_to_query}' not found in base_base.")
                )

        # This commit persists updates only if any deal was modified.
        if updated_deals > 0:
            session.commit()
            log_ref_a.append(_log("SUCCESS", "RefA-DB", "Commit successful."))
        # The else branch indicates no changes were made.
        else:
            log_ref_a.append(_log("INFO", "RefA-DB", "No DB changes, commit skipped."))
    # A rollback ensures consistency on any unhandled exception.
    except Exception as e:
        session.rollback()
        log_ref_a.append(_log("ERROR", "RefA-DB", str(e)))
        print(traceback.format_exc())
    finally:
        if MODELS_IMPORTED and session:
            session.close()

    log_ref_a.append(
        _log(
            "INFO",
            "RefA-DB",
            f"Summary: processed={processed}, base_found={found_base}, base_missing={not_found_base}, deals_checked={checked_deals}, deals_updated={updated_deals}",
        )
    )
    return log_ref_a

# The orchestrator performs the end-to-end processing for reference A files.
def process_referenz_a_file(file_stream) -> list[str]:
    all_logs = [_log("INFO", "RefA", "Processing started.")]
    df_loaded, logs_load = load_data_ref_a(file_stream)
    all_logs.extend(logs_load)

    # An early exit occurs if the initial load failed or produced no rows.
    if df_loaded is None or df_loaded.empty:
        all_logs.append(_log("INFO", "RefA", "Processing aborted after loader stage."))
        return all_logs

    df_transformed, logs_transform = transform_data_ref_a(df_loaded)
    all_logs.extend(logs_transform)

    # A transformed DataFrame with no rows stops further processing.
    if df_transformed.empty:
        all_logs.append(_log("INFO", "RefA", "Processing aborted after transform stage (no records)."))
        return all_logs

    logs_db = update_db_ref_a(df_transformed, [])
    all_logs.extend(logs_db)
    all_logs.append(_log("INFO", "RefA", "Processing completed."))
    return all_logs

# --- Reference B Verarbeitung ---
# The parser extracts value differences from reference B Excel files.
def parse_excel_ref_b(file_stream) -> tuple[pd.DataFrame | None, list[str]]:
    log_ref_b: list[str] = []
    records: list[dict[str, object]] = []

    try:
        file_stream.seek(0)
        df = pd.read_excel(file_stream, sheet_name=0, header=None, dtype=str).fillna("").iloc[:, 7:13]

        # An immediate failure is reported if the expected six columns are not present.
        if df.shape[1] != 6:
            log_ref_b.append(_log("ERROR", "RefB-Parse", "Incorrect column count after slice."))
            return pd.DataFrame(), log_ref_b

        for row_tuple in df.itertuples(index=False):
            r = [str(c).strip() for c in row_tuple]
            if not (
                len(r) == 6
                and all(
                    t in {"", "-", "–"} or NUM_RE_B.match(t) or CODE_RE_B.match(t) for t in r
                )
                and (CODE_RE_B.match(r[2]) or CODE_RE_B.match(r[5]))
            ):
                continue

            vmc, bmc, cmc, vsp, bsp, csp = r
            if CODE_RE_B.match(cmc):
                records.append(
                    {
                        "code": cmc,
                        "value": to_int_ref_b(bmc) - to_int_ref_b(vmc),
                        "source": "MC",
                    }
                )
            if CODE_RE_B.match(csp):
                records.append(
                    {
                        "code": csp,
                        "value": to_int_ref_b(bsp) - to_int_ref_b(vsp),
                        "source": "SP",
                    }
                )

        result_df = pd.DataFrame(records)
        log_ref_b.append(_log("SUCCESS", "RefB-Parse", f"{len(result_df)} valid entries parsed."))
        return result_df, log_ref_b
    except Exception as e:
        log_ref_b.append(_log("ERROR", "RefB-Parse", str(e)))
        print(traceback.format_exc())
        return pd.DataFrame(), log_ref_b

# The updater applies reference B values to the database.
def update_db_ref_b(df_input: pd.DataFrame, log_ref_b_outer: list[str]) -> list[str]:
    log_ref_b = log_ref_b_outer

    # The absence of model imports is treated as a critical error.
    if not MODELS_IMPORTED:
        log_ref_b.append(_log("ERROR", "RefB-DB", "Database modules are not available."))
        return log_ref_b

    # An empty DataFrame short-circuits the update logic.
    if df_input.empty:
        log_ref_b.append(_log("INFO", "RefB-DB", "Input DataFrame is empty."))
        return log_ref_b

    session: Session = MysqlManager().getSession()
    hits = misses = updated_count = 0

    try:
        for _, row in df_input.iterrows():
            code, value = row["code"], row["value"]
            deals = session.query(DealDeal).filter_by(providercode_deal=code).all()

            # This branch logs a successful hit and possible updates.
            if deals:
                hits += 1
                current_deal_updated = False
                for d_obj in deals:
                    if hasattr(d_obj, "provision2_deal") and d_obj.provision2_deal != value:
                        d_obj.provision2_deal = value
                        current_deal_updated = True
                    elif not hasattr(d_obj, "provision2_deal"):
                        log_ref_b.append(
                            _log("WARNING", "RefB-DB", f"Deal for code {code} lacks provision2_deal.")
                        )
                if current_deal_updated:
                    updated_count += 1
                    log_ref_b.append(
                        _log("SUCCESS", "RefB-DB", f"{code} ({len(deals)} deals) -> P2={value}")
                    )
                # An informational log is omitted when no changes are required.
            # The else branch records a miss against the provided code.
            else:
                misses += 1
                log_ref_b.append(_log("WARNING", "RefB-DB", f"{code}: no matching deal"))

        # This commit finalizes updates when any deal was modified.
        if updated_count > 0:
            session.commit()
            log_ref_b.append(_log("SUCCESS", "RefB-DB", "Commit successful."))
        # The else branch signifies no updates were necessary.
        else:
            log_ref_b.append(_log("INFO", "RefB-DB", "No DB changes, commit skipped."))
    except Exception as e:
        session.rollback()
        log_ref_b.append(_log("ERROR", "RefB-DB", str(e)))
        print(traceback.format_exc())
    finally:
        if MODELS_IMPORTED and session:
            session.close()

    log_ref_b.append(
        _log(
            "INFO",
            "RefB-DB",
            f"Summary: hits={hits} (updated={updated_count}), misses={misses}",
        )
    )
    return log_ref_b

# The orchestrator performs the end-to-end processing for reference B files.
def process_referenz_b_file(file_stream) -> list[str]:
    all_logs = [_log("INFO", "RefB", "Processing started.")]
    df_parsed, logs_parse = parse_excel_ref_b(file_stream)
    all_logs.extend(logs_parse)

    # An early exit is triggered if parsing failed or produced no records.
    if df_parsed.empty and not logs_parse:
        all_logs.append(_log("INFO", "RefB", "Processing aborted after parse stage."))
        return all_logs
    if df_parsed.empty:
        all_logs.append(_log("INFO", "RefB", "No data found after parsing; DB update skipped."))
        return all_logs

    logs_db = update_db_ref_b(df_parsed, [])
    all_logs.extend(logs_db)
    all_logs.append(_log("INFO", "RefB", "Processing completed."))
    return all_logs

# --- Front-End HTML Template ---
# The upload page provides file selection and displays the processing log.
UPLOAD_FORM_HTML = """
<!doctype html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Freenet Upload</title><style>body{font-family:Arial,sans-serif;margin:20px;background-color:#f9f9f9;color:#333}.container{max-width:700px;margin:auto;background-color:#fff;padding:30px;border-radius:8px;box-shadow:0 2px 10px rgba(0,0,0,.1)}h1{color:#28a745;text-align:center;margin-bottom:20px}input[type=file]{display:block;width:calc(100% - 22px);padding:10px;margin-bottom:20px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box}input[type=submit]{display:block;width:100%;padding:12px;background-color:#28a745;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:16px;transition:background-color .3s ease}input[type=submit]:hover{background-color:#1e7e34}.message-box{margin-top:25px;padding:15px;border-radius:4px;text-align:left;max-height:400px;overflow-y:auto;border:1px solid #ddd;background-color:#fdfdfd}.message-box p{margin:0 0 5px 0;white-space:pre-wrap;word-wrap:break-word;font-size:0.9em;}.message-box hr{margin:10px 0;border:0;border-top:1px solid #eee}.info{background-color:#e7f3fe;border-left:6px solid #2196F3;color:#0d47a1}.error{background-color:#ffebee;border-left:6px solid #f44336;color:#c62828}.unknown{background-color:#fff3e0;border-left:6px solid #ffa726;color:#e65100}</style></head>
<body><div class="container"><h1>Freenet Upload</h1>
<form method="post" enctype="multipart/form-data">
<input type="file" name="excel_file" id="excel_file" accept=".xlsx,.xls" required><input type="submit" value="Save"></form>
{% if feedback_messages %} <div class="message-box {{ message_class }}"><h3>Verarbeitungs-Log:</h3> {% for msg in feedback_messages %} <p>{{ msg | safe }}</p> {% endfor %} </div> {% endif %}
</div></body></html>
"""

# --- Flask Route ---
# The route handles GET for the upload form and POST for file processing.
@blueprint.route("/freenet-upload", methods=["GET", "POST"])
def freenet_upload_route():
    feedback_messages: list[str] = []
    message_class = "info"

    # This branch covers the POST request that processes the uploaded file.
    if request.method == "POST":
        if "excel_file" not in request.files or request.files["excel_file"].filename == "":
            feedback_messages.append("Fehler: Keine Datei ausgewählt.")
            message_class = "error"
        else:
            file = request.files["excel_file"]
            file_stream_content = io.BytesIO()
            file.save(file_stream_content)
            file_stream_content.seek(0)

            try:
                is_a = is_referenz_a_file(file_stream_content)
                is_b = is_referenz_b_file(file_stream_content)

                # This branch processes a reference A file.
                if is_a:
                    file_stream_content.seek(0)
                    logs = process_referenz_a_file(file_stream_content)
                    feedback_messages.extend(logs)
                    message_class = (
                        "info"
                        if not any("❌" in log or "⚠️" in log for log in logs)
                        else "error"
                    )
                # The elif handles a reference B file.
                elif is_b:
                    file_stream_content.seek(0)
                    logs = process_referenz_b_file(file_stream_content)
                    feedback_messages.extend(logs)
                    message_class = (
                        "info"
                        if not any("❌" in log or "⚠️" in log for log in logs)
                        else "error"
                    )
                # The else branch indicates an unrecognized file structure.
                else:
                    feedback_messages.append("Struktur unbekannt: Datei entspricht weder Referenz A noch B.")
                    message_class = "unknown"
            # Any unhandled exception bubbles up as a critical error.
            except Exception as e:
                feedback_messages.append(f"❌ Schwerwiegender Fehler bei Dateiverarbeitung: {str(e)}")
                message_class = "error"
                print(traceback.format_exc())

            # A fallback message ensures that the user always receives some form of feedback.
            if not feedback_messages:
                feedback_messages.append("Verarbeitung abgeschlossen. Keine spezifischen Logs.")

    return render_template_string(UPLOAD_FORM_HTML, feedback_messages=feedback_messages, message_class=message_class)
