"""Página de Comparación de jugadores.

El usuario introduce un ID de SofaScore (jugador externo) y elige uno de los
jugadores del CSV. Se pintan gráficos de radar por categoría normalizando
cada stat respecto al máximo entre los dos jugadores (estilo FBref/Wyscout):
así la comparación visual es directa y proporcional, no truncada por la
referencia de liga.
"""
import numpy as np
import matplotlib.pyplot as plt
import streamlit as st

from lib import (
    obtener_datos_jugador,
    extraer_stats_temporada,
    cargar_stats_temporada,
    cargar_stats_liga,
    STATS_GRUPOS,
    PHOTO_PLACEHOLDER,
    _get,
    SOFASCORE_BASE,
    DCL_PRIMARIO,
)

st.title("📊 Comparar jugadores")
st.caption(
    "Compara cualquier jugador de SofaScore (por ID) con uno de los del CSV. "
    "Cada eje del radar se normaliza al **máximo entre los dos jugadores**: si uno tiene "
    "el doble que el otro, el doble en el eje. Los valores brutos se ven al expandir la tabla."
)

df = st.session_state.get("df")
if df is None or df.empty:
    st.warning("Aún no se han cargado los jugadores del CSV.")
    st.stop()


# ── Helpers ────────────────────────────────────────────────────────────────
def _normalizar_grupo(*valores):
    """Normaliza N valores (jugadores + medias) al máximo entre todos los no-None.

    Acepta None para valores ausentes (se devuelven como None en la salida).
    Si todos son 0 / None, devuelve None para señalar "stat sin valor" → el caller
    decide si la incluye o no en el radar.
    """
    nums = [(v if isinstance(v, (int, float)) else 0) for v in valores]
    m = max(nums) if nums else 0
    if m == 0:
        return None
    return [round(100 * n / m) if v is not None else None
            for n, v in zip(nums, valores)]


def _cargar_perfil_externo(player_id):
    """Carga datos básicos + stats temporada + liga referencia de un jugador externo."""
    datos = obtener_datos_jugador(player_id)
    if not datos or "error" in datos:
        return None, (datos or {}).get("error", "Sin respuesta")

    raw = _get(f"{SOFASCORE_BASE}/player/{player_id}/statistics")
    _, comp, temp, tid, sid = extraer_stats_temporada(raw)
    stats = cargar_stats_temporada(player_id, tid, sid) if tid and sid else {}
    liga = cargar_stats_liga(tid, sid) if tid and sid else {}

    datos.update({
        "competicion": comp,
        "temporada": temp,
        "tournament_id": tid,
        "season_id": sid,
        "stats": stats,
        "liga_data": liga,
    })
    return datos, None


def _limpiar_etiqueta(texto):
    """Quita emojis y paréntesis del nombre del eje del radar."""
    for ch in ("⚽", "👟", "🛡️", "📍", "🏟️", "🤕"):
        texto = texto.replace(ch, "")
    if "(" in texto:
        texto = texto.split("(")[0]
    return texto.strip()


def _fmt_valor(v):
    """Formatea un valor numérico bruto para anotar en el radar."""
    if v is None:
        return "—"
    if isinstance(v, float):
        # Sin decimales si es entero; un decimal si no
        return f"{v:.0f}" if v.is_integer() else f"{v:.1f}"
    return str(v)


