from typing import List, Optional
from datetime import datetime
import uuid
from analogai.foundation.extensions.conversation.repositories.conversation_repository import ConversationRepository
from analogai.foundation.extensions.conversation.conversation import Conversation
from analogai.foundation.extensions.conversation.turn import Turn
from analogai.foundation.modules.user.user import User
from analogai.foundation.modules.agent.agent import Agent


class InMemoryConversationRepositoryImpl(ConversationRepository):

    def __init__(self):
        self._conversations: dict[str, Conversation] = {}
        self._turns: dict[str, List[Turn]] = {}

    def create_conversation(self, user_id: str, agent_id: str) -> Conversation:
        conversation_id = str(uuid.uuid4())
        now = datetime.now()

        user = User(id=user_id, name="", email="")
        agent_creator = User(id="system", name="", email="")
        agent = Agent(id=agent_id, knowledge_base="", creator=agent_creator)

        conversation = Conversation(
            id=conversation_id,
            user=user,
            agent=agent,
            created_at=now,
            updated_at=now
        )

        self._conversations[conversation_id] = conversation
        self._turns[conversation_id] = []

        return conversation

    def find_by_id(self, conversation_id: str) -> Optional[Conversation]:
        conversation = self._conversations.get(conversation_id)
        if conversation:
            conversation.turns = self._turns.get(conversation_id, [])
        return conversation

    def find_by_agent(self, agent_id: str, page: int = 1, page_size: int = 10) -> List[Conversation]:
        conversations = [
            conv for conv in self._conversations.values()
            if conv.agent.id == agent_id
        ]

        conversations.sort(key=lambda x: x.updated_at, reverse=True)

        start_idx = (page - 1) * page_size
        end_idx = start_idx + page_size

        result = conversations[start_idx:end_idx]
        for conv in result:
            conv.turns = self._turns.get(conv.id, [])

        return result

    def find_latest_by_user_and_agent(self, user_id: str, agent_id: str) -> Optional[Conversation]:
        candidates = [
            conv for conv in self._conversations.values()
            if conv.user.id == user_id and conv.agent.id == agent_id
        ]
        if not candidates:
            return None
        candidates.sort(key=lambda x: x.updated_at, reverse=True)
        latest = candidates[0]
        latest.turns = self._turns.get(latest.id, [])
        return latest

    def add_turn(self, conversation_id: str, turn: Turn) -> Turn:
        if conversation_id not in self._conversations:
            raise ValueError(f"Conversation {conversation_id} not found")

        conversation = self._conversations[conversation_id]
        conversation.add_turn(turn)

        if conversation_id not in self._turns:
            self._turns[conversation_id] = []
        if turn not in self._turns[conversation_id]:
            self._turns[conversation_id].append(turn)

        return turn

    def delete_conversation(self, conversation_id: str) -> bool:
        if conversation_id in self._conversations:
            del self._conversations[conversation_id]
            if conversation_id in self._turns:
                del self._turns[conversation_id]
            return True
        return False
