import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime, timedelta

# ==========================================
# 1. CONFIGURACIÓN DE LA PÁGINA Y ESTILOS
# ==========================================
st.set_page_config(
    page_title="Dashboard Corporativo 2025",
    page_icon="🏗️",
    layout="wide",
    initial_sidebar_state="expanded"
)

# Paleta de Colores Solicitada
PALETA = {
    'oscuro_profundo': '#01161e',
    'azul_petroleo': '#124559',
    'azul_medio': '#598392',
    'verde_gris': '#aec3b0',
    'blanco_crema': '#eff6e0',
    'rojo_alerta': '#d9534f',
    'verde_exito': '#5cb85c'
}

# Secuencia de colores para gráficas Plotly
COLOR_SEQUENCE = [PALETA['azul_petroleo'], PALETA['azul_medio'], PALETA['verde_gris'], PALETA['oscuro_profundo'], PALETA['blanco_crema']]

# CSS Personalizado para tarjetas
st.markdown(f"""
    <style>
    .big-font {{ font-size:24px !important; font-weight: bold; color: {PALETA['azul_petroleo']}; }}
    .metric-label {{ font-size:14px; color: #666; }}
    .stPlotlyChart {{ background-color: #ffffff; border-radius: 5px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
    hr {{ margin-top: 0.5rem; margin-bottom: 0.5rem; }}
    </style>
    """, unsafe_allow_html=True)

# ==========================================
# 2. GENERACIÓN DE DATOS MOCK (SIMULACIÓN 2025)
# ==========================================

