# Importar todas las librerias que se necesitaran para trabajar
import pandas as pd
import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
import numpy as np

def leer_archivo(ruta_archivo):
    """
    Lee un archivo de datos (.csv, .xls o .xlsx) y devuelve un DataFrame de pandas.

    Parámetros:
    -----------
    ruta_archivo : str o Path
        Ruta completa del archivo a leer.

    Retorna:
    --------
    pd.DataFrame
        El contenido del archivo como un DataFrame.

    Lanza:
    ------
    FileNotFoundError
        Si el archivo no existe en la ruta especificada.
    ValueError
        Si el archivo no puede ser leído o tiene un formato no soportado.
    UnicodeDecodeError
        Si no se puede decodificar el CSV con los encodings comunes.
    """
    ruta = Path(ruta_archivo)

    if not ruta.exists():
        raise FileNotFoundError(f"El archivo no se encontró: {ruta}")

    extension = ruta.suffix.lower()

    if extension == '.xls':
        try:
            return pd.read_excel(ruta, engine='xlrd')
        except Exception as e:
            raise ValueError(f"No se pudo leer el archivo .xls: {ruta}\nError: {e}")

    elif extension == '.xlsx':
        try:
            return pd.read_excel(ruta, engine='openpyxl')
        except Exception as e:
            raise ValueError(f"No se pudo leer el archivo .xlsx: {ruta}\nError: {e}")

    elif extension == '.csv':
        encodings_a_probar = ['utf-8', 'ISO-8859-1', 'latin1', 'cp1252']
        for enc in encodings_a_probar:
            try:
                return pd.read_csv(ruta, encoding=enc, low_memory=False)
            except UnicodeDecodeError:
                continue
            except Exception as e:
                raise ValueError(f"Error inesperado al leer CSV con codificación '{enc}': {e}")

        raise UnicodeDecodeError(
            f"No se pudo leer el archivo CSV con las codificaciones: {', '.join(encodings_a_probar)}"
        )

    else:
        raise ValueError(f"Formato de archivo no soportado: '{extension}'. Solo se permiten .csv, .xls, .xlsx")

def diagnostico_base_datos_pdf(df, nombre_pdf="diagnostico_datos.pdf"):
    with PdfPages(nombre_pdf) as pdf:
        # Página 1: Resumen general
        fig, ax = plt.subplots(figsize=(10, 6))
        texto = f"""Resumen general:
        Dimensiones: {df.shape}
        Columnas: {', '.join(df.columns[:10]) + ('...' if df.shape[1] > 10 else '')}
        Duplicados: {df.duplicated().sum()}
        Tipos de datos: {df.dtypes.value_counts().to_dict()}
        """
        ax.axis("off")
        ax.text(0.01, 0.9, texto, fontsize=12, verticalalignment='top', family='monospace')
        pdf.savefig(fig)
        plt.close()

        # Página 2: Valores nulos
        nulos = df.isnull().sum()
        nulos = nulos[nulos > 0].sort_values(ascending=False)
        if not nulos.empty:
            fig, ax = plt.subplots(figsize=(10, 6))
            nulos.plot(kind="barh", ax=ax, color="salmon")
            ax.set_title("Valores nulos por columna")
            pdf.savefig(fig)
            plt.close()

        # Página 3: Columnas irrelevantes (1 solo valor)
        unicos = df.nunique()
        irrelevantes = unicos[unicos <= 1]
        if not irrelevantes.empty:
            fig, ax = plt.subplots(figsize=(10, 6))
            irrelevantes.plot(kind="barh", ax=ax, color="gray")
            ax.set_title("Columnas con un solo valor único")
            pdf.savefig(fig)
            plt.close()

        # Página 4: Resumen numérico
        fig, ax = plt.subplots(figsize=(10, 6))
        ax.axis("off")
        resumen = df.describe().round(2).to_string()
        ax.text(0, 1, resumen, fontsize=10, verticalalignment='top', family='monospace')
        pdf.savefig(fig)
        plt.close()

        # Página 5+: Valores únicos por columnas tipo texto
        columnas_obj = df.select_dtypes(include='object').columns
        for col in columnas_obj:
            valores = df[col].value_counts(dropna=False).head(10)
            fig, ax = plt.subplots(figsize=(10, 6))
            ax.barh(valores.index.astype(str), valores.values, color='skyblue')
            ax.set_title(f"Top 10 valores en '{col}'")
            pdf.savefig(fig)
            plt.close()

    print(f"✅ Diagnóstico guardado en: {nombre_pdf}")

def limpiar_base_vivienda(df, drop_threshold=0.95, verbose=True):
    """
    Limpia un DataFrame eliminando columnas irrelevantes, 
    reemplazando valores problemáticos y asegurando tipos adecuados.

    Parámetros:
    ------------
    df : pd.DataFrame
        Base de datos a limpiar.
    drop_threshold : float, default=0.95
        Umbral de proporción de valores nulos o repetidos para eliminar una columna.
    verbose : bool, default=True
        Si se desea imprimir resumen de limpieza.

    Retorna:
    --------
    pd.DataFrame
        DataFrame limpio y listo para análisis.
    """

    df = df.copy()


    # 2. Reemplazar valores comunes problemáticos
    df.replace(["*", "NA", "N/A", "n/a", "--", "…", "..."], np.nan, inplace=True)

    # 3. Eliminar columnas con un solo valor o con más del % definido de valores nulos
    columnas_irrelevantes = df.columns[
        (df.nunique(dropna=False) <= 1) | (df.isna().mean() > drop_threshold)
    ]
    df.drop(columns=columnas_irrelevantes, inplace=True)

    # 5. Eliminar filas completamente vacías (si las hay)
    df.dropna(how='all', inplace=True)

    # 6. Resetear índice
    df.reset_index(drop=True, inplace=True)

    # 7. Opcional: mostrar resumen
    if verbose:
        print(f"🔍 Limpieza completa:")
        print(f" - Columnas eliminadas: {len(columnas_irrelevantes)}")
        print(f" - Columnas restantes: {df.shape[1]}")
        print(f" - Filas totales: {df.shape[0]}")

    return df
