"""Página de Calendario — usa st.navigation."""
import streamlit as st
from lib import _get, SOFASCORE_BASE

"""Vista de calendario mensual de partidos PRESENTES y FUTUROS de los jugadores del CSV.

Los partidos pasados no se incluyen aquí (ya están en la ficha de cada jugador).
La vista permite filtrar por equipo, liga (competición) y categoría de edad.
"""

import calendar as _cal
from collections import defaultdict
from datetime import datetime, date, timedelta

import pandas as pd
import streamlit as st


def _registrar_evento(buckets, ev, jugador):
    """Añade un evento futuro a los buckets {fecha → [partidos]}."""
    ts = ev.get("startTimestamp")
    if not ts:
        return
    dt = datetime.fromtimestamp(ts)
    fecha = dt.date()
    home = ev.get("homeTeam", {})
    away = ev.get("awayTeam", {})
    es_local = home.get("id") == jugador.get("equipo_id")
    rival = away.get("name") if es_local else home.get("name")

    buckets[fecha].append({
        "ts": ts,
        "hora": dt.strftime("%H:%M"),
        "fecha": fecha,
        "id": ev.get("id"),
        "player_id": jugador.get("id"),
        "jugador": jugador.get("nombre_agencia") or jugador.get("nombre", "—"),
        "equipo_local": home.get("name", "—"),
        "equipo_visitante": away.get("name", "—"),
        "rival": rival,
        "es_local": es_local,
        "competicion": ev.get("tournament", {}).get("name", "—"),
    })


def _proximos_partidos_equipo(get_fn, sofascore_base, team_id, max_paginas=4):
    """Trae los próximos partidos del equipo paginando hasta `max_paginas`."""
    eventos = []
    for pag in range(max_paginas):
        try:
            data = get_fn(f"{sofascore_base}/team/{team_id}/events/next/{pag}")
        except Exception:
            data = None
        if not data:
            break
        ev_pag = data.get("events", []) or []
        if not ev_pag:
            break
        eventos.extend(ev_pag)
        if not data.get("hasNextPage", False):
            break
    return eventos


def _recolectar_partidos_mes(year, month, df, get_fn, sofascore_base):
    """Para cada jugador filtrado, recoge sus próximos partidos que caen en el mes."""
    primer_dia = date(year, month, 1)
    if month == 12:
        ultimo_dia = date(year + 1, 1, 1) - timedelta(days=1)
    else:
        ultimo_dia = date(year, month + 1, 1) - timedelta(days=1)

    hoy = date.today()
    primer_dia_efectivo = max(primer_dia, hoy)

    buckets = defaultdict(list)

    # Cache por team_id para no repetir llamadas si varios jugadores comparten equipo
    cache_team = {}

    for _, j in df.iterrows():
        jugador = j.to_dict()
        equipo_id = jugador.get("equipo_id")
        if equipo_id is None or pd.isna(equipo_id):
            continue
        try:
            tid = int(equipo_id)
        except (TypeError, ValueError):
            continue

        if tid not in cache_team:
            cache_team[tid] = _proximos_partidos_equipo(get_fn, sofascore_base, tid)
        proximos = cache_team[tid]

        for ev in proximos:
            ts = ev.get("startTimestamp")
            if not ts:
                continue
            f = datetime.fromtimestamp(ts).date()
            if primer_dia_efectivo <= f <= ultimo_dia:
                # evita duplicados (mismo evento + mismo jugador)
                eid = ev.get("id")
                if any(p["id"] == eid and p["player_id"] == jugador["id"] for p in buckets[f]):
                    continue
                _registrar_evento(buckets, ev, jugador)

    return buckets


def _recolectar_cumpleanos_mes(year, month, df):
    """Para cada jugador del df con fecha_nacimiento_ts, calcula si su cumpleaños
    cae dentro del mes mostrado. Devuelve {fecha → [cumples]}."""
    cumples = defaultdict(list)
    for _, row in df.iterrows():
        ts = row.get("fecha_nacimiento_ts")
        if ts is None or pd.isna(ts):
            continue
        try:
            nac = datetime.fromtimestamp(int(ts)).date()
        except (TypeError, ValueError, OSError):
            continue
        # Cumple en el mes que estamos mostrando
        try:
            fecha_cumple = date(year, month, nac.day)
        except ValueError:
            # ej. nació un 29/02 y este año no es bisiesto → lo movemos al 28
            if nac.month == 2 and nac.day == 29:
                try:
                    fecha_cumple = date(year, 2, 28)
                except ValueError:
                    continue
            else:
                continue
        # Solo si efectivamente cumple en este mes (es decir, mes de nacimiento coincide)
        if nac.month != month:
            continue
        cumples[fecha_cumple].append({
            "nombre": row.get("nombre_agencia") or row.get("nombre", "—"),
            "edad_cumple": year - nac.year,
            "player_id": row.get("id"),
        })
    return cumples