@st.cache_data
def generar_datos_empresa(nombre, giros):
    """
    Genera un diccionario con DataFrames simulados para todo el año 2025.
    """
    np.random.seed(len(nombre)) # Semilla basada en nombre para consistencia
    weeks = list(range(1, 53))
    months = ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"]
    
    # --- 1. Bancos (Semanal) ---
    cuentas = ['Santander Operativa', 'BBVA Nómina', 'Banorte Inversión']
    data_bancos = []
    for w in weeks:
        saldo_base = np.random.uniform(2000000, 5000000)
        dist = np.random.dirichlet(np.ones(3), size=1)[0] # Distribución aleatoria
        for i, c in enumerate(cuentas):
            data_bancos.append({
                'Semana': w,
                'Cuenta': c,
                'Saldo': saldo_base * dist[i]
            })
    df_bancos = pd.DataFrame(data_bancos)

    # --- 2. CxC (Semanal) ---
    clientes = [f"Cliente {chr(65+i)}" for i in range(7)] # A-G
    data_cxc = []
    for w in weeks:
        total_semana = np.random.uniform(5000000, 9000000)
        montos = np.random.multinomial(int(total_semana), np.ones(7)/7)
        for i, cli in enumerate(clientes):
            dias_vencimiento = np.random.randint(15, 60)
            data_cxc.append({
                'Semana': w,
                'Cliente': cli,
                'Monto': montos[i],
                'Dias': dias_vencimiento
            })
    df_cxc = pd.DataFrame(data_cxc)

    # --- 3. CxP (Semanal) ---
    proveedores = [f"Prov. {chr(88+i)}" for i in range(6)] # X, Y, Z...
    data_cxp = []
    for w in weeks:
        total_semana = np.random.uniform(3000000, 6000000)
        montos = np.random.multinomial(int(total_semana), np.ones(6)/6)
        for i, prov in enumerate(proveedores):
            dias_para_pago = np.random.randint(1, 45)
            data_cxp.append({
                'Semana': w,
                'Proveedor': prov,
                'Monto': montos[i],
                'DiasVencimiento': dias_para_pago
            })
    df_cxp = pd.DataFrame(data_cxp)

    # --- 4. Ingresos (Semanal) ---
    data_ingresos = []
    for w in weeks:
        monto = np.random.uniform(1000000, 3000000)
        if "Construcción" not in giros: # Caso Malco
            pct_inmo = 1.0
            pct_const = 0.0
        else:
            pct_inmo = np.random.uniform(0.3, 0.7)
            pct_const = 1 - pct_inmo
        
        data_ingresos.append({'Semana': w, 'Giro': 'Inmobiliario', 'Monto': monto * pct_inmo})
        if "Construcción" in giros:
            data_ingresos.append({'Semana': w, 'Giro': 'Construcción', 'Monto': monto * pct_const})
    df_ingresos = pd.DataFrame(data_ingresos)

    # --- 5.1 Nómina (Quincenal simulada en semanas) ---
    data_nomina = []
    colaboradores_base = np.random.randint(150, 200)
    for w in weeks:
        # Incremento ligero de colaboradores
        if w % 4 == 0: colaboradores_base += np.random.randint(-2, 5)
        monto_nomina = colaboradores_base * 10500 # Promedio quincenal aprox
        data_nomina.append({
            'Semana': w,
            'Colaboradores': colaboradores_base,
            'Monto': monto_nomina
        })
    df_nomina = pd.DataFrame(data_nomina)

    # --- 5.2 Indirectos (Mensual simulado en semanas para gráfico) ---
    data_indirectos = []
    acumulado = 0
    presupuesto_total = 20000000
    for w in weeks:
        gasto = np.random.uniform(30000, 80000)
        acumulado += gasto
        pct = (acumulado / presupuesto_total) * 100 if w > 1 else np.random.uniform(5, 8) # % sobre total gasto (simulado)
        # Ajustamos el % para que sea el mensual no acumulado anual para el gauge
        pct_mensual = np.random.uniform(8, 18) 
        data_indirectos.append({
            'Semana': w,
            'Gasto': gasto,
            'Acumulado': acumulado,
            'Porcentaje': pct_mensual
        })
    df_indirectos = pd.DataFrame(data_indirectos)

    # --- 6. Costos / Contractual ---
    data_costos = []
    contratistas = ["Cimentación SA", "Aceros MX", "Concretos Del Sur", "Acabados Finos"]
    for w in weeks:
        for c in contratistas:
            amort = np.random.uniform(500000, 1500000)
            est = np.random.uniform(800000, 2000000)
            data_costos.append({
                'Semana': w,
                'Contratista': c,
                'AmortizacionPendiente': amort,
                'EstimacionProceso': est
            })
    df_costos = pd.DataFrame(data_costos)

    # --- 7. Inventarios (Mensual - mapeado a semanas para simplificar filtro) ---
    data_inv = []
    for w in weeks:
        sistema = np.random.uniform(4000000, 6000000)
        # Diferencia física (merma o error)
        diff = np.random.uniform(-200000, 50000) 
        fisico = sistema + diff
        data_inv.append({
            'Semana': w,
            'Sistema': sistema,
            'Fisico': fisico,
            'Diferencia': diff
        })
    df_inv = pd.DataFrame(data_inv)

    return {
        'bancos': df_bancos,
        'cxc': df_cxc,
        'cxp': df_cxp,
        'ingresos': df_ingresos,
        'nomina': df_nomina,
        'indirectos': df_indirectos,
        'costos': df_costos,
        'inventario': df_inv
    }

# ==========================================
# 3. FUNCIONES DE VISUALIZACIÓN
# ==========================================

def card_metric(label, value, delta_str=None, color_delta="normal"):
    st.markdown(f"""
    <div style="padding: 10px; border: 1px solid #ddd; border-radius: 5px; background: white;">
        <p style="margin:0; font-size: 14px; color: #666;">{label}</p>
        <p style="margin:0; font-size: 22px; font-weight: bold; color: {PALETA['azul_petroleo']};">{value}</p>
        <p style="margin:0; font-size: 12px; color: {'green' if color_delta=='green' else 'red' if color_delta=='red' else '#888'};">
            {delta_str if delta_str else ''}
        </p>
    </div>
    """, unsafe_allow_html=True)

def plot_sparkline(df, y_col, color=PALETA['azul_petroleo']):
    fig = px.line(df, x='Semana', y=y_col)
    fig.update_traces(line_color=color, line_width=2)
    fig.update_layout(
        showlegend=False,
        margin=dict(l=0, r=0, t=0, b=0),
        height=50,
        xaxis=dict(visible=False),
        yaxis=dict(visible=False),
        paper_bgcolor='rgba(0,0,0,0)',
        plot_bgcolor='rgba(0,0,0,0)'
    )
    return fig

# ==========================================
# 4. LOGICA PRINCIPAL DE LA APP
# ==========================================

