# /modules/calculations.py

"""
Módulo para realizar cálculos y agregaciones sobre los datos de ventas.
Contiene funciones para KPIs, análisis de tendencias y otras métricas de negocio.
"""

import pandas as pd
from typing import Dict, Any, Tuple, Optional

def calculate_main_kpis(df: pd.DataFrame) -> Dict[str, Any]:
    """
    Calcula un conjunto de KPIs principales a partir de un DataFrame de ventas.

    Args:
        df (pd.DataFrame): DataFrame filtrado para el análisis.

    Returns:
        Dict[str, Any]: Un diccionario con los KPIs calculados.
    """
    if df.empty:
        return {
            "ingreso_total": 0.0, "total_folios": 0, "total_items": 0,
            "ticket_promedio": 0.0, "pct_descuento": 0.0
        }

    ingreso_total = float(df["ingreso"].sum())
    total_folios = df["folio"].nunique()
    total_items = len(df)
    
    # Ticket promedio
    ingresos_por_folio = df.groupby("folio")["ingreso"].sum()
    ticket_promedio = float(ingresos_por_folio.mean()) if not ingresos_por_folio.empty else 0.0
    
    # Porcentaje de descuento
    bruto_total = df["importe_total_producto"].sum()
    desc_total = (df["importe_total_producto"] * df["descuento_porcentaje"]).sum()
    pct_descuento = (desc_total / bruto_total) if bruto_total > 0 else 0.0
    
    return {
        "ingreso_total": ingreso_total,
        "total_folios": total_folios,
        "total_items": total_items,
        "ticket_promedio": ticket_promedio,
        "pct_descuento": pct_descuento,
    }

def calculate_trend_metrics(
    df_current: pd.DataFrame, 
    df_historical: pd.DataFrame, 
    freq: str = "M"
) -> Tuple[float, Optional[float]]:
    """
    Calcula el ingreso promedio para un período y su variación vs. el período anterior.

    Args:
        df_current (pd.DataFrame): Datos del período actual seleccionado.
        df_historical (pd.DataFrame): Datos históricos completos de la sucursal.
        freq (str): Frecuencia de agrupación ('M' para mes, 'W' para semana, 'D' para día).

    Returns:
        Tuple[float, Optional[float]]: Una tupla con el ingreso promedio actual y
                                       el delta porcentual vs. el período previo.
    """
    if df_current.empty:
        return 0.0, None

    # Agrupar por período y sumar ingresos
    def group_by_period(df, date_col="fecha_ticket", value_col="ingreso"):
        return df.set_index(pd.to_datetime(df[date_col])).resample(freq)[value_col].sum()

    s_curr = group_by_period(df_current)
    if s_curr.empty:
        return 0.0, None
    
    avg_curr = float(s_curr.mean())

    # Ventana de tiempo anterior
    s_hist = group_by_period(df_historical)
    if len(s_hist) < len(s_curr):
         return avg_curr, None # No hay suficientes datos históricos para comparar

    # Localizar el índice del período anterior
    try:
        end_prev_period = s_curr.index.min() - pd.Timedelta(days=1)
        prev_periods = s_hist.loc[:end_prev_period].tail(len(s_curr))
    except (IndexError, KeyError):
        return avg_curr, None

    if prev_periods.empty:
        return avg_curr, None
        
    avg_prev = float(prev_periods.mean())
    
    delta = (avg_curr - avg_prev) / avg_prev if avg_prev > 0 else None
    
    return avg_curr, delta