"""
SQLAlchemy storage implementation for user preferences.
"""

from typing import List, Optional, Dict, Any
from sqlalchemy.orm import Session

from ..core.storage import PreferenceStorage
from ...database.models.news import UserPreference


class SQLPreferenceStorage(PreferenceStorage):
    """SQLAlchemy implementation of preference storage"""

    def __init__(self, session: Session):
        """Initialize with a database session from the user's encrypted database"""
        if not session:
            raise ValueError("Session is required for SQLPreferenceStorage")
        self._session = session

    @property
    def session(self):
        """Get database session"""
        return self._session

    def create(self, data: Dict[str, Any]) -> str:
        """Create new user preferences"""
        with self.session as session:
            prefs = UserPreference(
                user_id=data["user_id"],
                liked_categories=data.get("liked_categories", []),
                disliked_categories=data.get("disliked_categories", []),
                liked_topics=data.get("liked_topics", []),
                disliked_topics=data.get("disliked_topics", []),
                impact_threshold=data.get("impact_threshold", 5),
                focus_preferences=data.get("focus_preferences", {}),
                custom_prompt=data.get("custom_prompt"),
                custom_search_terms=data.get("custom_search_terms"),
                preference_embedding=data.get("preference_embedding"),
                liked_news_ids=data.get("liked_news_ids", []),
                disliked_news_ids=data.get("disliked_news_ids", []),
            )

            session.add(prefs)
            session.commit()

            return str(prefs.id)

    def get(self, id: str) -> Optional[Dict[str, Any]]:
        """Get preferences by ID"""
        with self.session as session:
            prefs = session.query(UserPreference).filter_by(id=int(id)).first()
            return prefs.to_dict() if prefs else None

    def update(self, id: str, data: Dict[str, Any]) -> bool:
        """Update preferences"""
        with self.session as session:
            prefs = session.query(UserPreference).filter_by(id=int(id)).first()
            if not prefs:
                return False

            # Update fields
            for field, value in data.items():
                if hasattr(prefs, field):
                    setattr(prefs, field, value)

            session.commit()
            return True

    def delete(self, id: str) -> bool:
        """Delete preferences"""
        with self.session as session:
            prefs = session.query(UserPreference).filter_by(id=int(id)).first()
            if not prefs:
                return False

            session.delete(prefs)
            session.commit()
            return True

    def list(
        self,
        filters: Optional[Dict[str, Any]] = None,
        limit: int = 100,
        offset: int = 0,
    ) -> List[Dict[str, Any]]:
        """List preferences (usually just one per user)"""
        with self.session as session:
            query = session.query(UserPreference)

            if filters and "user_id" in filters:
                query = query.filter_by(user_id=filters["user_id"])

            prefs = query.limit(limit).offset(offset).all()
            return [p.to_dict() for p in prefs]

    def get_user_preferences(self, user_id: str) -> Optional[Dict[str, Any]]:
        """Get preferences for a user"""
        with self.session as session:
            prefs = (
                session.query(UserPreference).filter_by(user_id=user_id).first()
            )
            return prefs.to_dict() if prefs else None

    def upsert_preferences(
        self, user_id: str, preferences: Dict[str, Any]
    ) -> str:
        """Create or update user preferences"""
        existing = self.get_user_preferences(user_id)

        if existing:
            # Update existing preferences
            with self.session as session:
                prefs = (
                    session.query(UserPreference)
                    .filter_by(user_id=user_id)
                    .first()
                )

                # Update fields
                for field, value in preferences.items():
                    if hasattr(prefs, field):
                        setattr(prefs, field, value)

                session.commit()
                return str(prefs.id)
        else:
            # Create new preferences
            preferences["user_id"] = user_id
            return self.create(preferences)

    def add_liked_item(
        self, user_id: str, item_id: str, item_type: str = "news"
    ) -> bool:
        """Add an item to liked list"""
        with self.session as session:
            prefs = (
                session.query(UserPreference).filter_by(user_id=user_id).first()
            )

            if not prefs:
                # Create new preferences
                prefs = UserPreference(
                    user_id=user_id,
                    liked_news_ids=[item_id] if item_type == "news" else [],
                    disliked_news_ids=[],
                )
                session.add(prefs)
            else:
                # Update existing preferences
                if item_type == "news":
                    liked_ids = prefs.liked_news_ids or []
                    if item_id not in liked_ids:
                        liked_ids.append(item_id)
                        # Keep last 100 items
                        prefs.liked_news_ids = liked_ids[-100:]

            session.commit()
            return True

    def add_disliked_item(
        self, user_id: str, item_id: str, item_type: str = "news"
    ) -> bool:
        """Add an item to disliked list"""
        with self.session as session:
            prefs = (
                session.query(UserPreference).filter_by(user_id=user_id).first()
            )

            if not prefs:
                # Create new preferences
                prefs = UserPreference(
                    user_id=user_id,
                    liked_news_ids=[],
                    disliked_news_ids=[item_id] if item_type == "news" else [],
                )
                session.add(prefs)
            else:
                # Update existing preferences
                if item_type == "news":
                    disliked_ids = prefs.disliked_news_ids or []
                    if item_id not in disliked_ids:
                        disliked_ids.append(item_id)
                        # Keep last 100 items
                        prefs.disliked_news_ids = disliked_ids[-100:]

            session.commit()
            return True

    def update_preference_embedding(
        self, user_id: str, embedding: List[float]
    ) -> bool:
        """Update the user's preference embedding"""
        with self.session as session:
            prefs = (
                session.query(UserPreference).filter_by(user_id=user_id).first()
            )

            if not prefs:
                # Create new preferences with embedding
                prefs = UserPreference(
                    user_id=user_id, preference_embedding=embedding
                )
                session.add(prefs)
            else:
                prefs.preference_embedding = embedding

            session.commit()
            return True