# --- Sidebar ---
st.sidebar.image("https://cdn-icons-png.flaticon.com/512/4825/4825038.png", width=50) # Placeholder logo
st.sidebar.title("Grupo Monk")

empresa_sel = st.sidebar.radio(
    "Seleccionar Empresa",
    ("Terracerías Maga", "DOI", "DIM", "Malco")
)

# Definir Giros
giros_map = {
    "Terracerías Maga": ["Inmobiliario", "Construcción"],
    "DOI": ["Inmobiliario", "Construcción"],
    "DIM": ["Inmobiliario", "Construcción"],
    "Malco": ["Inmobiliario"]
}

giros_actuales = giros_map[empresa_sel]
st.sidebar.info(f"Giros: {', '.join(giros_actuales)}")

st.sidebar.markdown("---")
semana_sel = st.sidebar.slider("Semana del Año (2025)", 1, 52, 48) # Default semana 48
st.sidebar.caption("Datos simulados Ene-Dic 2025")

# Generar datos
db = generar_datos_empresa(empresa_sel, giros_actuales)

# Filtrar datos por semana
df_b_wk = db['bancos'][db['bancos']['Semana'] == semana_sel]
df_cxc_wk = db['cxc'][db['cxc']['Semana'] == semana_sel]
df_cxp_wk = db['cxp'][db['cxp']['Semana'] == semana_sel]
df_ing_wk = db['ingresos'][db['ingresos']['Semana'] == semana_sel]
df_nom_wk = db['nomina'][db['nomina']['Semana'] == semana_sel]
df_ind_wk = db['indirectos'][db['indirectos']['Semana'] == semana_sel]
df_cos_wk = db['costos'][db['costos']['Semana'] == semana_sel]
df_inv_wk = db['inventario'][db['inventario']['Semana'] == semana_sel]

# Históricos para sparklines (últimas 12 semanas)
rango_hist = range(max(1, semana_sel-11), semana_sel+1)

# --- HEADER ---
st.title(f"Dashboard: {empresa_sel}")
st.markdown(f"**Semana {semana_sel} del 2025**")
st.markdown("---")

# ==========================================
# FILA 1: BANCOS & INGRESOS
# ==========================================
col1, col2 = st.columns([1, 1])

with col1:
    st.subheader("1. Posiciones Bancarias")
    total_bancos = df_b_wk['Saldo'].sum()
    
    # Layout interno bancos
    c_b1, c_b2 = st.columns([1, 2])
    with c_b1:
        card_metric("Total Bancos", f"${total_bancos:,.0f}", "Disponible", "green")
        # Sparkline consolidada
        df_hist_bancos = db['bancos'][db['bancos']['Semana'].isin(rango_hist)].groupby('Semana')['Saldo'].sum().reset_index()
        st.plotly_chart(plot_sparkline(df_hist_bancos, 'Saldo'), use_container_width=True, config={'displayModeBar': False})
        
    with c_b2:
        fig_pie = px.pie(df_b_wk, values='Saldo', names='Cuenta', 
                         color_discrete_sequence=COLOR_SEQUENCE, hole=0.4)
        fig_pie.update_traces(textposition='inside', textinfo='percent+label')
        fig_pie.update_layout(margin=dict(t=0, b=0, l=0, r=0), height=200, showlegend=False)
        st.plotly_chart(fig_pie, use_container_width=True)

with col2:
    st.subheader("4. Ingresos de la Semana")
    total_ing = df_ing_wk['Monto'].sum()
    
    c_i1, c_i2 = st.columns([1, 2])
    with c_i1:
        card_metric("Total Ingresos", f"${total_ing:,.0f}", "Semanal")
    
    with c_i2:
        if not df_ing_wk.empty:
            fig_donut = px.pie(df_ing_wk, values='Monto', names='Giro', 
                               color_discrete_sequence=[PALETA['azul_petroleo'], PALETA['verde_gris']], hole=0.6)
            fig_donut.update_traces(textinfo='percent+value')
            fig_donut.update_layout(margin=dict(t=0, b=0, l=0, r=0), height=200, showlegend=True)
            st.plotly_chart(fig_donut, use_container_width=True)
        else:
            st.warning("Sin ingresos esta semana")

st.markdown("---")

# ==========================================
# FILA 2: CXC & CXP
# ==========================================
col3, col4 = st.columns(2)