def _badge_partido_compacto(p):
    """Línea compacta de partido dentro de la celda del día."""
    return (
        f'<div style="font-size:10px;line-height:1.3;margin-top:2px;'
        f'white-space:nowrap;overflow:hidden;text-overflow:ellipsis">'
        f'<span style="color:#3498db;font-weight:600;font-size:9px">{p["hora"]}</span> '
        f'<span style="color:#222;font-weight:600">{p["jugador"]}</span> '
        f'<span style="color:#888">vs {p["rival"]}</span></div>'
    )


def _badge_cumple_compacto(c):
    """Línea compacta de cumpleaños dentro de la celda del día."""
    return (
        f'<div style="font-size:10px;line-height:1.3;margin-top:2px;'
        f'white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#c0392b">'
        f'🎂 <span style="font-weight:600">{c["nombre"]}</span> '
        f'<span style="color:#a06060">({c["edad_cumple"]})</span></div>'
    )


def _render_grid_mes(year, month, buckets, cumples_buckets=None):
    """Pinta el grid mensual con partidos y cumpleaños en cada celda."""
    cumples_buckets = cumples_buckets or {}
    cal = _cal.Calendar(firstweekday=0)  # lunes = 0
    semanas = cal.monthdatescalendar(year, month)
    hoy = date.today()

    DIAS = ["Lun", "Mar", "Mié", "Jue", "Vie", "Sáb", "Dom"]
    head = (
        '<tr style="background:#1A1A1A;color:white">'
        + "".join(f'<th style="padding:6px;text-align:center;width:14.2%;font-size:12px">{d}</th>' for d in DIAS)
        + "</tr>"
    )

    filas = ""
    for semana in semanas:
        celdas = ""
        for dia in semana:
            es_otro_mes = dia.month != month
            es_pasado = dia < hoy
            es_hoy = dia == hoy
            partidos = sorted(buckets.get(dia, []), key=lambda p: p["ts"])
            cumples = cumples_buckets.get(dia, []) if not es_otro_mes else []

            # Color base — los cumples tiñen ligeramente la celda de rosa si no hay partido
            if es_otro_mes or es_pasado:
                bg = "#fafafa"
                num_color = "#bbb"
            elif partidos and cumples:
                bg = "#fbe9e7"  # mezcla suave (cumple + partido)
                num_color = "#a04141"
            elif partidos:
                bg = "#e7f1fb"
                num_color = "#1c4f8c"
            elif cumples:
                bg = "#fdecea"
                num_color = "#a04141"
            else:
                bg = "#ffffff"
                num_color = "#222"

            borde = "2px solid #2980b9" if es_hoy else "1px solid #e0e0e0"
            peso = "700" if es_hoy else "500"

            # Pintamos primero cumples (siempre visibles), luego partidos
            contenido = ""
            for c in cumples:
                contenido += _badge_cumple_compacto(c)
            espacio_restante = max(0, 3 - len(cumples))
            for p in partidos[:espacio_restante]:
                contenido += _badge_partido_compacto(p)
            extras = len(partidos) - espacio_restante
            if extras > 0:
                contenido += f'<div style="font-size:9px;color:#888;margin-top:2px">+{extras} más</div>'

            celdas += (
                f'<td style="vertical-align:top;padding:5px;background:{bg};'
                f'border:{borde};height:90px;width:14.2%;overflow:hidden">'
                f'<div style="font-size:11px;font-weight:{peso};color:{num_color};margin-bottom:2px">{dia.day}</div>'
                f'{contenido}'
                f'</td>'
            )
        filas += f'<tr>{celdas}</tr>'

    st.markdown(
        '<table style="width:100%;border-collapse:collapse;table-layout:fixed">'
        f'<thead>{head}</thead>'
        f'<tbody>{filas}</tbody>'
        '</table>',
        unsafe_allow_html=True,
    )


