# benchmark.py

import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import folium
from folium.plugins import MarkerCluster

# ----------------------------
# Configuración general
# ----------------------------

EXCEL_PATH = r"C:\Users\julio\OneDrive\Documentos\Trabajo\Ideas Frescas\Proyectos\REM\BD\BD_Mazatlan.xlsm"
SHEET_VERTICAL = "Vertical"
SHEET_HORIZONTAL = "Horizontal"
SHEET_LOTE = "Lote"
SHEET_VENTAS = "Ventas"
SHEET_PRECIOS = "Precios"
SHEET_INFO_LOTE = "Info_Prototipos_lote"
SHEET_INFO_VERTICAL = "Info_Prototipos_vertical"
SHEET_INFO_HORIZONTAL = "Info_Prototipos_horizontal"

# Nombre de columna de proyecto en TODAS las hojas
COL_PROYECTO = "Nombre_desarrollo"
# Nombre de columna de estatus del proyecto en hojas Vertical/Horizontal/Lote
COL_ESTATUS = "Estatus_proyecto"

# Columna de fecha en la hoja de Ventas
COL_FECHA_VENTAS = "Fecha"
# Columnas en hoja Precios
COL_FECHA_PRECIOS = "Fecha"
COL_PRECIO_VIVIENDA = "Precio"

# Columna de m2 en hoja Precios
COL_M2_PRECIOS = "M2"

# ===============================================================================
# IDENTIDAD DE MARCA (COLORES Y TIPOGRAFÍA)
#    Nota: La paleta Picton Blue se aplica SOLO a las gráficas.
# ===============================================================================
COLORS = {
    "brown":       "#8B4513",   # madera
    "gold":        "#FD6A02",
    "white":       "#FFFFFF",
    "darkslate":   "#2F4F4F",
    "beige":       "#F5F5DC",
    "black":       "#000000",
    "light_brown": "#C19A6B",
    "dark_red":    "#8B0000",
}
TITLE_FONT = "Playfair Display, serif"   # Serif elegante (títulos)
BODY_FONT = "Lato, sans-serif"          # Sans moderna (cuerpo)
ALT_FONT = "Montserrat, sans-serif"     # Alternativa versátil

# Paleta Picton Blue (solo charts)
PICTON_BLUE = [
    "#eff8ff", "#dff0ff", "#b8e3ff", "#78cdff", "#38b6ff",
    "#069af1", "#007ace", "#0061a7", "#02528a", "#084572", "#062b4b"
]
# ===============================================================================
# Paleta especial para BUMP CHART (muchos colores bien diferenciados)
BUMP_COLORS = [
    "#e6194b", "#3cb44b", "#ffe119", "#4363d8",
    "#f58231", "#911eb4", "#46f0f0", "#f032e6",
    "#bcf60c", "#fabebe", "#008080", "#e6beff",
    "#9a6324", "#fffac8", "#800000", "#aaffc3",
    "#808000", "#ffd8b1", "#000075", "#808080",
]


# TEMA PLOTLY (APLICA SOLO A GRÁFICAS)
# ===============================================================================
def apply_charts_theme(fig: go.Figure, title: str | None = None) -> go.Figure:
    layout_updates = dict(
        font=dict(family=BODY_FONT, size=13, color=COLORS["white"]),
        paper_bgcolor=COLORS["black"],
        plot_bgcolor=COLORS["black"],
        margin=dict(l=10, r=10, t=60, b=10),
        legend=dict(
            title=None,
            orientation="h",
            yanchor="bottom", y=1.02,
            xanchor="left", x=0,
        ),
    )
    if title is not None:
        layout_updates["title"] = dict(text=title, x=0, xanchor="left")

    fig.update_layout(**layout_updates)
    return fig


# Defaults globales para px (SOLO afecta gráficas)
px.defaults.template = "plotly_dark"
px.defaults.color_discrete_sequence = PICTON_BLUE

SPANISH_MONTH_ABBR = {
    1: "Ene", 2: "Feb", 3: "Mar", 4: "Abr",
    5: "May", 6: "Jun", 7: "Jul", 8: "Ago",
    9: "Sep", 10: "Oct", 11: "Nov", 12: "Dic",
}


def format_periodo(fecha: pd.Timestamp | None) -> str:
    if fecha is None or pd.isna(fecha):
        return ""
    return f"{SPANISH_MONTH_ABBR[fecha.month]}-{fecha.year}"


@st.cache_data
def load_data():
    """Carga las hojas necesarias desde el Excel base."""
    xls = pd.ExcelFile(EXCEL_PATH)

    df_vertical = pd.read_excel(xls, SHEET_VERTICAL)
    df_horizontal = pd.read_excel(xls, SHEET_HORIZONTAL)
    df_lote = pd.read_excel(xls, SHEET_LOTE)
    df_ventas = pd.read_excel(xls, SHEET_VENTAS)
    df_precios = pd.read_excel(xls, SHEET_PRECIOS)
    df_info_lote = pd.read_excel(xls, SHEET_INFO_LOTE)
    df_info_vertical = pd.read_excel(xls, SHEET_INFO_VERTICAL)
    df_info_horizontal = pd.read_excel(xls, SHEET_INFO_HORIZONTAL)

    # Aseguramos que las columnas de fecha sean datetime
    if COL_FECHA_VENTAS in df_ventas.columns:
        df_ventas[COL_FECHA_VENTAS] = pd.to_datetime(df_ventas[COL_FECHA_VENTAS], errors="coerce")
    if COL_FECHA_PRECIOS in df_precios.columns:
        df_precios[COL_FECHA_PRECIOS] = pd.to_datetime(df_precios[COL_FECHA_PRECIOS], errors="coerce")

    # Convertimos precio a numérico por si viene con $ y comas
    if COL_PRECIO_VIVIENDA in df_precios.columns:
        df_precios[COL_PRECIO_VIVIENDA] = (
            df_precios[COL_PRECIO_VIVIENDA]
            .replace({r"[\$,]": ""}, regex=True)
            .astype(float)
        )

    return (
        df_vertical,
        df_horizontal,
        df_lote,
        df_ventas,
        df_precios,
        df_info_lote,
        df_info_vertical,
        df_info_horizontal,
    )


def get_df_by_tipo(tipo, df_vertical, df_horizontal, df_lote):
    """Devuelve el DF correcto según el tipo de proyecto."""
    if tipo == "Vertical":
        return df_vertical
    elif tipo == "Horizontal":
        return df_horizontal
    elif tipo == "Lote":
        return df_lote
    else:
        raise ValueError(f"Tipo de proyecto no reconocido: {tipo}")


def get_unidades_planeadas(row, tipo):
    """Obtiene 'unidades planeadas' según el tipo de proyecto."""
    if tipo == "Vertical":
        col = "Departamentos_planeados"
    elif tipo == "Horizontal":
        col = "Casas_planeados"
    else:  # Lote
        col = "Lotes_planeados"

    return row.get(col, 0)


