"""
Funciones de transformación y normalización de datos.

Utilidades para limpiar, normalizar y transformar datos antes o después
de cargarlos en DataFrames.
"""
import unicodedata
from typing import Any


def normalizar_texto(texto: Any) -> str:
    """
    Normaliza texto removiendo tildes, espacios y convirtiendo a snake_case.
    
    Útil para normalizar nombres de columnas en datasets.
    
    Args:
        texto: Texto a normalizar (se convierte a string si no lo es)
        
    Returns:
        Texto normalizado en formato snake_case sin tildes
        
    Examples:
        >>> normalizar_texto('Nombre Completo')
        'nombre_completo'
        >>> normalizar_texto('FechaCreación')
        'fecha_creacion'
        >>> normalizar_texto('Código.Único')
        'codigo_unico'
        >>> normalizar_texto('ID Usuario')
        'id_usuario'
    """
    texto = str(texto)
    
    # Remover tildes y diacríticos
    texto_sin_tildes = ''.join(
        c for c in unicodedata.normalize('NFD', texto)
        if unicodedata.category(c) != 'Mn'
    )
    
    # Quitar espacios al inicio y final
    texto_sin_espacios = texto_sin_tildes.strip()
    
    # Separar palabras si hay mayúsculas (CamelCase -> Camel Case)
    # Pero NO separar si son mayúsculas consecutivas (ID, URL, etc.)
    texto_separado = []
    for i, char in enumerate(texto_sin_espacios):
        # Si es mayúscula y no es el primer caracter
        if char.isupper() and i > 0:
            # Verificar si el caracter anterior también es mayúscula (acronimo)
            # o si el siguiente también es mayúscula (parte de acronimo)
            prev_is_upper = texto_sin_espacios[i-1].isupper()
            next_is_upper = (i + 1 < len(texto_sin_espacios) and 
                           texto_sin_espacios[i+1].isupper())
            
            # Solo agregar espacio si no es parte de un acronimo
            if not prev_is_upper and not next_is_upper:
                texto_separado.append(' ')
        texto_separado.append(char)
    
    texto_separado = ''.join(texto_separado)
    
    # Convertir a minúsculas
    texto_minusculas = texto_separado.lower()
    
    # Reemplazar puntos por espacios
    texto_sin_puntos = texto_minusculas.replace('.', ' ')
    
    # Reemplazar espacios por guiones bajos
    texto_normalizado = texto_sin_puntos.replace(' ', '_')
    
    # Limpiar guiones bajos múltiples
    while '__' in texto_normalizado:
        texto_normalizado = texto_normalizado.replace('__', '_')
    
    return texto_normalizado.strip('_')


def limpiar_valor(valor: Any) -> Any:
    """
    Limpia un valor removiendo espacios en blanco si es string.
    
    Args:
        valor: Valor a limpiar
        
    Returns:
        Valor limpio (stripped si es string, sin cambios si no)
    """
    if isinstance(valor, str):
        return valor.strip()
    return valor
