"""Cached service implementations using dogpile.cache.

This module provides cached versions of search and API cache functionality.
"""

from typing import Any, Dict, List, Optional
from dogpile.cache.api import NO_VALUE
from loguru import logger
from sqlalchemy.orm import Session

from .config import get_thread_local_cache


class CachedSearchCache:
    """Replacement for search_cache.py using dogpile.cache."""

    def __init__(self, user_id: str):
        """Initialize cached search cache.

        Args:
            user_id: User identifier
        """
        self.user_id = str(user_id)
        self.cache = get_thread_local_cache()

    def get(
        self, search_query: str, search_engine: str
    ) -> Optional[List[Dict[str, Any]]]:
        """Get cached search results.

        Args:
            search_query: Search query
            search_engine: Search engine name

        Returns:
            Cached search results or None
        """
        key = f"{search_engine}:{search_query}"
        value = self.cache.get(self.user_id, "search_results", key)

        if value is NO_VALUE:
            return None

        return value

    def set(
        self,
        search_query: str,
        search_engine: str,
        results: List[Dict[str, Any]],
        ttl: int = 3600,
    ) -> None:
        """Cache search results.

        Args:
            search_query: Search query
            search_engine: Search engine name
            results: Search results
            ttl: Time to live in seconds
        """
        key = f"{search_engine}:{search_query}"
        self.cache.set(
            self.user_id, "search_results", key, results, expiration_time=ttl
        )

    def invalidate_all(self) -> None:
        """Invalidate all search results for user."""
        self.cache.invalidate(self.user_id, "search_results")


class CachedAPICache:
    """Replacement for database/models/cache.py using dogpile.cache."""

    def __init__(self, user_id: str):
        """Initialize cached API cache.

        Args:
            user_id: User identifier
        """
        self.user_id = str(user_id)
        self.cache = get_thread_local_cache()

    def get(self, cache_key: str) -> Optional[Any]:
        """Get cached API response.

        Args:
            cache_key: Cache key

        Returns:
            Cached value or None
        """
        value = self.cache.get(self.user_id, "api_cache", cache_key)

        if value is NO_VALUE:
            return None

        return value

    def set(
        self,
        cache_key: str,
        value: Any,
        ttl: int = 86400,  # 24 hours default
    ) -> None:
        """Cache API response.

        Args:
            cache_key: Cache key
            value: Value to cache
            ttl: Time to live in seconds
        """
        self.cache.set(
            self.user_id, "api_cache", cache_key, value, expiration_time=ttl
        )

    def delete(self, cache_key: str) -> None:
        """Delete specific cache entry.

        Args:
            cache_key: Cache key to delete
        """
        # Dogpile doesn't have per-key deletion in our implementation
        # This would need to be enhanced for production
        logger.warning(f"Per-key deletion not implemented for {cache_key}")

    def get_hit_count(self, cache_key: str) -> int:
        """Get hit count for cache key.

        Args:
            cache_key: Cache key

        Returns:
            Hit count (not tracked in dogpile by default)
        """
        # Would need custom implementation to track hit counts
        return 0


class CachedResearchService:
    """Cached service for research reports and data."""

    def __init__(self, session: Session, user_id: str):
        """Initialize cached research service.

        Args:
            session: SQLAlchemy session
            user_id: User identifier
        """
        self.session = session
        self.user_id = str(user_id)
        self.cache = get_thread_local_cache()

    def save_report(
        self,
        research_id: str,
        report_content: str,
        metadata: Dict[str, Any] = None,
    ) -> bool:
        """Save research report to database and cache.

        Args:
            research_id: Research ID
            report_content: Report content in markdown
            metadata: Optional metadata

        Returns:
            True if successful
        """
        try:
            from ..database.models import ResearchHistory

            # Update database
            research = (
                self.session.query(ResearchHistory)
                .filter_by(id=research_id)
                .first()
            )

            if not research:
                logger.error(f"Research {research_id} not found")
                return False

            # Store report content in database
            research.report_content = report_content

            # Update metadata if provided
            if metadata:
                if research.research_meta:
                    research.research_meta.update(metadata)
                else:
                    research.research_meta = metadata

            self.session.commit()

            # Cache the report
            self.cache.set(
                self.user_id,
                "research_reports",
                research_id,
                report_content,
                expiration_time=86400,  # 24 hours
            )

            # Also cache metadata
            if metadata:
                self.cache.set(
                    self.user_id,
                    "research_metadata",
                    research_id,
                    metadata,
                    expiration_time=86400,
                )

            logger.info(f"Saved report for research {research_id}")
            return True

        except Exception:
            logger.exception("Error saving research report")
            self.session.rollback()
            return False

    def get_report(
        self, research_id: str, use_cache: bool = True
    ) -> Optional[str]:
        """Get research report from cache or database.

        Args:
            research_id: Research ID
            use_cache: Whether to use cache

        Returns:
            Report content or None
        """
        if use_cache:
            # Try cache first
            value = self.cache.get(
                self.user_id, "research_reports", research_id
            )
            if value is not NO_VALUE:
                return value

        try:
            from ..database.models import ResearchHistory

            # Get from database
            research = (
                self.session.query(ResearchHistory)
                .filter_by(id=research_id)
                .first()
            )

            if not research or not research.report_content:
                return None

            report_content = research.report_content

            # Cache it
            if use_cache:
                self.cache.set(
                    self.user_id,
                    "research_reports",
                    research_id,
                    report_content,
                    expiration_time=86400,
                )

            return report_content

        except Exception:
            logger.exception("Error getting research report")
            return None

    def invalidate_report(self, research_id: str) -> None:
        """Invalidate cached report.

        Args:
            research_id: Research ID
        """
        # Invalidate specific report
        # Note: dogpile doesn't support per-key invalidation in our setup
        # Would need to enhance for production
        logger.info(f"Invalidating cache for research {research_id}")