def make_benchmark_map(df_bm, archivo_html="mapa_benchmark.html"):
    df = df_bm.copy()
     # Si no hay columnas de coordenadas, no se puede construir el mapa
    if not {"Latitud", "Longitud"}.issubset(df.columns):
        return None

    df = df.replace([np.inf, -np.inf], np.nan)
    df = df.dropna(subset=["Latitud", "Longitud"])

    if df.empty:
        return None

    # Centro del mapa
    lat_c = df["Latitud"].astype(float).mean()
    lon_c = df["Longitud"].astype(float).mean()

    m = folium.Map(location=[lat_c, lon_c], zoom_start=12, tiles="CartoDB positron")

    # Colores por zona
    zonas = df["Zona"].astype(str).unique().tolist()
    base_colors = [
        "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728",
        "#9467bd", "#8c564b", "#e377c2", "#7f7f7f",
        "#bcbd22", "#17becf"
    ]
    color_by_zona = {z: base_colors[i % len(base_colors)] for i, z in enumerate(zonas)}

    cluster = MarkerCluster().add_to(m)

    for _, r in df.iterrows():
        lat = float(r["Latitud"])
        lon = float(r["Longitud"])

        proyecto = r["Proyecto"]
        zona = str(r.get("Zona", "—"))
        precio = r.get("Precio actual", None)
        ventas = r.get("Ventas promedio último mes", None)
        m2_disp = r.get("m² promedio disponible", None)

        precio_txt = f"${precio:,.0f}" if pd.notna(precio) else "—"
        ventas_txt = f"{ventas:.2f}" if pd.notna(ventas) else "—"
        m2_txt = f"{m2_disp:.2f}" if pd.notna(m2_disp) else "—"

        popup_html = f"""
        <b>{proyecto}</b><br>
        Zona: {zona}<br>
        Precio promedio: {precio_txt}<br>
        Ventas último mes: {ventas_txt}<br>
        m² promedio disponible: {m2_txt}
        """

        color = color_by_zona.get(zona, "#3186cc")

        folium.CircleMarker(
            location=[lat, lon],
            radius=6,
            color=color,
            fill=True,
            fill_opacity=0.9,
            popup=folium.Popup(popup_html, max_width=300),
            tooltip=proyecto,
        ).add_to(cluster)

    # Leyenda
    legend_html = """
    <div style="
        position: fixed; bottom: 20px; left: 20px; z-index: 9999;
        background: white; padding: 10px 12px; border: 1px solid #ccc; border-radius: 8px;
        font-size: 13px; color:#000000;">
        <b>Zonas</b><br>
    """
    for z, c in color_by_zona.items():
        legend_html += (
            f'<span style="display:inline-block;width:12px;height:12px;'
            f'background:{c};margin-right:6px;border-radius:2px;"></span>{z}<br>'
        )
    legend_html += "</div>"
    m.get_root().html.add_child(folium.Element(legend_html))
    m.save(archivo_html)
    return m


def meses_diff(f_ini, f_fin):
    """Diferencia en meses enteros entre dos fechas."""
    if pd.isna(f_ini) or pd.isna(f_fin):
        return None
    return (f_fin.year - f_ini.year) * 12 + (f_fin.month - f_ini.month)


def compute_ventas_promedio_series(df_ventas, proyectos_seleccionados):
    """
    Calcula la serie histórica de 'ventas promedio último mes' por proyecto,
    usando la lógica de: Ventas_periodo / meses_entre_fechas.

    Cada fila tendrá:
      - Proyecto
      - Fecha (fin del periodo)
      - Ventas_promedio_ult_mes
      - Es_primer_registro (para marcar entrada del proyecto)
    """
    df = df_ventas[df_ventas[COL_PROYECTO].isin(proyectos_seleccionados)].copy()
    if df.empty:
        return pd.DataFrame(columns=["Proyecto", "Fecha", "Ventas_promedio_ult_mes", "Es_primer_registro"])

    df[COL_FECHA_VENTAS] = pd.to_datetime(df[COL_FECHA_VENTAS], errors="coerce")
    df["Ventas_periodo"] = pd.to_numeric(df["Ventas_periodo"], errors="coerce").fillna(0)

    df = df.sort_values([COL_PROYECTO, COL_FECHA_VENTAS])

    registros = []
    for proyecto, grp in df.groupby(COL_PROYECTO):
        grp = grp.sort_values(COL_FECHA_VENTAS)
        fechas = grp[COL_FECHA_VENTAS].tolist()
        ventas = grp["Ventas_periodo"].tolist()

        for i in range(len(grp)):
            if i == 0:
                diff_meses = 1
            else:
                diff_meses = meses_diff(fechas[i - 1], fechas[i])
                if not diff_meses or diff_meses <= 0:
                    diff_meses = 1

            prom = ventas[i] / diff_meses if diff_meses > 0 else ventas[i]

            registros.append(
                {
                    "Proyecto": proyecto,
                    "Fecha": fechas[i],
                    "Ventas_promedio_ult_mes": prom,
                    "Es_primer_registro": (i == 0),
                }
            )

    return pd.DataFrame(registros)


def get_precios_y_m2(
    proyecto,
    tipo,
    df_precios,
    df_info_lote,
    df_info_vertical,
    df_info_horizontal,
):
    """
    Calcula:
    - precio inicial (promedio de la primera fecha de precios, precios > 0)
    - precio final (promedio de la última fecha de precios, precios > 0)
    - m² promedio proyecto (de Info_Prototipo_*)
    - m² promedio disponible (en la última fecha de precios, prototipos con precio > 0)
    """

    # --------------------
    # PRECIOS (hoja Precios)
    # --------------------
    df_p = df_precios[df_precios[COL_PROYECTO] == proyecto].copy()

    precio_inicial = np.nan
    precio_final = np.nan
    m2_promedio_disponible = np.nan

    if not df_p.empty and COL_PRECIO_VIVIENDA in df_p.columns:

        # Aseguramos tipos numéricos
        df_p[COL_PRECIO_VIVIENDA] = pd.to_numeric(df_p[COL_PRECIO_VIVIENDA], errors="coerce")
        if COL_M2_PRECIOS in df_p.columns:
            df_p[COL_M2_PRECIOS] = pd.to_numeric(df_p[COL_M2_PRECIOS], errors="coerce")

        df_p = df_p.sort_values(COL_FECHA_PRECIOS)

        # ---- Precio inicial (primera fecha, solo precios > 0) ----
        fecha_min = df_p[COL_FECHA_PRECIOS].min()
        df_primera = df_p[df_p[COL_FECHA_PRECIOS] == fecha_min]
        df_primera_pos = df_primera[df_primera[COL_PRECIO_VIVIENDA] > 0]

        if not df_primera_pos.empty:
            precio_inicial = df_primera_pos[COL_PRECIO_VIVIENDA].mean()

        # ---- Precio final (última fecha, solo precios > 0) ----
        fecha_max = df_p[COL_FECHA_PRECIOS].max()
        df_ultima = df_p[df_p[COL_FECHA_PRECIOS] == fecha_max]
        df_ultima_pos = df_ultima[df_ultima[COL_PRECIO_VIVIENDA] > 0]

        if not df_ultima_pos.empty:
            precio_final = df_ultima_pos[COL_PRECIO_VIVIENDA].mean()

            # ---- m² promedio disponible (última fecha, precios > 0) ----
            if COL_M2_PRECIOS in df_ultima_pos.columns:
                m2_promedio_disponible = df_ultima_pos[COL_M2_PRECIOS].mean()

    # --------------------
    # METROS CUADRADOS PROMEDIO PROYECTO (Info_Prototipo_*)
    # --------------------
    if tipo == "Lote":
        df_info = df_info_lote
        col_m2 = "Medida_terreno"
    elif tipo == "Vertical":
        df_info = df_info_vertical
        col_m2 = "Medida_construcción"
    else:  # Horizontal
        df_info = df_info_horizontal
        col_m2 = "Medida_construcción"

    m2_promedio = np.nan
    if col_m2 in df_info.columns:
        df_i = df_info[df_info[COL_PROYECTO] == proyecto]
        if not df_i.empty:
            m2_promedio = pd.to_numeric(df_i[col_m2], errors="coerce").mean()

    return precio_inicial, precio_final, m2_promedio, m2_promedio_disponible


