"""
Base class for preference management.
Following LDR's pattern from BaseSearchStrategy.
"""

from abc import ABC, abstractmethod
from typing import Dict, Any, List, Optional
from datetime import timedelta
from loguru import logger

from ..core.utils import utc_now


class BasePreferenceManager(ABC):
    """Abstract base class for preference management."""

    def __init__(self, storage_backend: Optional[Any] = None):
        """
        Initialize the base preference manager.

        Args:
            storage_backend: Optional storage backend for preferences
        """
        self.storage_backend = storage_backend

    @abstractmethod
    def get_preferences(self, user_id: str) -> Dict[str, Any]:
        """
        Get user preferences.

        Args:
            user_id: ID of the user

        Returns:
            Dictionary of user preferences
        """
        pass

    @abstractmethod
    def update_preferences(
        self, user_id: str, preferences: Dict[str, Any]
    ) -> Dict[str, Any]:
        """
        Update user preferences.

        Args:
            user_id: ID of the user
            preferences: Dictionary of preferences to update

        Returns:
            Updated preferences
        """
        pass

    def add_interest(
        self, user_id: str, interest: str, weight: float = 1.0
    ) -> None:
        """
        Add an interest to user preferences.

        Args:
            user_id: ID of the user
            interest: The interest to add
            weight: Weight/importance of this interest
        """
        prefs = self.get_preferences(user_id)

        if "interests" not in prefs:
            prefs["interests"] = {}

        prefs["interests"][interest] = weight
        prefs["interests_updated_at"] = utc_now().isoformat()

        self.update_preferences(user_id, prefs)
        logger.info(f"Added interest '{interest}' for user {user_id}")

    def remove_interest(self, user_id: str, interest: str) -> None:
        """
        Remove an interest from user preferences.

        Args:
            user_id: ID of the user
            interest: The interest to remove
        """
        prefs = self.get_preferences(user_id)

        if "interests" in prefs and interest in prefs["interests"]:
            del prefs["interests"][interest]
            prefs["interests_updated_at"] = utc_now().isoformat()

            self.update_preferences(user_id, prefs)
            logger.info(f"Removed interest '{interest}' for user {user_id}")

    def ignore_topic(self, user_id: str, topic: str) -> None:
        """
        Add a topic to the ignore list.

        Args:
            user_id: ID of the user
            topic: Topic to ignore
        """
        prefs = self.get_preferences(user_id)

        if "disliked_topics" not in prefs:
            prefs["disliked_topics"] = []

        if topic not in prefs["disliked_topics"]:
            prefs["disliked_topics"].append(topic)
            prefs["preferences_updated_at"] = utc_now().isoformat()

            self.update_preferences(user_id, prefs)
            logger.info(f"Added '{topic}' to ignore list for user {user_id}")

    def boost_source(
        self, user_id: str, source: str, weight: float = 1.5
    ) -> None:
        """
        Boost a particular news source.

        Args:
            user_id: ID of the user
            source: Source domain to boost
            weight: Boost weight
        """
        prefs = self.get_preferences(user_id)

        if "source_weights" not in prefs:
            prefs["source_weights"] = {}

        prefs["source_weights"][source] = weight
        prefs["preferences_updated_at"] = utc_now().isoformat()

        self.update_preferences(user_id, prefs)
        logger.info(
            f"Set source weight for '{source}' to {weight} for user {user_id}"
        )

    def get_default_preferences(self) -> Dict[str, Any]:
        """
        Get default preferences for new users.

        Returns:
            Dictionary of default preferences
        """
        return {
            "liked_categories": [],
            "disliked_categories": [],
            "liked_topics": [],
            "disliked_topics": [],
            "interests": {},
            "source_weights": {},
            "impact_threshold": 5,  # Default threshold
            "focus_preferences": {
                "surprising": False,
                "breaking": True,
                "positive": False,
                "local": False,
            },
            "custom_search_terms": "",
            "search_strategy": "news_aggregation",
            "created_at": utc_now().isoformat(),
            "preferences_updated_at": utc_now().isoformat(),
        }


class TopicRegistry:
    """
    Registry for dynamically discovered topics.
    Not user-specific - tracks global topic trends.
    """

    def __init__(self, llm_client: Optional[Any] = None):
        """
        Initialize topic registry.

        Args:
            llm_client: LLM client for topic extraction
        """
        self.llm_client = llm_client
        self.topics: Dict[str, Dict[str, Any]] = {}

    def extract_topics(self, content: str, max_topics: int = 5) -> List[str]:
        """
        Extract topics from content using topic generator.

        Args:
            content: Text content to analyze
            max_topics: Maximum number of topics to extract

        Returns:
            List of extracted topics
        """
        from ..utils.topic_generator import generate_topics

        # Use topic generator to extract topics
        topics = generate_topics(
            query="",  # No specific query, just analyzing content
            findings=content,
            category="",
            max_topics=max_topics,
        )

        # Register discovered topics
        for topic in topics:
            self.register_topic(topic)

        return topics

    def register_topic(self, topic: str) -> None:
        """
        Register a discovered topic.

        Args:
            topic: Topic to register
        """
        if topic not in self.topics:
            self.topics[topic] = {
                "first_seen": utc_now(),
                "count": 0,
                "last_seen": utc_now(),
            }

        self.topics[topic]["count"] += 1
        self.topics[topic]["last_seen"] = utc_now()

    def get_trending_topics(
        self, hours: int = 24, limit: int = 10
    ) -> List[str]:
        """
        Get trending topics from the last N hours.

        Args:
            hours: Look back period in hours
            limit: Maximum number of topics to return

        Returns:
            List of trending topic names
        """
        cutoff_time = utc_now() - timedelta(hours=hours)

        # Filter topics seen recently
        recent_topics = [
            (topic, data)
            for topic, data in self.topics.items()
            if data["last_seen"] >= cutoff_time
        ]

        # Sort by count (most frequent first)
        recent_topics.sort(key=lambda x: x[1]["count"], reverse=True)

        # Return topic names only
        return [topic for topic, _ in recent_topics[:limit]]

    def get_topic_info(self, topic: str) -> Optional[Dict[str, Any]]:
        """
        Get information about a specific topic.

        Args:
            topic: Topic to look up

        Returns:
            Topic information or None if not found
        """
        return self.topics.get(topic)
