"""Puntuación y selección de los tweets TOP.

La puntuación combina:
  - engagement (likes, RTs, respuestas, citas) con pesos configurables
  - frescura: un tweet pierde la mitad de su valor cada `recency_halflife_hours`
  - temas: multiplicador extra si el texto menciona alguno de tus temas
"""

from datetime import datetime, timezone
from typing import List, Optional, Tuple

from agent.models import Tweet

DEFAULT_WEIGHTS = {"likes": 1.0, "retweets": 2.0, "replies": 1.5, "quotes": 1.5}


def score_tweet(
    tweet: Tweet,
    weights: Optional[dict] = None,
    now: Optional[datetime] = None,
    recency_halflife_hours: float = 18.0,
    keywords: Optional[List[str]] = None,
    keyword_boost: float = 1.5,
) -> float:
    weights = weights or DEFAULT_WEIGHTS
    now = now or datetime.now(timezone.utc)

    base = (
        tweet.likes * weights.get("likes", 1.0)
        + tweet.retweets * weights.get("retweets", 2.0)
        + tweet.replies * weights.get("replies", 1.5)
        + tweet.quotes * weights.get("quotes", 1.5)
    )

    age_hours = max(0.0, (now - tweet.created_at).total_seconds() / 3600.0)
    decay = 0.5 ** (age_hours / recency_halflife_hours) if recency_halflife_hours > 0 else 1.0
    score = base * decay

    if keywords:
        text = tweet.text.lower()
        if any(k.lower() in text for k in keywords):
            score *= keyword_boost

    return score


def rank_tweets(tweets: List[Tweet], top_n: int = 10, **kwargs) -> List[Tuple[float, Tweet]]:
    scored = [(score_tweet(t, **kwargs), t) for t in tweets]
    scored.sort(key=lambda pair: pair[0], reverse=True)
    return [(round(s, 1), t) for s, t in scored[:top_n]]