def compute_kpis_periodo(df_bm, df_ventas, df_series, proyectos, fecha_objetivo):
    """
    Calcula KPIs para un periodo específico usando:
    - df_bm: info estática de proyectos (meses, unidades, precios, m², etc.)
    - df_ventas: corte de inventario / ventas a la fecha objetivo
    - df_series: series de ventas promedio último mes por proyecto (para ese periodo)
    """
    if fecha_objetivo is None:
        return [None] * 11  # mismos KPIs, todos nulos

    # --------------------------
    # 1) KPIs estáticos (no cambian por periodo)
    # --------------------------
    kpi_meses = df_bm["Meses en venta"].mean()
    kpi_unidades = df_bm["Unidades planeadas"].sum()

    # --------------------------
    # 2) Corte de ventas en la fecha objetivo
    # --------------------------
    df_v = df_ventas[
        (df_ventas[COL_PROYECTO].isin(proyectos)) &
        (df_ventas[COL_FECHA_VENTAS] == fecha_objetivo)
    ].copy()

    if df_v.empty:
        # No hay datos en ese periodo: devolvemos los estáticos y el resto en None/0
        kpi_pi = df_bm["Precio inicial"].mean()
        kpi_pf = df_bm["Precio actual"].mean()
        kpi_m2 = df_bm["m² promedio proyecto"].mean()
        kpi_m2d = df_bm["m² promedio disponible"].mean()
        return [
            kpi_meses,
            kpi_unidades,
            0,          # oferta disponible
            0,          # oferta vendida
            None,       # % vendido
            None,       # ritmo hist
            None,       # ventas prom ult mes
            kpi_pi,
            kpi_pf,
            kpi_m2,
            kpi_m2d,
        ]

    # Convertimos columnas numéricas clave
    for col in ["Inventario_disponible", "Ventas_acumuladas", "Ventas_periodo"]:
        if col in df_v.columns:
            df_v[col] = pd.to_numeric(df_v[col], errors="coerce").fillna(0)

    # --------------------------
    # 3) Oferta disponible y vendida (suma en el periodo)
    # --------------------------
    kpi_disp = df_v["Inventario_disponible"].sum() if "Inventario_disponible" in df_v.columns else 0
    kpi_vendida = df_v["Ventas_acumuladas"].sum() if "Ventas_acumuladas" in df_v.columns else 0

    # % vendido
    kpi_pct = (kpi_vendida / kpi_unidades * 100) if kpi_unidades and kpi_unidades > 0 else None

    # --------------------------
    # 4) Ritmo mensual ventas históricas (hasta ese periodo)
    #    ritmo_proy = Ventas_acumuladas_periodo / Meses_venta
    # --------------------------
    if "Ventas_acumuladas" in df_v.columns:
        df_va = (
            df_v.groupby(COL_PROYECTO, as_index=False)["Ventas_acumuladas"]
            .sum()
        )

        df_merge_ritmo = df_bm[["Proyecto", "Meses en venta"]].merge(
            df_va,
            left_on="Proyecto",
            right_on=COL_PROYECTO,
            how="left",
        )

        df_merge_ritmo["Ventas_acumuladas"] = pd.to_numeric(
            df_merge_ritmo["Ventas_acumuladas"], errors="coerce"
        ).fillna(0)
        df_merge_ritmo["Meses en venta"] = pd.to_numeric(
            df_merge_ritmo["Meses en venta"], errors="coerce"
        ).fillna(0)

        df_merge_ritmo["Ritmo"] = np.where(
            df_merge_ritmo["Meses en venta"] > 0,
            df_merge_ritmo["Ventas_acumuladas"] / df_merge_ritmo["Meses en venta"],
            df_merge_ritmo["Ventas_acumuladas"],
        )
        kpi_ritmo = df_merge_ritmo["Ritmo"].mean()
    else:
        kpi_ritmo = None

    # --------------------------
    # 5) Ventas promedio último mes (usando df_series para esa fecha)
    # --------------------------
    df_sp = df_series[df_series["Fecha"] == fecha_objetivo].copy()
    df_sp["Ventas_promedio_ult_mes"] = pd.to_numeric(
        df_sp["Ventas_promedio_ult_mes"], errors="coerce"
    )

    kpi_ult_mes = df_sp["Ventas_promedio_ult_mes"].mean() if not df_sp.empty else None

    # --------------------------
    # 6) Precios y m² (promedio de df_bm, estáticos)
    # --------------------------
    kpi_pi = df_bm["Precio inicial"].mean()
    kpi_pf = df_bm["Precio actual"].mean()
    kpi_m2 = df_bm["m² promedio proyecto"].mean()
    kpi_m2d = df_bm["m² promedio disponible"].mean()

    return [
        kpi_meses,
        kpi_unidades,
        kpi_disp,
        kpi_vendida,
        kpi_pct,
        kpi_ritmo,
        kpi_ult_mes,
        kpi_pi,
        kpi_pf,
        kpi_m2,
        kpi_m2d,
    ]


