from typing import Dict, List, Optional
import logging
from .persistent_cache import PersistentCache

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format="\n%(asctime)s - %(name)s - %(levelname)s - %(message)s\n",
    datefmt="%Y-%m-%d %H:%M:%S",
    force=True,
)
logger = logging.getLogger(__name__)


class CacheManager:
    _cache: Dict[str, Dict] = {}

    @classmethod
    def set_prompt_details(cls, prompt_id: str, details: Dict) -> None:
        """Store prompt details in cache with version info"""
        logger.info(f"Caching prompt details for {prompt_id}: {details}")
        cls._cache[prompt_id] = details

    @classmethod
    def get_prompt_details(cls, prompt_id: str) -> Optional[Dict]:
        """Get prompt details from cache"""
        details = cls._cache.get(prompt_id)
        logger.info(f"Retrieved prompt details for {prompt_id}: {details}")
        return details

    @classmethod
    def has_prompt_details(cls, prompt_id: str) -> bool:
        """Check if prompt details exist in cache"""
        return prompt_id in cls._cache

    @classmethod
    def print_cache_contents(cls) -> None:
        """Print all contents of the cache for debugging"""
        print("\n=== CacheManager Contents ===")
        if not cls._cache:
            print("Cache is empty")
        else:
            for key, value in cls._cache.items():
                print(f"\nKey: {key}")
                print(f"Value: {value}")

    @classmethod
    def clear_cache(cls) -> None:
        """Clear the cache"""
        cls._cache.clear()
        logger.info("CacheManager cache cleared")

    @classmethod
    def verify_cache_storage(cls, prompt_id: str) -> Dict:
        """Verify cache storage for a specific prompt"""
        verification_result = {
            "cache_exists": False,
            "details": None,
        }

        if prompt_id in cls._cache:
            verification_result.update(
                {"cache_exists": True, "details": cls._cache[prompt_id]}
            )
            logger.info(
                f"Cache verification for prompt_id={prompt_id}: {verification_result}"
            )
        else:
            logger.warning(f"No cache found for prompt_id={prompt_id}")

        return verification_result