with col3:
    st.subheader("2. Cuentas por Cobrar (Top Clientes)")
    total_cxc = df_cxc_wk['Monto'].sum()
    st.metric("Total CxC", f"${total_cxc:,.0f}")
    
    df_cxc_sorted = df_cxc_wk.sort_values(by='Monto', ascending=True) # Ascendente para plot h
    
    # Colores condicionales simulados (Verde < 30 dias, Rojo > 45)
    colors_cxc = [PALETA['rojo_alerta'] if d > 45 else PALETA['verde_exito'] for d in df_cxc_sorted['Dias']]
    
    fig_cxc = go.Figure(go.Bar(
        x=df_cxc_sorted['Monto'],
        y=df_cxc_sorted['Cliente'],
        orientation='h',
        text=df_cxc_sorted['Monto'].apply(lambda x: f"${x:,.0f}"),
        textposition='auto',
        marker_color=colors_cxc
    ))
    fig_cxc.update_layout(margin=dict(t=0, b=0, l=0, r=0), height=250, xaxis=dict(visible=False))
    st.plotly_chart(fig_cxc, use_container_width=True)

with col4:
    st.subheader("3. Cuentas por Pagar (Top Proveedores)")
    total_cxp = df_cxp_wk['Monto'].sum()
    st.metric("Total CxP", f"${total_cxp:,.0f}")
    
    df_cxp_sorted = df_cxp_wk.sort_values(by='Monto', ascending=True)
    
    # Colores condicionales (Rojo si vence en < 7 dias)
    colors_cxp = [PALETA['rojo_alerta'] if d < 7 else PALETA['azul_medio'] for d in df_cxp_sorted['DiasVencimiento']]
    
    fig_cxp = go.Figure(go.Bar(
        x=df_cxp_sorted['Monto'],
        y=df_cxp_sorted['Proveedor'],
        orientation='h',
        text=df_cxp_sorted['Monto'].apply(lambda x: f"${x:,.0f}"),
        textposition='auto',
        marker_color=colors_cxp
    ))
    fig_cxp.update_layout(margin=dict(t=0, b=0, l=0, r=0), height=250, xaxis=dict(visible=False))
    st.plotly_chart(fig_cxp, use_container_width=True)

st.markdown("---")

# ==========================================
# FILA 3: GASTOS (NÓMINA & INDIRECTOS)
# ==========================================
col5, col6 = st.columns(2)

with col5:
    st.subheader("5.1 Nómina (Quincenal)")
    if not df_nom_wk.empty:
        nom_monto = df_nom_wk.iloc[0]['Monto']
        nom_colabs = df_nom_wk.iloc[0]['Colaboradores']
        
        c_n1, c_n2 = st.columns(2)
        with c_n1:
            card_metric("Monto a Pagar", f"${nom_monto:,.0f}")
        with c_n2:
            card_metric("Colaboradores", f"{nom_colabs}", "+2 vs ant")
            
        st.caption("Tendencia últimos 6 meses (semanas)")
        # Sparkline más larga
        rango_largo = range(max(1, semana_sel-24), semana_sel+1)
        df_hist_nom = db['nomina'][db['nomina']['Semana'].isin(rango_largo)]
        st.plotly_chart(plot_sparkline(df_hist_nom, 'Monto', color=PALETA['azul_petroleo']), use_container_width=True, config={'displayModeBar': False})

with col6:
    st.subheader("5.2 Gastos Indirectos")
    if not df_ind_wk.empty:
        pct_ind = df_ind_wk.iloc[0]['Porcentaje']
        acum_ind = df_ind_wk.iloc[0]['Acumulado']
        
        c_ind1, c_ind2 = st.columns([1, 2])
        with c_ind1:
            # Gauge chart
            fig_gauge = go.Figure(go.Indicator(
                mode = "gauge+number",
                value = pct_ind,
                title = {'text': "% Gasto"},
                gauge = {
                    'axis': {'range': [0, 25]},
                    'bar': {'color': PALETA['azul_petroleo']},
                    'steps': [
                        {'range': [0, 15], 'color': PALETA['blanco_crema']},
                        {'range': [15, 25], 'color': "#ffecec"}],
                    'threshold': {'line': {'color': "red", 'width': 4}, 'thickness': 0.75, 'value': 15}}
            ))
            fig_gauge.update_layout(margin=dict(t=30, b=10, l=20, r=20), height=150)
            st.plotly_chart(fig_gauge, use_container_width=True)
            
        with c_ind2:
            st.metric("Acumulado Anual", f"${acum_ind:,.0f}")
            # Linea mensual acumulada
            df_hist_ind = db['indirectos'][db['indirectos']['Semana'] <= semana_sel]
            fig_line = px.area(df_hist_ind, x='Semana', y='Acumulado', color_discrete_sequence=[PALETA['verde_gris']])
            fig_line.update_layout(height=150, margin=dict(t=0, b=0, l=0, r=0), yaxis=dict(visible=False))
            st.plotly_chart(fig_line, use_container_width=True)