def _aplicar_filtros(df, equipos_sel, ligas_sel, categorias_sel):
    """Filtra el df por las selecciones del usuario."""
    out = df
    if equipos_sel:
        out = out[out["equipo"].isin(equipos_sel)]
    if ligas_sel:
        out = out[out["competicion"].isin(ligas_sel)]
    if categorias_sel:
        out = out[out["categoria"].isin(categorias_sel)]
    return out


def vista_calendario(df, get_fn, sofascore_base):
    """Punto de entrada del calendario.

    Args:
        df: DataFrame de jugadores (debe contener equipo, equipo_id, competicion, categoria, etc.)
        get_fn: función `_get(url)` con auth para llamar a SofaScore
        sofascore_base: URL base de la API
    """
    st.title("📅 Calendario de partidos")
    st.caption("Próximos partidos de los jugadores del CSV. Para ver el histórico, abre la ficha del jugador.")

    if df.empty:
        st.info("No hay jugadores cargados.")
        return

    # ── Filtros ────────────────────────────────────────────────────────────
    with st.expander("🔍 Filtros", expanded=False):
        c1, c2, c3 = st.columns(3)
        with c1:
            equipos = sorted(df["equipo"].dropna().unique().tolist())
            equipos_sel = st.multiselect("Equipo", equipos, default=[], key="cal_filt_eq")
        with c2:
            ligas = sorted(df["competicion"].dropna().unique().tolist())
            ligas_sel = st.multiselect("Liga / competición", ligas, default=[], key="cal_filt_li")
        with c3:
            categorias_disp = ["Sub-19 (Juvenil)", "Sub-23", "23+"]
            categorias_sel = st.multiselect(
                "Categoría de edad",
                categorias_disp,
                default=categorias_disp,
                key="cal_filt_cat",
            )

    df_filt = _aplicar_filtros(df, equipos_sel, ligas_sel, categorias_sel)

    if df_filt.empty:
        st.warning("Ningún jugador coincide con los filtros seleccionados.")
        return

    # ── Navegación de mes ──────────────────────────────────────────────────
    if "calendario_year" not in st.session_state or "calendario_month" not in st.session_state:
        hoy = date.today()
        st.session_state.calendario_year = hoy.year
        st.session_state.calendario_month = hoy.month

    c_prev, c_titulo, c_next, c_hoy = st.columns([1, 5, 1, 1])
    with c_prev:
        if st.button("◀", key="cal_prev", use_container_width=True):
            m = st.session_state.calendario_month - 1
            y = st.session_state.calendario_year
            if m < 1:
                m, y = 12, y - 1
            st.session_state.calendario_month = m
            st.session_state.calendario_year = y
            st.rerun()
    with c_next:
        if st.button("▶", key="cal_next", use_container_width=True):
            m = st.session_state.calendario_month + 1
            y = st.session_state.calendario_year
            if m > 12:
                m, y = 1, y + 1
            st.session_state.calendario_month = m
            st.session_state.calendario_year = y
            st.rerun()
    with c_hoy:
        if st.button("Hoy", key="cal_hoy", use_container_width=True):
            hoy = date.today()
            st.session_state.calendario_year = hoy.year
            st.session_state.calendario_month = hoy.month
            st.rerun()

    year = st.session_state.calendario_year
    month = st.session_state.calendario_month
    NOMBRES_MES = ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio",
                   "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"]
    with c_titulo:
        st.markdown(
            f'<h3 style="text-align:center;margin:0;padding-top:4px">{NOMBRES_MES[month-1]} {year}</h3>',
            unsafe_allow_html=True,
        )

    # ── Carga de partidos + cumpleaños ─────────────────────────────────────
    with st.spinner("Cargando próximos partidos..."):
        buckets = _recolectar_partidos_mes(year, month, df_filt, get_fn, sofascore_base)
    cumples_buckets = _recolectar_cumpleanos_mes(year, month, df_filt)

    total_partidos = sum(len(v) for v in buckets.values())
    total_cumples = sum(len(v) for v in cumples_buckets.values())
    n_dias = len(buckets)

    c1, c2, c3, c4 = st.columns(4)
    c1.metric("Jugadores incluidos", len(df_filt))
    c2.metric("Días con partido", n_dias)
    c3.metric("Partidos próximos", total_partidos)
    c4.metric("🎂 Cumpleaños", total_cumples)

    _render_grid_mes(year, month, buckets, cumples_buckets)

    # ── Tabla resumen del mes ──────────────────────────────────────────────
    if total_partidos:
        st.divider()
        st.markdown("#### Próximos partidos del mes")
        todos = sorted(
            (p for ps in buckets.values() for p in ps),
            key=lambda p: p["ts"],
        )
        filas_html = ""
        for idx, p in enumerate(todos):
            bg_fila = "#ffffff" if idx % 2 == 0 else "#f8f9fa"
            if p["es_local"]:
                partido_str = f'<strong>{p["equipo_local"]}</strong> <span style="color:#888">vs {p["equipo_visitante"]}</span>'
            else:
                partido_str = f'<span style="color:#888">{p["equipo_local"]} vs</span> <strong>{p["equipo_visitante"]}</strong>'
            fecha_str = p["fecha"].strftime("%d/%m/%Y")
            filas_html += (
                f'<tr style="background:{bg_fila}">'
                f'<td style="padding:6px 10px">{fecha_str}</td>'
                f'<td style="padding:6px 10px;color:#888;font-size:0.85em">{p["hora"]}</td>'
                f'<td style="padding:6px 10px;font-weight:600">{p["jugador"]}</td>'
                f'<td style="padding:6px 10px">{partido_str}</td>'
                f'<td style="padding:6px 10px;color:#666;font-size:0.85em">{p["competicion"]}</td>'
                f'</tr>'
            )
        st.markdown(
            '<table style="width:100%;border-collapse:collapse;border:1px solid #ddd;border-radius:8px;overflow:hidden;font-size:0.9em">'
            '<thead><tr style="background:#1A1A1A;color:white;font-size:0.85em">'
            "<th style='padding:8px 10px;text-align:left'>Fecha</th>"
            "<th style='padding:8px 10px;text-align:left'>Hora</th>"
            "<th style='padding:8px 10px;text-align:left'>Jugador</th>"
            "<th style='padding:8px 10px;text-align:left'>Partido</th>"
            "<th style='padding:8px 10px;text-align:left'>Competición</th>"
            "</tr></thead>"
            f'<tbody>{filas_html}</tbody></table>',
            unsafe_allow_html=True,
        )
    else:
        st.info("No hay partidos próximos en este mes para los jugadores filtrados.")

    # ── Tabla resumen de cumpleaños del mes ─────────────────────────────────
    if total_cumples:
        st.divider()
        st.markdown("#### 🎂 Cumpleaños del mes")
        todos_cumples = sorted(
            ((f, c) for f, cs in cumples_buckets.items() for c in cs),
            key=lambda x: x[0],
        )
        filas_html = ""
        for idx, (fecha_c, c) in enumerate(todos_cumples):
            bg_fila = "#ffffff" if idx % 2 == 0 else "#f8f9fa"
            filas_html += (
                f'<tr style="background:{bg_fila}">'
                f'<td style="padding:6px 10px">{fecha_c.strftime("%d/%m/%Y")}</td>'
                f'<td style="padding:6px 10px;font-weight:600">🎂 {c["nombre"]}</td>'
                f'<td style="padding:6px 10px;text-align:center">cumple {c["edad_cumple"]}</td>'
                f'</tr>'
            )
        st.markdown(
            '<table style="width:100%;border-collapse:collapse;border:1px solid #ddd;border-radius:8px;overflow:hidden;font-size:0.9em">'
            '<thead><tr style="background:#1A1A1A;color:white;font-size:0.85em">'
            "<th style='padding:8px 10px;text-align:left'>Fecha</th>"
            "<th style='padding:8px 10px;text-align:left'>Jugador</th>"
            "<th style='padding:8px 10px;text-align:center'>Años que cumple</th>"
            "</tr></thead>"
            f'<tbody>{filas_html}</tbody></table>',
            unsafe_allow_html=True,
        )


# Entry de la page
df = st.session_state.get("df")
if df is None or df.empty:
    st.warning("Aún no se han cargado los jugadores. Vuelve al inicio.")
else:
    vista_calendario(df, _get, SOFASCORE_BASE)