def build_benchmark_df(
    tipo,
    proyectos_seleccionados,
    df_vertical,
    df_horizontal,
    df_lote,
    df_ventas,
    df_precios,
    df_info_lote,
    df_info_vertical,
    df_info_horizontal,
):
    """Construye el DataFrame con los KPIs de benchmark para los proyectos seleccionados."""
    df_base = get_df_by_tipo(tipo, df_vertical, df_horizontal, df_lote)

    registros = []

    for proyecto in proyectos_seleccionados:
        # Fila(s) del proyecto en la hoja correspondiente
        df_proj = df_base[df_base[COL_PROYECTO] == proyecto]

        if df_proj.empty:
            continue

        # Suponemos que hay una fila por proyecto. Si hay varias, tomamos la primera.
        row_proj = df_proj.iloc[0]

        # --------------------------
        # 1. Fechas y meses en venta
        # --------------------------
        fecha_inicio = row_proj.get("Fecha_inicio_venta", pd.NaT)
        fecha_fin = row_proj.get("Fecha_fin_ventas", pd.NaT)  # si no se ha vendido, estará vacío/NaT
        meses_venta = row_proj.get("Meses_venta", 0)

        # --------------------------
        # 2. Unidades planeadas
        # --------------------------
        unidades_planeadas = get_unidades_planeadas(row_proj, tipo)

        # --------------------------
        # 3. Estatus del proyecto
        # --------------------------
        estatus = row_proj.get(COL_ESTATUS, None)
        estatus_str = str(estatus).strip().lower() if estatus is not None else ""

        # --------------------------
        # 4. Datos desde hoja Ventas
        # --------------------------
        df_vent = df_ventas[df_ventas[COL_PROYECTO] == proyecto].copy()
        df_vent = df_vent.sort_values(COL_FECHA_VENTAS)

        if df_vent.empty:
            oferta_disponible = 0
            oferta_vendida = 0
            ritmo_mensual_hist = 0
            ventas_prom_ult_mes = 0
        else:
            ultima = df_vent.iloc[-1]

            # oferta disponible
            if "vendido" in estatus_str:
                oferta_disponible = 0
            else:
                oferta_disponible = ultima.get("Inventario_disponible", 0)

            # oferta vendida
            if "vendido" in estatus_str:
                oferta_vendida = unidades_planeadas
            else:
                oferta_vendida = ultima.get("Ventas_acumuladas", 0)

            # ritmo mensual ventas históricas
            if meses_venta and meses_venta > 0:
                ritmo_mensual_hist = oferta_vendida / meses_venta
            else:
                ritmo_mensual_hist = oferta_vendida

            # ventas promedio último mes
            ventas_periodo = ultima.get("Ventas_periodo", 0)

            if len(df_vent) >= 2:
                penultima = df_vent.iloc[-2]
                f_ult = ultima[COL_FECHA_VENTAS]
                f_pen = penultima[COL_FECHA_VENTAS]

                diff_meses = meses_diff(f_pen, f_ult)
                if diff_meses is None or diff_meses == 0:
                    diff_meses = 1
            else:
                diff_meses = 1

            ventas_prom_ult_mes = ventas_periodo / diff_meses if diff_meses > 0 else ventas_periodo

        # --------------------------
        # 5. % vendido
        # --------------------------
        if unidades_planeadas and unidades_planeadas > 0:
            if "vendido" in estatus_str:
                porcentaje_vendido = 1.0
            else:
                porcentaje_vendido = oferta_vendida / unidades_planeadas
        else:
            porcentaje_vendido = None

        # --------------------------
        # 6. Precio inicial, precio final, m²
        # --------------------------
        precio_inicial, precio_final, m2_promedio, m2_disp_prom = get_precios_y_m2(
            proyecto,
            tipo,
            df_precios,
            df_info_lote,
            df_info_vertical,
            df_info_horizontal,
        )

        # --------------------------
        # 7. Zona del proyecto
        # --------------------------
        zona = row_proj.get("Zona", None)

        # --------------------------
        # 8. Estatus del proyecto
        # --------------------------
        Estatus_venta = row_proj.get("Estatus_venta", None)

        registros.append(
            {
                "Proyecto": proyecto,
                "Fecha inicio preventa": fecha_inicio,
                "Fecha fin venta": fecha_fin,
                "Meses en venta": meses_venta,
                "Unidades planeadas": unidades_planeadas,
                "Oferta disponible": oferta_disponible,
                "Oferta vendida": oferta_vendida,
                "% vendido": porcentaje_vendido,
                "Ritmo mensual ventas históricas": ritmo_mensual_hist,
                "Ventas promedio último mes": ventas_prom_ult_mes,
                "Precio inicial": precio_inicial,
                "Precio actual": precio_final,
                "m² promedio proyecto": m2_promedio,
                "m² promedio disponible": m2_disp_prom,
                "Zona": zona,
                "Estatus venta": Estatus_venta,
            }
        )

    df_result = pd.DataFrame(registros)

    # Formateo básico
    if not df_result.empty and "% vendido" in df_result.columns:
        df_result["% vendido"] = df_result["% vendido"] * 100  # porcentaje

    return df_result


def fmt_num(x, dec=1):
    if pd.isna(x):
        return "-"
    return f"{x:,.{dec}f}"


def fmt_int(x):
    if pd.isna(x):
        return "-"
    return f"{x:,.0f}"


def fmt_money(x, dec=0):
    if pd.isna(x):
        return "-"
    return f"${x:,.{dec}f}"