def _radar(categorias, valores1, valores2, nombre1, nombre2,
           brutos1=None, brutos2=None,
           medias=None, brutos_medias=None, label_media="Media top liga",
           medias2=None, brutos_medias2=None, label_media2=None,
           color1="#3498db", color2=DCL_PRIMARIO):
    """Radar de comparación con jugadores + media(s) de liga opcionales.

    - `medias` / `medias2`: listas de valores 0-100 normalizados para las medias del top 50.
      `medias2` solo se usa si los jugadores son de ligas distintas (dos referencias).
    - `brutos_*`: valores crudos (para anotar en cada vértice).
    """
    n = len(categorias)
    angles = [i * 2 * np.pi / n for i in range(n)]
    angles_cerrado = angles + [angles[0]]

    def _cerrar(vals):
        return [(v if v is not None else 0) for v in vals] + [(vals[0] if vals[0] is not None else 0)]

    v1 = _cerrar(valores1)
    v2 = _cerrar(valores2)

    fig, ax = plt.subplots(figsize=(5.5, 5.5), subplot_kw={"polar": True})
    ax.set_theta_offset(np.pi / 2)
    ax.set_theta_direction(-1)  # sentido horario

    # Capas: primero medias (al fondo), luego jugadores encima
    if medias is not None:
        vm = _cerrar(medias)
        ax.plot(angles_cerrado, vm, color="#7f8c8d", linewidth=1.5,
                linestyle="--", alpha=0.85, label=label_media)
    if medias2 is not None:
        vm2 = _cerrar(medias2)
        ax.plot(angles_cerrado, vm2, color="#bdc3c7", linewidth=1.5,
                linestyle=":", alpha=0.85, label=label_media2 or "Media liga 2")

    ax.plot(angles_cerrado, v1, color=color1, linewidth=2.5, label=nombre1)
    ax.fill(angles_cerrado, v1, color=color1, alpha=0.22)
    ax.plot(angles_cerrado, v2, color=color2, linewidth=2.5, label=nombre2)
    ax.fill(angles_cerrado, v2, color=color2, alpha=0.30)

    # Anotación de valores brutos en cada vértice
    if brutos1 is not None and brutos2 is not None:
        for ang, b1, b2, p1, p2 in zip(angles, brutos1, brutos2,
                                        valores1, valores2):
            p1_ = p1 if p1 is not None else 0
            p2_ = p2 if p2 is not None else 0
            r1 = min(p1_ + 8, 110)
            r2 = min(p2_ + 8, 110)
            if abs(p1_ - p2_) < 12:
                r1 = min(p1_ + 4, 108)
                r2 = min(p2_ + 14, 116)
            ax.text(ang, r1, _fmt_valor(b1), color=color1,
                    fontsize=7.5, fontweight="bold", ha="center", va="center",
                    bbox=dict(boxstyle="round,pad=0.15", facecolor="white",
                              edgecolor=color1, linewidth=0.7, alpha=0.92))
            ax.text(ang, r2, _fmt_valor(b2), color=color2,
                    fontsize=7.5, fontweight="bold", ha="center", va="center",
                    bbox=dict(boxstyle="round,pad=0.15", facecolor="white",
                              edgecolor=color2, linewidth=0.7, alpha=0.92))

        # Anotación de la media (más pequeña y gris) sobre el eje, hacia dentro
        if brutos_medias is not None and medias is not None:
            for ang, bm, pm in zip(angles, brutos_medias, medias):
                if bm is None or pm is None:
                    continue
                # Colocamos la media ligeramente HACIA DENTRO del vértice para no
                # solapar con las etiquetas de los jugadores
                rm = max(pm - 9, 8)
                ax.text(ang, rm, _fmt_valor(bm), color="#666",
                        fontsize=6.5, fontweight="normal", ha="center", va="center",
                        bbox=dict(boxstyle="round,pad=0.1", facecolor="#f0f0f0",
                                  edgecolor="#bdc3c7", linewidth=0.5, alpha=0.85))

    ax.set_xticks(angles)
    ax.set_xticklabels(categorias, fontsize=8.5)
    ax.set_ylim(0, 120)
    ax.set_yticks([20, 40, 60, 80, 100])
    ax.set_yticklabels(["20", "40", "60", "80", "100"], color="#bbb", fontsize=7)
    ax.grid(True, alpha=0.4, linestyle="--")
    ax.spines["polar"].set_color("#ddd")

    ax.legend(loc="upper center", bbox_to_anchor=(0.5, -0.08),
              ncol=3, frameon=False, fontsize=8.5)
    fig.tight_layout()
    return fig


def _tarjeta_jugador(datos, es_externo=False):
    """Pinta una tarjeta resumen del jugador."""
    foto = datos.get("foto") or PHOTO_PLACEHOLDER
    nombre = (
        datos.get("nombre_agencia") or datos.get("nombre", "—")
        if not es_externo
        else datos.get("nombre", "—")
    )
    with st.container(border=True):
        c1, c2 = st.columns([1, 3])
        with c1:
            st.markdown(
                f'<img src="{foto}" style="width:80px;height:80px;border-radius:8px;object-fit:cover">',
                unsafe_allow_html=True,
            )
        with c2:
            tag_externo = (
                '<span style="background:#3498db;color:white;font-size:10px;'
                'padding:2px 7px;border-radius:10px;margin-left:6px;font-weight:600">EXTERNO</span>'
                if es_externo else ""
            )
            st.markdown(
                f'<div style="font-size:17px;font-weight:700">{nombre}{tag_externo}</div>',
                unsafe_allow_html=True,
            )
            st.caption(
                f"🛡️ {datos.get('equipo', '—')} · "
                f"📍 {datos.get('posicion', '—')} · "
                f"{datos.get('edad', '—')} años"
            )
            st.caption(
                f"🏆 {datos.get('competicion', '—')} {datos.get('temporada', '')}"
            )


# ── Inputs ─────────────────────────────────────────────────────────────────
nuestros = df.to_dict("records")
opciones_csv = {
    f"{p.get('nombre_agencia') or p['nombre']} · {p.get('equipo', '')}".strip(" ·"): p
    for p in nuestros
}

