import asyncio
import json
import logging
import uuid
from datetime import datetime, timedelta, timezone
from typing import Any

from common.cache import get_redis_cache
from config import REDIS_CACHE_TURN_ON

logger = logging.getLogger(__name__)

CHAT_HISTORY_TTL = 1800  # 30 minutes in seconds

class ConversationManager:
    """
    Redis-backed Conversation Manager for LangGraph agents.
    Stores chat history with a TTL of 30 minutes.
    """
    def __init__(self):
        self._enabled = REDIS_CACHE_TURN_ON

    async def initialize_table(self):
        """No-op for Redis, kept for backward compatibility."""
        if self._enabled:
            logger.info("🟢 Redis ConversationManager initialized (TTL 30mins)")
        else:
            logger.warning("🟡 Redis Cache is disabled, history won't be saved!")

    def _get_redis_key(self, identity_key: str, conversation_id: str | None = None) -> str:
        if conversation_id:
            return f"chat_history:{identity_key}:{conversation_id}"
        return f"chat_history:{identity_key}:default"

    async def save_conversation_turn(self, identity_key: str, human_message: str, ai_message: str, conversation_id: str | None = None):
        """Save both human and AI messages to a Redis list."""
        if not self._enabled:
            return

        client = get_redis_cache().get_client()
        if not client:
            return

        try:
            vietnam_tz = timezone(timedelta(hours=7))
            timestamp = datetime.now(vietnam_tz).isoformat()
            
            # Khởi tạo ID giả lập từ timestamp
            base_id = int(datetime.now().timestamp() * 1000)
            human_id = base_id
            ai_id = base_id + 1

            human_entry = {
                "id": human_id,
                "message": human_message,
                "is_human": True,
                "timestamp": timestamp,
                "conversation_id": conversation_id
            }

            ai_entry = {
                "id": ai_id,
                "message": ai_message,
                "is_human": False,
                "timestamp": timestamp,
                "conversation_id": conversation_id
            }

            key = self._get_redis_key(identity_key, conversation_id)
            
            # Push vào Redis
            await client.rpush(key, json.dumps(human_entry))
            await client.rpush(key, json.dumps(ai_entry))
            # Set TTL 30 minutes
            await client.expire(key, CHAT_HISTORY_TTL)

            logger.debug(f"Saved conversation turn to Redis for {key} (TTL {CHAT_HISTORY_TTL}s)")
        except Exception as e:
            logger.error(f"Failed to save conversation for identity_key {identity_key}: {e}", exc_info=True)

    async def get_chat_history(
        self,
        identity_key: str,
        limit: int | None = None,
        before_id: int | None = None,
        include_product_ids: bool = True,
        skip_date_filter: bool = False,
        date_from: str | None = None,
        date_to: str | None = None,
        conversation_id: str | None = None,
    ) -> list[dict[str, Any]]:
        """
        Retrieve chat history from Redis.
        """
        if not self._enabled:
            return []

        client = get_redis_cache().get_client()
        if not client:
            return []

        try:
            key = self._get_redis_key(identity_key, conversation_id)
            # Fetch all elements from the list
            items = await client.lrange(key, 0, -1)
            
            history = []
            for item in items:
                try:
                    data = json.loads(item)
                    is_human = data.get("is_human", False)
                    # Support old string timestamps by converting back to datetime if needed, 
                    # but we'll just keep the structure compatible.
                    
                    entry = {
                        "is_human": is_human,
                        "timestamp": datetime.fromisoformat(data["timestamp"]) if "timestamp" in data else datetime.now(),
                        "id": data.get("id", 0),
                        "conversation_id": data.get("conversation_id"),
                    }

                    message_content = data.get("message", "")

                    if is_human:
                        entry["message"] = message_content
                    else:
                        # Giữ nguyên raw JSON string để frontend parse được products + lead_stage
                        # Frontend sẽ tự JSON.parse và extract ai_response, products, lead_stage
                        entry["message"] = message_content
                        if include_product_ids:
                            try:
                                parsed = json.loads(message_content)
                                entry["product_ids"] = parsed.get("product_ids", parsed.get("products", []))
                            except (json.JSONDecodeError, TypeError):
                                entry["product_ids"] = []

                    history.append(entry)
                except Exception as e:
                    logger.warning(f"Error parsing redis history item: {e}")

            # Đảo ngược mảng để match behavior cũ (ORDER BY id DESC)
            history.reverse()

            # Lọc theo before_id
            if before_id:
                history = [h for h in history if h["id"] < before_id]

            # Giới hạn limit
            if limit:
                history = history[:limit]

            return history
        except Exception as e:
            logger.error(f"Error retrieving chat history from Redis: {e}")
            return []

    async def archive_history(self, identity_key: str, conversation_id: str | None = None) -> str:
        """Archive current chat history in Redis."""
        if not self._enabled:
            return ""
        
        client = get_redis_cache().get_client()
        if not client:
            return ""
            
        try:
            timestamp_suffix = datetime.now().strftime("%Y%m%d_%H%M%S")
            new_conv_id = f"{conversation_id or 'default'}_archived_{timestamp_suffix}"
            
            old_key = self._get_redis_key(identity_key, conversation_id)
            new_key = self._get_redis_key(identity_key, new_conv_id)
            
            if await client.exists(old_key):
                await client.rename(old_key, new_key)
                await client.expire(new_key, CHAT_HISTORY_TTL)
                logger.info(f"Archived history for {identity_key} to {new_key}")
            
            return new_conv_id
        except Exception as e:
            logger.error(f"Error archiving history: {e}")
            return ""

    async def clear_history(self, identity_key: str, conversation_id: str | None = None):
        """Clear all chat history for an identity."""
        if not self._enabled:
            return
            
        client = get_redis_cache().get_client()
        if not client:
            return
            
        try:
            key = self._get_redis_key(identity_key, conversation_id)
            await client.delete(key)
            logger.info(f"Cleared chat history from Redis for {key}")
        except Exception as e:
            logger.error(f"Error clearing chat history: {e}")

    async def get_user_count(self) -> int:
        """Count unique users in Redis. Approximate and slow, just a mock for now."""
        if not self._enabled:
            return 0
            
        client = get_redis_cache().get_client()
        if not client:
            return 0
            
        try:
            keys = await client.keys("chat_history:*")
            # Extract unique identity_keys
            users = set()
            for key in keys:
                parts = key.split(":")
                if len(parts) >= 2:
                    users.add(parts[1])
            return len(users)
        except Exception as e:
            logger.error(f"Error getting user count from Redis: {e}")
            return 0

    async def get_message_count_today(self, identity_key: str) -> int:
        """Count human messages. Since TTL is 30 mins, we just count all human messages in Redis for this user."""
        if not self._enabled:
            return 0
            
        client = get_redis_cache().get_client()
        if not client:
            return 0
            
        try:
            keys = await client.keys(f"chat_history:{identity_key}:*")
            count = 0
            for key in keys:
                items = await client.lrange(key, 0, -1)
                for item in items:
                    data = json.loads(item)
                    if data.get("is_human", False):
                        count += 1
            return count
        except Exception as e:
            logger.error(f"Error counting messages for {identity_key} from Redis: {e}")
            return 0

    async def close(self):
        """No-op for Redis client which is managed externally"""
        pass

# --- Singleton ---
_instance: ConversationManager | None = None

async def get_conversation_manager() -> ConversationManager:
    """Get or create ConversationManager singleton"""
    global _instance
    if _instance is None:
        _instance = ConversationManager()
        await _instance.initialize_table()
    return _instance