def benchmark_page():
    st.header("Benchmark de Proyectos")

    st.markdown(
        """
        **Crea tu propio Benchmark**.
        
        1. Selecciona el **tipo de proyecto** (Vertical, Horizontal o Lote).  
        2. Selecciona uno o varios proyectos para incluir en el benchmark.  
        """
    )

    (
        df_vertical,
        df_horizontal,
        df_lote,
        df_ventas,
        df_precios,
        df_info_lote,
        df_info_vertical,
        df_info_horizontal,
    ) = load_data()

    # ----------------------------
    # Selección de tipo de proyecto
    # ----------------------------
    tipo = st.radio(
        "Tipo de proyecto a analizar:",
        options=["Vertical", "Horizontal", "Lote"],
        horizontal=True,
    )

    df_tipo = get_df_by_tipo(tipo, df_vertical, df_horizontal, df_lote)

    proyectos_disponibles = sorted(df_tipo[COL_PROYECTO].dropna().unique().tolist())

    proyectos_seleccionados = st.multiselect(
        "Selecciona los proyectos a incluir en el benchmark:",
        options=proyectos_disponibles,
    )

    if not proyectos_seleccionados:
        st.info("Selecciona al menos un proyecto para ver el benchmark.")
        return

    # ----------------------------
    # Construcción del DF base
    # ----------------------------
    df_bm = build_benchmark_df(
        tipo,
        proyectos_seleccionados,
        df_vertical,
        df_horizontal,
        df_lote,
        df_ventas,
        df_precios,
        df_info_lote,
        df_info_vertical,
        df_info_horizontal,
    )

    # Añadir geolocalización UNA sola vez
    geo_cols = [COL_PROYECTO, "Latitud", "Longitud"]
    geo_cols = [c for c in geo_cols if c in df_tipo.columns]

    if geo_cols:
        df_geo = df_tipo[geo_cols].copy()
        df_bm = df_bm.merge(
            df_geo,
            left_on="Proyecto",
            right_on=COL_PROYECTO,
            how="left",
        )

    if df_bm.empty:
        st.warning("No se pudo construir el benchmark con la información disponible.")
        return

    # ----------------------------
    # Aseguramos numéricos
    # ----------------------------
    num_cols = [
        "Meses en venta",
        "Unidades planeadas",
        "Oferta disponible",
        "Oferta vendida",
        "% vendido",
        "Ritmo mensual ventas históricas",
        "Ventas promedio último mes",
        "Precio inicial",
        "Precio actual",
        "m² promedio proyecto",
        "m² promedio disponible",
    ]
    for col in num_cols:
        if col in df_bm.columns:
            df_bm[col] = pd.to_numeric(df_bm[col], errors="coerce")

    # ----------------------------
    # Series históricas
    # ----------------------------
    df_series = compute_ventas_promedio_series(df_ventas, proyectos_seleccionados)

    # ============================
    # Layout c1 (KPIs) / c2 (Mapa)
    # ============================
    c1, c2 = st.columns(2)

    # ------------------------------------------
    # C1 — TABLA DE INDICADORES (corregida)
    # ------------------------------------------
    with c1:

        st.subheader("Indicadores principales de proyectos seleccionados")

        df_v_sel = df_ventas[df_ventas[COL_PROYECTO].isin(proyectos_seleccionados)].copy()
        df_v_sel[COL_FECHA_VENTAS] = pd.to_datetime(df_v_sel[COL_FECHA_VENTAS], errors="coerce")
        df_v_sel = df_v_sel.dropna(subset=[COL_FECHA_VENTAS])

        fechas_orden = sorted(df_v_sel[COL_FECHA_VENTAS].unique())

        f0 = fechas_orden[-1] if len(fechas_orden) >= 1 else None
        f1 = fechas_orden[-2] if len(fechas_orden) >= 2 else None
        f2 = fechas_orden[-3] if len(fechas_orden) >= 3 else None

        periodos = [f0, f1, f2]
        periodos_fmt = [format_periodo(x) for x in periodos]

        kpis_por_periodo = [
            compute_kpis_periodo(df_bm, df_ventas,df_series, proyectos_seleccionados, f0),
            compute_kpis_periodo(df_bm, df_ventas,df_series, proyectos_seleccionados, f1),
            compute_kpis_periodo(df_bm, df_ventas,df_series, proyectos_seleccionados, f2),
        ]

        indicadores = [
            "Promedio meses en venta",
            "Unidades planeadas (suma)",
            "Oferta disponible (suma)",
            "Oferta vendida (suma)",
            "% vendido (promedio)",
            "Ritmo mensual ventas históricas (prom)",
            "Ventas promedio último mes",
            "Precio inicial promedio",
            "Precio actual promedio",
            "m² promedio proyecto",
            "m² promedio disponible",
        ]

        df_kpis = pd.DataFrame(
            {
                "Indicador": indicadores,
                periodos_fmt[0]: kpis_por_periodo[0],
                periodos_fmt[1]: kpis_por_periodo[1],
                periodos_fmt[2]: kpis_por_periodo[2],
            }
        )

        def fmt_val(v):
            if v is None or pd.isna(v):
                return "-"
            if abs(v) > 100000:
                return f"${v:,.0f}"
            return f"{v:,.2f}"

        df_kpis_fmt = df_kpis.copy()
        for c in df_kpis_fmt.columns:
            if c != "Indicador":
                df_kpis_fmt[c] = df_kpis_fmt[c].apply(fmt_val)

        st.dataframe(df_kpis_fmt, use_container_width=True)

    # ------------------------------------------
    # C2 — MAPA (corregido)
    # ------------------------------------------
    with c2:
        st.subheader("Mapa de ubicaciones de proyectos seleccionados")

        m = make_benchmark_map(df_bm)

        if m is None:
            st.info("Los proyectos seleccionados no tienen coordenadas suficientes para mostrar el mapa.")
        else:
            from streamlit_folium import st_folium
            st_folium(m, width=900, height=400)


    # ==========================
    # GRÁFICAS (c13, c14)
    # ==========================
    c13, c14 = st.columns(2)

    # ------------------------------
    # c13: Pie / donut de participación por proyecto
    # ------------------------------
    with c13:
    # =============================
    # Participación solo del último periodo real
    # =============================

        # Asegurar fechas limpias desde df_series
        df_series_local = df_series.copy()
        df_series_local["Fecha"] = pd.to_datetime(df_series_local["Fecha"], errors="coerce")
        df_series_local = df_series_local.dropna(subset=["Fecha"])

        if df_series_local.empty:
            st.info("No hay datos suficientes para graficar.")
        else:
            # Última fecha real
            ultima_fecha = df_series_local["Fecha"].max()
            periodo_label = format_periodo(ultima_fecha)

            st.markdown(f"#### Participación en ventas del último mes - {periodo_label}")

            # Filtrar solo datos del último periodo
            df_ultimo = df_series_local[df_series_local["Fecha"] == ultima_fecha].copy()

            # Formar estructura equivalente a df_pie original
            df_pie = (
                df_ultimo.groupby("Proyecto", as_index=False)["Ventas_promedio_ult_mes"]
                .mean()
                .rename(columns={"Ventas_promedio_ult_mes": "Ventas promedio último mes"})
            )

            # Solo proyectos con ventas > 0
            df_pie = df_pie[df_pie["Ventas promedio último mes"] > 0]

            if df_pie.empty:
                st.info("No hay proyectos con ventas en el último mes.")
            else:
                # === aquí pones tu código ORIGINAL DEL GRÁFICO PIE/BARRAS ===
           

                total = df_pie["Ventas promedio último mes"].sum()
                df_pie["Participación_%"] = df_pie["Ventas promedio último mes"] / total * 100

                # Ordenar de mayor a menor participación
                df_pie = df_pie.sort_values("Participación_%", ascending=False)

                # ==============================
                # CASO 1: 5 proyectos o menos → DONA
                # ==============================
                if len(df_pie) <= 5:
                    donut_colors = [
                        "#FFE697",
                        "#FFD85B",
                        "#FFC000",
                        "#F3B700",
                        "#DAA400",
                    ]
                    colors = donut_colors[: len(df_pie)]

                    fig_pie = px.pie(
                        df_pie,
                        names="Proyecto",
                        values="Ventas promedio último mes",
                        hole=0.60,
                    )

                    fig_pie.update_traces(
                        sort=False,  # respetar el orden del DataFrame
                        marker=dict(colors=colors),
                        texttemplate="%{percent:.0%}",  # solo el porcentaje grande
                        textposition="inside",
                        hovertemplate=(
                            "<b>%{label}</b><br>"
                            "Participación: %{percent:.1%}<br>"
                            "Ventas prom. último mes: %{value:,.2f}<extra></extra>"
                        ),
                    )

                    # fig_pie = apply_charts_theme(fig_pie)
                    st.plotly_chart(fig_pie, use_container_width=True)

                    # Top 3 proyectos
                    top3 = df_pie.sort_values("Participación_%", ascending=False).head(3)
                    txt_top = ", ".join(
                        f"{row['Proyecto']} ({row['Participación_%']:,.1f}%)"
                        for _, row in top3.iterrows()
                    )
                    st.caption(f"Top 3 proyectos por participación: {txt_top}")

                    # Data a exportar (tal cual se ve)
                    df_export = df_pie[["Proyecto", "Ventas promedio último mes", "Participación_%"]].copy()

                # ==============================
                # CASO 2: más de 5 proyectos → BARRAS
                # ==============================
                else:
                    df_bar = df_pie.copy()  # ya viene ordenado de mayor a menor

                    if len(df_bar) > 10:
                        top9 = df_bar.head(9).copy()
                        resto = df_bar.iloc[9:].copy()

                        resto_row = pd.DataFrame(
                            {
                                "Proyecto": ["Resto de proyectos"],
                                "Ventas promedio último mes": [resto["Ventas promedio último mes"].sum()],
                                "Participación_%": [resto["Participación_%"].sum()],
                            }
                        )
                        df_bar = pd.concat([top9, resto_row], ignore_index=True)

                    # aseguramos orden de mayor a menor
                    df_bar = df_bar.sort_values("Participación_%", ascending=False)
                    categoria_orden = df_bar["Proyecto"].tolist()

                    fig_bar = px.bar(
                        df_bar,
                        x="Proyecto",
                        y="Participación_%",
                        text="Participación_%",
                    )
                    fig_bar.update_traces(
                        marker_color="#8EB4E3",
                        texttemplate="%{y:.1f} %",
                        hovertemplate=(
                            "<b>%{x}</b><br>"
                            "Participación: %{y:.1f}%<br>"
                            "Ventas prom. último mes: %{customdata:,.2f}<extra></extra>"
                        ),
                        customdata=df_bar["Ventas promedio último mes"],
                    )

                    fig_bar.update_layout(
                        xaxis_title=None,
                        yaxis_title="% de participación en ventas",
                    )
                    fig_bar.update_xaxes(
                        categoryorder="array",
                        categoryarray=categoria_orden,
                    )

                    # fig_bar = apply_charts_theme(fig_bar)
                    st.plotly_chart(fig_bar, use_container_width=True)

                    # Top 3 proyectos
                    top3 = df_pie.sort_values("Participación_%", ascending=False).head(3)
                    txt_top = ", ".join(
                        f"{row['Proyecto']} ({row['Participación_%']:,.1f}%)"
                        for _, row in top3.iterrows()
                    )
                    st.caption(f"Top 3 proyectos por participación: {txt_top}")

                    df_export = df_bar[["Proyecto", "Ventas promedio último mes", "Participación_%"]]

            # Botón para descargar el CSV de lo que se está graficando
            csv_pie = df_export.to_csv(index=False).encode("utf-8")
            st.download_button(
                label="Descargar datos de participación (CSV)",
                data=csv_pie,
                file_name="participacion_ventas_ultimo_mes.csv",
                mime="text/csv",
            )

    # ------------------------------
    # Preparar series históricas para c14 y gráficas siguientes
    # (ya tenemos df_series calculado arriba)
    # ------------------------------

    # ------------------------------
    # c14: Barras agrupadas – participación por periodo (últimos 3)
    # ------------------------------
    with c14:
        st.markdown("#### Participación en ventas del último mes (últimos 3 periodos)")

        if df_series.empty:
            st.info("No hay historial suficiente de ventas para graficar.")
        else:
            # Aseguramos fechas limpias
            df_series_local = df_series.copy()
            df_series_local["Fecha"] = pd.to_datetime(df_series_local["Fecha"], errors="coerce")
            df_series_local = df_series_local.dropna(subset=["Fecha"])

            # Tomar las 3 últimas fechas únicas
            fechas_unicas = sorted(df_series_local["Fecha"].unique())
            if not fechas_unicas:
                st.info("No hay fechas válidas para graficar.")
            else:
                ultimas_fechas = fechas_unicas[-3:]  # si hay menos de 3, Python ya devuelve solo las disponibles

                df_3p = df_series_local[df_series_local["Fecha"].isin(ultimas_fechas)].copy()

                # Ventas promedio último mes por proyecto y fecha
                df_3p = (
                    df_3p.groupby(["Fecha", "Proyecto"], as_index=False)["Ventas_promedio_ult_mes"]
                    .mean()
                )

                # Totales por fecha para calcular el %
                totales = (
                    df_3p.groupby("Fecha", as_index=False)["Ventas_promedio_ult_mes"]
                    .sum()
                    .rename(columns={"Ventas_promedio_ult_mes": "Total_fecha"})
                )
                df_3p = df_3p.merge(totales, on="Fecha", how="left")
                df_3p["Participación_%"] = (
                    df_3p["Ventas_promedio_ult_mes"] / df_3p["Total_fecha"] * 100
                )

                # Etiqueta de periodo (Ene-2025, Ago-2025, etc.)
                df_3p["Periodo"] = df_3p["Fecha"].apply(format_periodo)

                # Ordenar periodos de más antiguo a más reciente
                periodos_orden = [format_periodo(f) for f in ultimas_fechas]
                df_3p["Periodo"] = pd.Categorical(
                    df_3p["Periodo"],
                    categories=periodos_orden,
                    ordered=True,
                )

                # ==============================
                # Limitar número de proyectos a mostrar
                # ==============================
                proyectos_unicos = sorted(df_3p["Proyecto"].unique().tolist())

                # Periodo más reciente (último en periodos_orden)
                periodo_mas_reciente = periodos_orden[-1] if len(periodos_orden) > 0 else None

                if len(proyectos_unicos) > 8 and periodo_mas_reciente is not None:
                    # Tomar participación del periodo más reciente
                    df_actual = df_3p[df_3p["Periodo"] == periodo_mas_reciente].copy()
                    df_actual = df_actual.sort_values("Participación_%", ascending=False)

                    top_default = df_actual["Proyecto"].head(10).tolist()

                    st.markdown(
                        f"> Hay **{len(proyectos_unicos)} proyectos** en el benchmark. "
                        "Para una mejor lectura, selecciona hasta **10** proyectos para comparar."
                    )

                    proyectos_seleccionados_c14 = st.multiselect(
                        "Proyectos a mostrar en la comparación de periodos:",
                        options=proyectos_unicos,
                        default=top_default,
                        max_selections=10,
                    )

                    if proyectos_seleccionados_c14:
                        df_3p = df_3p[df_3p["Proyecto"].isin(proyectos_seleccionados_c14)]
                    else:
                        # Si despejan todo, no mostramos nada
                        st.info("Selecciona al menos un proyecto para mostrar la gráfica.")
                        df_3p = df_3p.iloc[0:0]  # dataframe vacío
                else:
                    # Si son pocos proyectos, mostramos todos sin selector
                    proyectos_seleccionados_c14 = proyectos_unicos

                if df_3p.empty:
                    st.info("No hay suficientes datos para graficar la comparación por proyecto.")
                else:
                    # ==========================
                    # BUMP CHART (ranking)
                    # ==========================
                    df_3p = df_3p.copy()

                    # 1) Traer el ritmo mensual histórico desde df_bm
                    df_3p = df_3p.merge(
                        df_bm[["Proyecto", "Ritmo mensual ventas históricas"]],
                        on="Proyecto",
                        how="left",
                    )
                    df_3p.rename(
                        columns={"Ritmo mensual ventas históricas": "Ritmo_hist"},
                        inplace=True,
                    )

                    # 2) Ordenar aplicando criterios de desempate:
                    #    1) Participación_% (mayor es mejor)
                    #    2) Ritmo_hist (mayor es mejor)
                    #    3) Ventas_promedio_ult_mes (mayor es mejor)
                    df_3p = df_3p.sort_values(
                        ["Periodo", "Participación_%", "Ritmo_hist", "Ventas_promedio_ult_mes"],
                        ascending=[True, False, False, False],
                    )

                    # 3) Rank oficial = posición después de ordenar
                    df_3p["Rank"] = df_3p.groupby("Periodo").cumcount() + 1

                    # Para la gráfica usamos Rank (el que ya rompe empates)
                    df_sorted = df_3p.sort_values(["Proyecto", "Periodo"]).copy()
                    df_sorted["Rank_label"] = df_sorted["Rank"].astype(str)

                    # 4) Crear bump chart con custom_data bien alineado
                    fig_bump = px.line(
                        df_sorted,
                        x="Periodo",
                        y="Rank",
                        color="Proyecto",
                        markers=True,
                        color_discrete_sequence=BUMP_COLORS,
                        text="Rank_label",  # el número que se ve al lado del punto
                        custom_data=[
                            "Proyecto",
                            "Rank",
                            "Participación_%",
                            "Ventas_promedio_ult_mes",
                            "Ritmo_hist",
                        ],
                    )

                    fig_bump.update_traces(
                        textposition="top center",
                        marker=dict(size=12, line=dict(width=2, color="white")),
                        line=dict(width=4),
                        hovertemplate=(
                            "<b>%{customdata[0]}</b><br>"
                            "Periodo: %{x}<br>"
                            "Rank: %{customdata[1]}<br>"
                            "Participación: %{customdata[2]:.1f}%<br>"
                            "Ventas prom. último mes: %{customdata[3]:,.2f}<br>"
                            "Ritmo mensual histórico: %{customdata[4]:,.2f}"
                            "<extra></extra>"
                        ),
                    )
 
                    max_rank = df_sorted["Rank"].max()
                    fig_bump.update_yaxes(
                        autorange="reversed",
                        dtick=1,
                        range=[0.5, max_rank + 0.5],
                        title_text="Posición en el ranking",
                        showgrid=True,
                        gridcolor="rgba(128,128,128,0.2)",
                    )
                    fig_bump.update_xaxes(title_text="Periodo")

                    fig_bump.update_layout(
                        legend=dict(
                            orientation="v",       # vertical
                            yanchor="top",
                            y=1,
                            xanchor="left",
                            x=1.02,                # mueve la leyenda justo afuera de la gráfica (lado derecho)
                            bgcolor="rgba(0,0,0,0)", # fondo transparente
                            bordercolor="rgba(255,255,255,0.2)",
                            borderwidth=1,
                            font=dict(size=12),
                            itemwidth=30,
                        )
                    )
                    fig_bump.update_layout(
                        legend_title_text='Proyectos',
                        hovermode="closest" # Opcional: Esto ayuda a comparar todos los ranks en un solo hover
                    )
                    st.plotly_chart(fig_bump, use_container_width=True)
                    # ==========================
                    # CSV descargable
                    # ==========================
                    df_export_c14 = df_3p[
                        ["Periodo", "Proyecto", "Rank", "Participación_%", "Ventas_promedio_ult_mes", "Ritmo_hist"]
                    ].sort_values(["Periodo", "Rank"])

                    csv_c14 = df_export_c14.to_csv(index=False).encode("utf-8")
                    st.download_button(
                        label="Descargar ranking últimos 3 periodos (CSV)",
                        data=csv_c14,
                        file_name="ranking_ultimos_3_periodos.csv",
                        mime="text/csv",
                    )



    # ------------------------------
    # Línea – promedio general de ventas promedio último mes
    # ------------------------------
    st.markdown("#### Evolución promedio de ventas del último mes (todos los proyectos)")

    if df_series.empty:
        st.info("No hay historial suficiente de ventas para graficar.")
    else:
        # ==========================
        # Serie principal: promedio por fecha
        # ==========================
        df_total = (
            df_series.groupby("Fecha", as_index=False)["Ventas_promedio_ult_mes"]
            .mean()
            .sort_values("Fecha")
        )
        df_total["Ventas_promedio_ult_mes"] = pd.to_numeric(
            df_total["Ventas_promedio_ult_mes"], errors="coerce"
        )

        # % cambio vs periodo anterior
        df_total["Pct_change"] = df_total["Ventas_promedio_ult_mes"].pct_change() * 100

        # ==========================
        # Entradas de proyectos → estrellas numeradas
        # ==========================
        primeros = (
            df_series[df_series["Es_primer_registro"]]
            .groupby("Proyecto", as_index=False)["Fecha"]
            .min()
        )

        # Agrupar por fecha (varios proyectos pueden entrar el mismo mes)
        entradas = (
            primeros.groupby("Fecha")["Proyecto"]
            .apply(list)
            .reset_index()
            .sort_values("Fecha")
        )
        entradas["Marca"] = range(1, len(entradas) + 1)  # 1,2,3,...

        # ==========================
        # Construcción de la figura
        # ==========================
        fig_line_avg = go.Figure()

        # --- Trazo 1: ventas promedio último mes (línea principal) ---
        fig_line_avg.add_trace(
            go.Scatter(
                x=df_total["Fecha"],
                y=df_total["Ventas_promedio_ult_mes"],
                mode="lines+markers+text",
                name="Ventas prom. último mes",
                text=[f"{v:.1f}" if not pd.isna(v) else "" for v in df_total["Ventas_promedio_ult_mes"]],
                textposition="top center",
                hovertemplate=(
                    "Fecha: %{x|%b %Y}<br>"
                    "Ventas prom. último mes: %{y:,.2f}<extra></extra>"
                ),
            )
        )

        # --- Trazo 2: % cambio vs periodo anterior (línea punteada, eje derecho) ---
        fig_line_avg.add_trace(
            go.Scatter(
                x=df_total["Fecha"],
                y=df_total["Pct_change"],
                mode="lines+markers",
                name="% cambio vs periodo anterior",
                line=dict(dash="dot"),
                yaxis="y2",
                hovertemplate=(
                    "Fecha: %{x|%b %Y}<br>"
                    "Variación: %{y:.1f}%<extra></extra>"
                ),
            )
        )

        # --- Trazos de estrellas (entradas de proyectos) ---
        max_y = df_total["Ventas_promedio_ult_mes"].max()

        for _, row in entradas.iterrows():
            # y del punto en esa fecha (si existe), si no usar max_y
            y_val = df_total.loc[df_total["Fecha"] == row["Fecha"], "Ventas_promedio_ult_mes"]
            y_plot = y_val.iloc[0] if not y_val.empty else max_y

            fig_line_avg.add_trace(
                go.Scatter(
                    x=[row["Fecha"]],
                    y=[y_plot],
                    mode="markers+text",
                    marker_symbol="star",
                    marker_size=16,
                    marker_color="#FFC000",
                    text=[str(row["Marca"])],      # número de la estrella
                    textposition="bottom center",
                    name=f"Ingreso #{row['Marca']}",
                    hovertemplate=(
                        f"Ingreso #{row['Marca']}<br>"
                        "Fecha: %{x|%b %Y}<extra></extra>"
                    ),
                    showlegend=False,
                )
            )

        # Layout: ejes y títulos
        fig_line_avg.update_layout(
            xaxis_title="Fecha",
            yaxis=dict(title="Ventas promedio último mes"),
            yaxis2=dict(
                title="% cambio vs periodo anterior",
                overlaying="y",
                side="right",
                showgrid=False,
            ),
        )

        fig_line_avg = apply_charts_theme(fig_line_avg)
        col_graf, col_tabla = st.columns([5, 3])

        # ------------------------------
        # IZQUIERDA → GRÁFICA
        # ------------------------------
        with col_graf:
            st.plotly_chart(fig_line_avg, use_container_width=True)

        # ------------------------------
        # DERECHA → TABLA DE ESTRELLAS
        # ------------------------------
        with col_tabla:
            if not entradas.empty:
                legend_df = entradas.copy()
                legend_df["Fecha"] = legend_df["Fecha"].dt.strftime("%b-%Y")
                legend_df["Proyectos que ingresan"] = legend_df["Proyecto"].apply(
                    lambda lst: ", ".join(lst)
                )
                legend_df = legend_df[["Marca", "Fecha", "Proyectos que ingresan"]]

                st.markdown("##### Ingresos por ⭐")
                st.table(legend_df)

        # ==========================
        # CSV descargable (incluye % cambio)
        # ==========================
        csv_total = df_total.to_csv(index=False).encode("utf-8")
        st.download_button(
            label="Descargar serie promedio (CSV)",
            data=csv_total,
            file_name="serie_promedio_ventas_ultimo_mes.csv",
            mime="text/csv",
        )

    # ============================================================
    # SEGUNDA GRÁFICA → Evolución promedio (SIN OUTLIERS)
    # ============================================================
    st.markdown("#### Evolución promedio de ventas del último mes (sin outliers)")

    if df_series.empty:
        st.info("No hay historial suficiente de ventas para graficar.")
    else:

        # --- Copiamos df_total ya calculado arriba ---
        df_total_no = df_total.copy()
        df_total_no["Ventas_promedio_ult_mes"] = pd.to_numeric(
            df_total_no["Ventas_promedio_ult_mes"], errors="coerce"
        )

        # -----------------------------------------
        # Detectar outliers con percentil 75
        # -----------------------------------------
        q75 = df_total_no["Ventas_promedio_ult_mes"].quantile(0.75)

        # Filtrar solo valores permitidos
        df_no_out = df_total_no[df_total_no["Ventas_promedio_ult_mes"] <= q75]

        # Promedio sin outliers
        promedio_no_out = df_no_out["Ventas_promedio_ult_mes"].mean()

        # -----------------------------------------
        # Construir gráfica
        # -----------------------------------------
        fig_line_no = go.Figure()

        # Línea principal sin outliers
        fig_line_no.add_trace(
            go.Scatter(
                x=df_no_out["Fecha"],
                y=df_no_out["Ventas_promedio_ult_mes"],
                mode="lines+markers+text",
                name="Promedio sin outliers",
                text=[f"{v:.1f}" if not pd.isna(v) else "" for v in df_no_out["Ventas_promedio_ult_mes"]],
                textposition="top center",
                hovertemplate=(
                    "Fecha: %{x|%b %Y}<br>"
                    "Ventas prom. (sin outliers): %{y:,.2f}<extra></extra>"
                ),
            )
        )

        # Línea horizontal del promedio sin outliers
        if not pd.isna(promedio_no_out):
            fig_line_no.add_hline(
                y=promedio_no_out,
                line_dash="dash",
                line_color="#FFC000",
                annotation_text=f"Promedio sin outliers: {promedio_no_out:,.1f}",
                annotation_position="top left",
            )

        # Ajustes de layout
        fig_line_no.update_layout(
            xaxis_title="Fecha",
            yaxis_title="Ventas promedio sin outliers",
        )

        fig_line_no = apply_charts_theme(fig_line_no)
        st.plotly_chart(fig_line_no, use_container_width=True)

        # Descargar CSV
        csv_no = df_no_out.to_csv(index=False).encode("utf-8")
        st.download_button(
            label="Descargar serie sin outliers (CSV)",
            data=csv_no,
            file_name="serie_promedio_sin_outliers.csv",
            mime="text/csv",
        )

    # ------------------------------
    # Evolución por proyecto (ventas promedio último mes) con corte de outliers
    # ------------------------------
    # st.markdown("#### Evolución por proyecto (ventas promedio último mes)")
    # if df_series.empty:
    #     st.info("No hay historial suficiente de ventas para graficar.")
    # else:
    #     df_plot = df_series.copy()
    #     df_plot["Ventas_promedio_ult_mes"] = pd.to_numeric(
    #         df_plot["Ventas_promedio_ult_mes"], errors="coerce"
    #     )

    #     # -----------------------------------------
    #     # Detectar outliers con el percentil 90
    #     # -----------------------------------------
    #     q90 = df_plot["Ventas_promedio_ult_mes"].quantile(0.90)

    #     # Datos SIN outliers (para calcular promedio)
    #     df_sin_outliers = df_plot[df_plot["Ventas_promedio_ult_mes"] <= q90]
    #     promedio_sin_outliers = df_sin_outliers["Ventas_promedio_ult_mes"].mean()

    #     # -----------------------------------------
    #     # Gráfica de líneas por proyecto
    #     # -----------------------------------------
    #     fig_line_proj = px.line(
    #         df_plot.sort_values(["Proyecto", "Fecha"]),
    #         x="Fecha",
    #         y="Ventas_promedio_ult_mes",
    #         color="Proyecto",
    #         markers=True,
    #     )

    #     # Limitar eje Y a 0 – Q90 (outliers quedan fuera de escala)
    #     fig_line_proj.update_yaxes(range=[0, q90])

    #     # Línea horizontal con el promedio sin outliers
    #     if not pd.isna(promedio_sin_outliers):
    #         fig_line_proj.add_hline(
    #             y=promedio_sin_outliers,
    #             line_dash="dash",
    #             line_color="#FFC000",
    #             annotation_text=f"Prom. sin outliers: {promedio_sin_outliers:,.1f}",
    #             annotation_position="top left",
    #         )

    #     fig_line_proj.update_layout(
    #         xaxis_title="Fecha",
    #         yaxis_title="Ventas promedio último mes",
    #     )

    #     fig_line_proj = apply_charts_theme(fig_line_proj)
    #     st.plotly_chart(fig_line_proj, use_container_width=True)

    #     # Botón CSV para esta serie detallada
    #     csv_series = df_series.to_csv(index=False).encode("utf-8")
    #     st.download_button(
    #         label="Descargar series por proyecto (CSV)",
    #         data=csv_series,
    #         file_name="series_proyectos_ventas_ultimo_mes.csv",
    #         mime="text/csv",
    #     )

    # ------------------------------
    # Resumen comparativo (tabla de proyectos)
    # ------------------------------
    fmt = {
        "Unidades planeadas": "{:,.0f}",
        "Oferta disponible": "{:,.0f}",
        "Oferta vendida": "{:,.0f}",
        "% vendido": "{:,.1f} %",
        "Ritmo mensual ventas históricas": "{:,.2f}",
        "Ventas promedio último mes": "{:,.2f}",
        "Precio inicial": "${:,.0f}",
        "Precio actual": "${:,.0f}",
        "m² promedio proyecto": "{:,.2f}",
        "m² promedio disponible": "{:,.2f}",
    }

    st.subheader("Resumen comparativo")

    # Formato de fechas para vista
    if "Fecha inicio preventa" in df_bm.columns:
        df_bm["Fecha inicio preventa"] = df_bm["Fecha inicio preventa"].dt.strftime("%b-%Y")

    if "Fecha fin venta" in df_bm.columns:
        df_bm["Fecha fin venta"] = df_bm["Fecha fin venta"].dt.strftime("%b-%Y")
        # df_bm['Nombre_desarrrollo'].dropcolumns
        df_bm = df_bm.drop('Nombre_desarrollo', axis=1)
    st.dataframe(df_bm.style.format(fmt))