c_id, c_drop, c_btn = st.columns([2, 3, 1])
with c_id:
    id_externo = st.text_input(
        "ID jugador externo (SofaScore)",
        placeholder="ej: 12345",
        help="Cópialo de la URL de SofaScore: .../player/<id>/...",
    )
with c_drop:
    nombre_seleccionado = st.selectbox(
        "Tu jugador (CSV)",
        list(opciones_csv.keys()),
    )
with c_btn:
    st.markdown("<div style='height:28px'></div>", unsafe_allow_html=True)
    comparar = st.button("Comparar", use_container_width=True, type="primary")


# Re-disparar si los inputs cambiaron desde la última comparación
key_actual = (id_externo.strip(), nombre_seleccionado)
key_cache = st.session_state.get("comparar_key")

if comparar:
    # Validar ID externo
    try:
        pid_ext = int(id_externo.strip())
    except (ValueError, TypeError):
        st.error("El ID externo debe ser un número entero (cópialo de la URL de SofaScore).")
        st.stop()

    with st.spinner("Cargando perfiles y referencia de liga..."):
        externo, err = _cargar_perfil_externo(pid_ext)
        if err or not externo:
            st.error(f"No se pudo cargar el jugador externo: {err}")
            st.stop()

        # Si el ID coincide con uno del CSV, no es "externo" — quitamos el tag
        ids_csv = {int(p["id"]) for p in nuestros if p.get("id") is not None}
        externo["es_externo"] = pid_ext not in ids_csv

        nuestro = opciones_csv[nombre_seleccionado]
        # Cache de la liga del jugador nuestro (suele estar precargada)
        tid_n = nuestro.get("tournament_id")
        sid_n = nuestro.get("season_id")
        liga_nuestro = cargar_stats_liga(int(tid_n), int(sid_n)) if tid_n and sid_n else {}

        st.session_state.comparar_externo = externo
        st.session_state.comparar_nuestro_meta = nuestro
        st.session_state.comparar_liga_nuestro = liga_nuestro
        st.session_state.comparar_key = key_actual

# Si no hay datos cacheados o cambió la selección, pedir click
externo = st.session_state.get("comparar_externo")
nuestro = st.session_state.get("comparar_nuestro_meta")
liga_nuestro = st.session_state.get("comparar_liga_nuestro") or {}
liga_externo = (externo or {}).get("liga_data") or {}

if not externo or not nuestro:
    st.info("Introduce un ID externo y pulsa **Comparar**.")
    st.stop()

if key_cache != key_actual:
    st.warning("Los inputs cambiaron. Pulsa **Comparar** para actualizar la vista.")

# ── Tarjetas ───────────────────────────────────────────────────────────────
col_e, col_n = st.columns(2)
with col_e:
    _tarjeta_jugador(externo, es_externo=externo.get("es_externo", True))
with col_n:
    _tarjeta_jugador(nuestro, es_externo=False)

# ── Radares por categoría ──────────────────────────────────────────────────
st.divider()
st.markdown("### Comparativa por categorías")
st.caption(
    "Cada eje se normaliza al **máximo entre los dos jugadores + media de liga** (el más alto marca el 100%). "
    "El número en cada vértice es el **valor bruto** (color de jugador en negrita, media en gris). "
    "La línea **discontinua gris** es la media del top 50 de la liga — referencia rápida de élite."
)

nombre_ext = externo.get("nombre", "Externo")
nombre_nos = nuestro.get("nombre_agencia") or nuestro.get("nombre", "Nuestro")

GRUPOS_PARA_RADAR = ["Ataque", "Pases", "Defensa", "Duelos"]

misma_liga = (
    externo.get("tournament_id") == nuestro.get("tournament_id")
    and externo.get("season_id") == nuestro.get("season_id")
    and externo.get("tournament_id") is not None
)
comp_ext = externo.get("competicion", "—")
comp_nos = nuestro.get("competicion", "—")

