from pathlib import Path
import re
import pandas as pd 

# Mapping "possible names" - "standard names"

column_aliases =   {
    "Voltaje Inyectado (V)"     :   ["Voltaje Inyectado (V)"],
    "Voltaje Electrodos (V)"    :   ["Voltaje Electrodos (V)"],
    "Corriente Electrodos (A)"  :   ["Corriente Electrodos (A)"],
    "Corriente Inyectada (A)"   :   ["Corriente Inyectada (A)"],
    "Resistencia"               :   ["Resistencia"],
    "Temperatura"               :   ["Temperatura"],
} 

def _clean_name(name:   str) -> str:
    """Normaliza un encabezado: minisculas, sin espacios dobles, sin simbolos raros."""
    name    =   name.replace("\ufeff", "")
    name    =   name.strip().lower()
    name    =   re.sub(r"\s+", "", name)
    name    =   re.sub(r"[^a-z0-9áéíóúñ _\-]", "", name)
    return name

def normalize_columns(df: pd.DataFrame) -> pd.DataFrame:
    """Rename columns to standard names as alias"""

    df.columns      =   [str(c) for c in df.columns]

    ## Print the information in the columns
    #print("Originals Columns:", df.columns)
    #print("Types:", [type(c) for c in df.columns])

    original_cols   =   list(df.columns)
    cleaned         =   {_clean_name(c): c for c in original_cols}

    rename_map      =   {}
    for std, aliases in column_aliases.items():
        for a in aliases:
            a_clean =   _clean_name(a)
            if  a_clean in cleaned:
                rename_map[cleaned[a_clean]]    =   std
                break
    df  =   df.rename(columns=rename_map)

    return  df

def load_experiment(csv_path: Path, ronda: int, experimento: int) -> pd.DataFrame:
    """Upload a CSV, normalize columns and add metadata."""
    df  =   pd.read_csv(csv_path, sep=None, engine="python", encoding="utf-8-sig")

    df  =   normalize_columns(df)

    # Adding metadata for comparative analysis
    df["ronda"]         =   ronda
    df["experimento"]   =   experimento
    df["archivo"]       =   csv_path.name

    return  df

def apply_filter(
        df: pd.DataFrame,
        row_start:  int     |   None    =   None,
        row_end:    int     |   None    =   None,
        time_col:   str     =   "tiempo",
        t_min:      float   |   None    =   None,
        t_max:      float   |   None    =   None,   
)   ->  pd.DataFrame:
    """
    Filtro Flexible:
    -   por índices de fila [row_start:row_end]
    -   por rango de tiempo [t_min, t_max] si existe columna 'tiempo'
    """

    out =   df.copy()

    if  row_start is not None or row_end is not None:
        out =   out.iloc[row_start:row_end]

    if time_col in out.columns  and (t_min  is not  None    or t_max is not None):
        if  t_min   is not  None:
            out =   out[out[time_col]   >=  t_min]
        if  t_max   is not  None:
            out =   out[out[time_col]   <=  t_max]
    
    return   out.reset_index(drop=True)

def load_all(data_dir: Path)    -> dict[tuple[int, int], pd.DataFrame]:
    """
    Carga todo en un diccionario:
    key     =   (ronda, experimento)
    value   =   DataFrame 
    """
    data = {}

    #Find files like: data/round1/*.csv and data/round2/*.csv
    for ronda in [1,2]:
        ronda_dir   =   data_dir / f"Rnd_{ronda}"
        csvs        =   sorted(ronda_dir.glob("*.csv"))

        if not csvs:
            print(f"Theres no CSVs in: {ronda_dir}")
            continue
        
        for i, csv_path in enumerate(csvs, start=1):
            df  =   load_experiment(csv_path, ronda=ronda, experimento=i)
            data[(ronda, i)]    =   df
    
    return data