st.markdown("---")

# ==========================================
# FILA 4: COSTOS Y CONTRACTUAL & INVENTARIOS
# ==========================================
col7, col8 = st.columns([3, 2])

with col7:
    st.subheader("6. Costos / Control Contractual")
    total_amort = df_cos_wk['AmortizacionPendiente'].sum()
    total_est = df_cos_wk['EstimacionProceso'].sum()
    
    c_cos1, c_cos2 = st.columns(2)
    with c_cos1:
        card_metric("Amort. Pendiente (Anticipos)", f"${total_amort:,.0f}", "Dinero Atrapado", "red")
    with c_cos2:
        card_metric("Estimaciones en Proceso", f"${total_est:,.0f}", "Por Facturar", "normal")
        
    st.caption("Detalle por Contratista (Waterfall simulado como Barras Apiladas para claridad)")
    
    fig_bar_stack = px.bar(df_cos_wk, x='Contratista', y=['AmortizacionPendiente', 'EstimacionProceso'],
                           labels={'value': 'Monto', 'variable': 'Tipo'},
                           color_discrete_sequence=[PALETA['azul_medio'], PALETA['verde_gris']])
    fig_bar_stack.update_layout(height=300, legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1))
    st.plotly_chart(fig_bar_stack, use_container_width=True)

with col8:
    st.subheader("7. Inventarios")
    if not df_inv_wk.empty:
        sis = df_inv_wk.iloc[0]['Sistema']
        fis = df_inv_wk.iloc[0]['Fisico']
        dif = df_inv_wk.iloc[0]['Diferencia']
        
        # Tarjeta diferencia
        st.markdown(f"""
        <div style="background-color: {'#ffecec' if dif < 0 else '#eaffea'}; padding: 10px; border-radius: 5px; text-align: center; margin-bottom: 10px;">
            <span style="font-weight:bold; color: #333;">Diferencia (Físico vs Sistema)</span><br>
            <span style="font-size: 20px; font-weight:bold; color: {'red' if dif < 0 else 'green'};">${dif:,.0f}</span>
        </div>
        """, unsafe_allow_html=True)
        
        # Gráfica comparativa
        df_comp = pd.DataFrame({
            'Tipo': ['Sistema', 'Físico'],
            'Valor': [sis, fis]
        })
        fig_inv = px.bar(df_comp, x='Tipo', y='Valor', color='Tipo',
                         color_discrete_sequence=[PALETA['azul_petroleo'], PALETA['verde_exito']],
                         text_auto='.2s')
        fig_inv.update_layout(height=250, showlegend=False, margin=dict(t=0, b=0, l=0, r=0))
        st.plotly_chart(fig_inv, use_container_width=True)
        
        # Sparkline histórico diferencia
        st.caption("Histórico Diferencia (Año)")
        df_hist_inv = db['inventario'][db['inventario']['Semana'] <= semana_sel]
        fig_spark_inv = px.bar(df_hist_inv, x='Semana', y='Diferencia', 
                               color='Diferencia', color_continuous_scale=['red', 'green'])
        fig_spark_inv.update_layout(height=80, showlegend=False, coloraxis_showscale=False,
                                    margin=dict(t=0, b=0, l=0, r=0), xaxis=dict(visible=False), yaxis=dict(visible=False))
        st.plotly_chart(fig_spark_inv, use_container_width=True)

# Footer
st.markdown("---")
st.caption("Dashboard desarrollado para Grupo Monk - Simulación de Datos Financieros y Operativos 2025")