"""
Relevance and trending calculation service.
Handles business logic for calculating relevance scores and trending metrics.
"""

from typing import Optional, Dict, List
from .base_card import BaseCard


class RelevanceService:
    """Service for calculating relevance and trending scores."""

    def calculate_relevance(
        self, card: BaseCard, user_prefs: Optional[Dict]
    ) -> float:
        """
        Calculate relevance score for a card based on user preferences.

        Args:
            card: The card to score
            user_prefs: User preferences dictionary

        Returns:
            Relevance score between 0 and 1
        """
        if not user_prefs:
            # Default relevance based on impact
            return float(getattr(card, "impact_score", 5)) / 10.0

        score = 0.5  # Base score

        # Category preference
        if hasattr(card, "category"):
            if card.category in user_prefs.get("liked_categories", []):
                score += 0.2
            elif card.category in user_prefs.get("disliked_categories", []):
                score -= 0.2

        # Impact threshold
        if hasattr(card, "impact_score"):
            threshold = user_prefs.get("impact_threshold", 5)
            if card.impact_score >= threshold:
                score += 0.1
            else:
                score -= 0.1

        # Topic matching (simplified without embeddings)
        if hasattr(card, "topics"):
            liked_topics = user_prefs.get("liked_topics", [])
            for topic in card.topics:
                if any(liked in topic.lower() for liked in liked_topics):
                    score += 0.1
                    break

        # Ensure score is in valid range
        return max(0.0, min(1.0, score))

    def calculate_trending_score(self, card: BaseCard) -> float:
        """
        Calculate trending score based on impact and engagement.

        Args:
            card: The card to score

        Returns:
            Trending score
        """
        if not hasattr(card, "impact_score"):
            return 0.0

        # Calculate engagement
        engagement = (
            card.interaction.get("views", 0)
            + card.interaction.get("votes_up", 0) * 2
            - card.interaction.get("votes_down", 0)
        )

        # Combine impact and engagement
        trending_score: float = float(getattr(card, "impact_score", 0)) + (
            engagement / 10
        )

        return trending_score

    def filter_trending(
        self, cards: List[BaseCard], min_impact: int = 7, limit: int = 10
    ) -> List[BaseCard]:
        """
        Filter and sort cards by trending score.

        Args:
            cards: List of cards to filter
            min_impact: Minimum impact score required
            limit: Maximum number of cards to return

        Returns:
            List of trending cards sorted by score
        """
        trending = []

        for card in cards:
            if (
                hasattr(card, "impact_score")
                and card.impact_score >= min_impact
            ):
                setattr(
                    card, "trending_score", self.calculate_trending_score(card)
                )
                trending.append(card)

        # Sort by trending score
        trending.sort(
            key=lambda c: getattr(c, "trending_score", 0.0), reverse=True
        )

        return trending[:limit]

    def personalize_feed(
        self,
        cards: List[BaseCard],
        user_prefs: Optional[Dict],
        include_seen: bool = True,
    ) -> List[BaseCard]:
        """
        Personalize a feed of cards based on user preferences.

        Args:
            cards: List of cards to personalize
            user_prefs: User preferences
            include_seen: Whether to include already viewed cards

        Returns:
            Personalized list of cards
        """
        personalized = []

        for card in cards:
            # Calculate relevance
            setattr(
                card,
                "relevance_score",
                self.calculate_relevance(card, user_prefs),
            )

            # Filter seen if requested
            if not include_seen and card.interaction.get("viewed"):
                continue

            personalized.append(card)

        # Sort by relevance
        personalized.sort(
            key=lambda c: getattr(c, "relevance_score", 0.0), reverse=True
        )

        return personalized


# Singleton instance
_relevance_service = None


def get_relevance_service() -> RelevanceService:
    """Get or create the global RelevanceService instance."""
    global _relevance_service
    if _relevance_service is None:
        _relevance_service = RelevanceService()
    return _relevance_service