# Pintamos los radares en una rejilla 2 columnas
cols_radar = st.columns(2)
idx_radar = 0
for grupo in GRUPOS_PARA_RADAR:
    if grupo not in STATS_GRUPOS:
        continue

    cats = []
    v_ext, v_nos, v_avg_e, v_avg_n = [], [], [], []
    raw_ext, raw_nos, raw_avg_e, raw_avg_n = [], [], [], []
    for clave, etiqueta, _ in STATS_GRUPOS[grupo]:
        if clave == "rating":
            continue
        if clave not in externo.get("stats", {}) or clave not in nuestro.get("stats", {}):
            continue
        raw_e = externo["stats"][clave]
        raw_n = nuestro["stats"][clave]
        # avg de cada liga (puede no existir en el endpoint top-players para esa stat)
        avg_e = (liga_externo.get(clave) or {}).get("avg")
        avg_n = (liga_nuestro.get(clave) or {}).get("avg")

        # Normalizamos jugadores + media(s). Si misma liga, una sola.
        if misma_liga:
            normed = _normalizar_grupo(raw_e, raw_n, avg_e)
            if normed is None:
                continue  # todo en 0
            e_n, n_n, ae_n = normed
            an_n = ae_n
            avg_n_show = avg_e
        else:
            normed = _normalizar_grupo(raw_e, raw_n, avg_e, avg_n)
            if normed is None:
                continue
            e_n, n_n, ae_n, an_n = normed
            avg_n_show = avg_n

        cats.append(_limpiar_etiqueta(etiqueta))
        v_ext.append(e_n)
        v_nos.append(n_n)
        v_avg_e.append(ae_n)
        v_avg_n.append(an_n)
        raw_ext.append(raw_e)
        raw_nos.append(raw_n)
        raw_avg_e.append(avg_e)
        raw_avg_n.append(avg_n_show)

    if len(cats) < 3:
        with cols_radar[idx_radar % 2]:
            st.caption(f"_{grupo}: no hay suficientes stats comunes._")
        idx_radar += 1
        continue

    with cols_radar[idx_radar % 2]:
        st.markdown(f"#### {grupo}")
        if misma_liga:
            fig = _radar(
                cats, v_ext, v_nos, nombre_ext, nombre_nos,
                brutos1=raw_ext, brutos2=raw_nos,
                medias=v_avg_e, brutos_medias=raw_avg_e,
                label_media=f"Media top liga ({comp_ext})",
            )
        else:
            fig = _radar(
                cats, v_ext, v_nos, nombre_ext, nombre_nos,
                brutos1=raw_ext, brutos2=raw_nos,
                medias=v_avg_e, brutos_medias=raw_avg_e,
                label_media=f"Media {comp_ext}",
                medias2=v_avg_n, brutos_medias2=raw_avg_n,
                label_media2=f"Media {comp_nos}",
            )
        st.pyplot(fig, use_container_width=True)
        plt.close(fig)
    idx_radar += 1

# ── Tabla detallada (valores brutos) ───────────────────────────────────────
st.divider()
with st.expander("📋 Ver valores brutos por estadística", expanded=False):
    # Fondos semánticos: verde claro = mejor, rojo claro = peor, transparente = empate
    BG_MEJOR = "background:#d4edda;color:#155724;"  # verde claro
    BG_PEOR = "background:#f8d7da;color:#721c24;"   # rojo claro
    BG_NEUTRO = "color:#333;"

    filas_html = ""
    for grupo, campos in STATS_GRUPOS.items():
        for clave, etiqueta, fmt in campos:
            if clave == "rating":
                continue
            v_e_raw = externo.get("stats", {}).get(clave)
            v_n_raw = nuestro.get("stats", {}).get(clave)
            if v_e_raw is None and v_n_raw is None:
                continue
            try:
                v_e_s = fmt.format(v_e_raw) if v_e_raw is not None else "—"
            except Exception:
                v_e_s = str(v_e_raw)
            try:
                v_n_s = fmt.format(v_n_raw) if v_n_raw is not None else "—"
            except Exception:
                v_n_s = str(v_n_raw)

            # Estilo por comparación (solo si ambos son numéricos y distintos)
            if (isinstance(v_e_raw, (int, float))
                and isinstance(v_n_raw, (int, float))
                and v_e_raw != v_n_raw):
                if v_e_raw > v_n_raw:
                    estilo_e, estilo_n = BG_MEJOR, BG_PEOR
                else:
                    estilo_e, estilo_n = BG_PEOR, BG_MEJOR
            else:
                estilo_e = estilo_n = BG_NEUTRO

            filas_html += (
                f'<tr><td style="padding:5px 12px;color:#666">{grupo}</td>'
                f'<td style="padding:5px 12px">{etiqueta}</td>'
                f'<td style="padding:5px 12px;text-align:right;font-weight:700;{estilo_e}">{v_e_s}</td>'
                f'<td style="padding:5px 12px;text-align:right;font-weight:700;{estilo_n}">{v_n_s}</td></tr>'
            )
    st.markdown(
        '<table style="width:100%;border-collapse:collapse;font-size:0.9em">'
        '<thead><tr>'
        '<th style="padding:6px 12px;text-align:left">Categoría</th>'
        '<th style="padding:6px 12px;text-align:left">Estadística</th>'
        f'<th style="padding:6px 12px;text-align:right">{nombre_ext}</th>'
        f'<th style="padding:6px 12px;text-align:right">{nombre_nos}</th>'
        '</tr></thead>'
        f'<tbody>{filas_html}</tbody></table>',
        unsafe_allow_html=True,
    )