class InteractionCacheManager:
    _interaction_cache: Dict[str, Dict] = {}
    _user_messages: Dict[str, Dict] = {}
    _prompt_version_messages: Dict[str, List] = {}
    _persistent = PersistentCache()
    _user_messages_cache = {}

    @classmethod
    def save_user_messages(cls, prompt_id: str, messages: Dict) -> None:
        """Save user messages with system message and variables"""
        logger.info(f"Saving user messages for prompt_id: {prompt_id}")
        logger.debug(f"Messages content: {messages}")
        cls._user_messages[prompt_id] = messages

    # @classmethod
    # def save_interaction(
    #     cls,
    #     session_id: str,
    #     interaction_data: Dict,
    #     prompt_id: str,
    #     version: str,
    # ) -> None:
    #     """
    #     Save interaction with hierarchical tracking and message history.
    #     Maintains a hierarchical cache structure: prompt_id -> session_id -> version -> messages

    #     Args:
    #         session_id: Unique identifier for the chat session
    #         interaction_data: Dictionary containing messages and metadata for the interaction
    #         prompt_id: ID of the prompt being used
    #         version: Version of the prompt

    #     The method:
    #     1. Creates nested dictionaries for prompt_id, session_id and version if they don't exist
    #     2. Retrieves existing messages for the given prompt/session/version
    #     3. Appends new messages from interaction_data to existing messages
    #     4. Updates both in-memory cache and persistent storage with:
    #        - Combined message history
    #        - Last response timestamp
    #        - Memory type (defaults to "fullMemory")
    #        - Window size (defaults to 10)
    #     """
    #     logger.info(
    #         f"Saving interaction - Prompt ID: {prompt_id}, Session: {session_id}, Version: {version}"
    #     )

    #     # Initialize nested cache structure if needed
    #     if prompt_id not in cls._interaction_cache:
    #         cls._interaction_cache[prompt_id] = {}
    #         logger.debug(f"Created new prompt cache for {prompt_id}")

    #     # Initialize session if not exists
    #     if session_id not in cls._interaction_cache[prompt_id]:
    #         cls._interaction_cache[prompt_id][session_id] = {}
    #         logger.debug(f"Created new session cache for {session_id}")

    #     # Initialize version if not exists
    #     if version not in cls._interaction_cache[prompt_id][session_id]:
    #         cls._interaction_cache[prompt_id][session_id][version] = {
    #             "messages": [],
    #             "lastResponseAt": None,
    #         }
    #         logger.debug(f"Created new version cache for {version}")

    #     # Get existing messages
    #     existing_messages = cls._interaction_cache[prompt_id][session_id][version].get(
    #         "messages", []
    #     )

    #     # Add new messages to existing ones
    #     new_messages = interaction_data.get("messages", [])

    #     # Combine existing and new messages while maintaining order
    #     updated_messages = existing_messages + new_messages

    #     # Update cache with combined messages
    #     cls._interaction_cache[prompt_id][session_id][version].update(
    #         {
    #             "messages": updated_messages,
    #             "lastResponseAt": interaction_data["lastResponseAt"],
    #             "memory_type": interaction_data.get("memory_type", "fullMemory"),
    #             "window_size": interaction_data.get("window_size", 10),
    #             "summarized_content": interaction_data.get("summarized_content", None),
    #         }
    #     )

    #     # Save to persistent storage
    #     cache_key = f"{prompt_id}_{session_id}_{version}"
    #     persistent_data = {
    #         "messages": updated_messages,
    #         "lastResponseAt": interaction_data["lastResponseAt"],
    #         "memory_type": interaction_data.get("memory_type", "fullMemory"),
    #         "window_size": interaction_data.get("window_size", 10),
    #         "summarized_content": interaction_data.get("summarized_content", None),
    #     }
    #     cls._persistent.save(cache_key, persistent_data)

    #     logger.info(
    #         f"Saved interaction. Total messages in cache: " f"{len(updated_messages)}"
    #     )
    #     logger.debug(
    #         f"Current cache state for {prompt_id}/{session_id}/{version}: "
    #         f"{cls._interaction_cache[prompt_id][session_id][version]}"
    #     )

    @classmethod
    def save_interaction(
        cls, session_id: str, interaction_data: Dict, prompt_id: str, version: str
    ):
        """Save interaction data to cache"""
        logger.info(f"\nSaving interaction to cache:")
        logger.info(f"Session ID: {session_id}")
        logger.info(f"Prompt ID: {prompt_id}")
        logger.info(f"Version: {version}")

        cache_key = f"{prompt_id}_{session_id}_v{version}"
        logger.info(f"Cache key: {cache_key}")

        # Get existing cache
        existing_cache = cls._interaction_cache.get(cache_key, {})
        logger.info(f"Existing cache found: {bool(existing_cache)}")
        if existing_cache:
            logger.info(
                f"Previous summarized_content: {existing_cache.get('summarized_content', 'None')}"
            )

        # Update with new data
        if not existing_cache:
            existing_cache = {"messages": [], "summarized_content": None}

        existing_cache["messages"].extend(interaction_data["messages"])
        existing_cache["lastResponseAt"] = interaction_data["lastResponseAt"]
        existing_cache["memory_type"] = interaction_data["memory_type"]

        # Update summarized_content
        if interaction_data["memory_type"] == "summarizedMemory":
            existing_cache["summarized_content"] = interaction_data[
                "summarized_content"
            ]
            logger.info(
                f"Updated summarized_content: {existing_cache['summarized_content']}"
            )

        # Save to cache
        cls._interaction_cache[cache_key] = existing_cache
        logger.info("Cache updated successfully")

        # Verify save
        saved_cache = cls._interaction_cache.get(cache_key, {})
        logger.info("\nVerifying saved data:")
        logger.info(
            f"Saved summarized_content: {saved_cache.get('summarized_content', 'None')}"
        )

    @classmethod
    def print_cache_contents(cls):
        logger.info("=== Interaction Cache Contents ===")
        if not cls._interaction_cache:
            logger.info("Interaction cache is empty")
        else:
            for key, value in cls._interaction_cache.items():
                logger.info(f"Key: {key}")
                logger.info(f"Value: {value}")

        logger.info("\n=== User Messages Cache Contents ===")
        if not cls._user_messages_cache:
            logger.info("User messages cache is empty")
        else:
            for key, value in cls._user_messages_cache.items():
                logger.info(f"Key: {key}")
                logger.info(f"Value: {value}")

    @classmethod
    def get_interaction_history(
        cls, prompt_id: str, session_id: str, version: str
    ) -> Optional[Dict]:
        """Get interaction history with persistence"""
        # Try memory cache first
        # history = (
        #     cls._interaction_cache.get(prompt_id, {}).get(session_id, {}).get(version)
        # )
        cache_key = f"{prompt_id}_{session_id}_v{version}"
        history = cls._interaction_cache.get(cache_key)

        # If not in memory, try persistent storage
        if not history:
            cache_key = f"{prompt_id}_{session_id}_{version}"
            history = cls._persistent.load(cache_key)
            if history:
                # Update memory cache
                if prompt_id not in cls._interaction_cache:
                    cls._interaction_cache[prompt_id] = {}
                if session_id not in cls._interaction_cache[prompt_id]:
                    cls._interaction_cache[prompt_id][session_id] = {}
                cls._interaction_cache[prompt_id][session_id][version] = history

        return history

    @classmethod
    def get_all_prompt_interactions(cls, prompt_id: str) -> Dict:
        """Get all interactions for a specific prompt across all sessions and versions"""
        interactions = cls._interaction_cache.get(prompt_id, {})
        logger.info(f"Retrieved all interactions for prompt ID: {prompt_id}")
        logger.debug(f"Interactions content: {interactions}")
        return interactions

    @classmethod
    def clear_cache(cls) -> None:
        """Clear both memory and persistent cache"""
        cls._interaction_cache.clear()
        cls._user_messages.clear()
        cls._prompt_version_messages.clear()
        cls._persistent.clear()
        logger.info("Cleared all cache (memory and persistent)")

    # @classmethod
    # def print_cache_contents(cls) -> None:
    #     """Print all contents of different caches for debugging"""
    #     print("\n=== Interaction Cache Contents ===")
    #     if not cls._interaction_cache:
    #         print("Interaction cache is empty")
    #     for prompt_id, sessions in cls._interaction_cache.items():
    #         print(f"\nPrompt ID: {prompt_id}")
    #         for session_id, versions in sessions.items():
    #             print(f"  Session ID: {session_id}")
    #             for version, data in versions.items():
    #                 print(f"    Version: {version}")
    #                 print(f"    Messages: {data['messages']}")
    #                 print(f"    Last Response At: {data['lastResponseAt']}")

    #     print("\n=== User Messages Cache Contents ===")
    #     if not cls._user_messages:
    #         print("User messages cache is empty")
    #     for key, value in cls._user_messages.items():
    #         print(f"\nPrompt ID: {key}")
    #         print(f"Messages: {value}")

    @classmethod
    def verify_cache_storage(
        cls, prompt_id: str, session_id: str, version: str
    ) -> Dict:
        """
        Verify cache storage for a specific prompt, session and version
        Returns a dictionary with cache verification details
        """
        verification_result = {
            "cache_exists": False,
            "message_count": 0,
            "last_message": None,
            "cache_details": None,
        }

        try:
            # Check if cache exists for this combination
            if (
                prompt_id in cls._interaction_cache
                and session_id in cls._interaction_cache[prompt_id]
                and version in cls._interaction_cache[prompt_id][session_id]
            ):

                cache_data = cls._interaction_cache[prompt_id][session_id][version]
                messages = cache_data.get("messages", [])

                verification_result.update(
                    {
                        "cache_exists": True,
                        "message_count": len(messages),
                        "last_message": messages[-1] if messages else None,
                        "cache_details": {
                            "lastResponseAt": cache_data.get("lastResponseAt"),
                            "total_interactions": len(messages)
                            // 2,  # user + assistant messages
                        },
                    }
                )

                logger.info(
                    f"Cache verification for prompt_id={prompt_id}, "
                    f"session_id={session_id}, version={version}: {verification_result}"
                )
            else:
                logger.warning(
                    f"No cache found for prompt_id={prompt_id}, "
                    f"session_id={session_id}, version={version}"
                )

        except Exception as e:
            logger.error(f"Error verifying cache: {str(e)}")
            verification_result["error"] = str(e)

        return verification_result
