"""
Web Session Manager - Manage conversation sessions

Handles session lifecycle, message storage, and agent coordination
for the web interface.
"""

import asyncio
import uuid
from datetime import datetime
from pathlib import Path
from typing import Any, AsyncIterator, Optional

from groknroll.web.types import (
    AgentType,
    Message,
    MessageRole,
    SessionDetail,
    SessionInfo,
    SessionStatus,
    StreamChunk,
)


class WebSession:
    """
    Represents a single chat session

    Stores conversation history and manages agent interaction.
    """

    def __init__(
        self,
        session_id: str,
        name: Optional[str] = None,
        agent: AgentType = AgentType.BUILD,
        project_path: Optional[Path] = None,
    ):
        self.id = session_id
        self.name = name
        self.agent = agent
        self.status = SessionStatus.ACTIVE
        self.created_at = datetime.now()
        self.updated_at = datetime.now()
        self.messages: list[Message] = []
        self.project_path = project_path or Path.cwd()
        self._agent_instance: Optional[Any] = None

    def add_message(self, role: MessageRole, content: str, **kwargs) -> Message:
        """Add a message to the session"""
        message = Message(
            role=role,
            content=content,
            timestamp=datetime.now(),
            **kwargs,
        )
        self.messages.append(message)
        self.updated_at = datetime.now()
        return message

    def get_conversation_history(self) -> list[dict[str, Any]]:
        """Get conversation history in format for LLM"""
        history = []
        for msg in self.messages:
            history.append(
                {
                    "role": msg.role.value,
                    "content": msg.content,
                }
            )
        return history

    def to_info(self) -> SessionInfo:
        """Convert to SessionInfo"""
        return SessionInfo(
            id=self.id,
            name=self.name,
            agent=self.agent,
            status=self.status,
            created_at=self.created_at,
            updated_at=self.updated_at,
            message_count=len(self.messages),
        )

    def to_detail(self) -> SessionDetail:
        """Convert to SessionDetail"""
        return SessionDetail(
            id=self.id,
            name=self.name,
            agent=self.agent,
            status=self.status,
            created_at=self.created_at,
            updated_at=self.updated_at,
            message_count=len(self.messages),
            messages=self.messages,
        )


class WebSessionManager:
    """
    Manager for web sessions

    Handles creation, retrieval, and deletion of sessions.
    Thread-safe for concurrent access.
    """

    def __init__(self, project_path: Optional[Path] = None):
        self.project_path = project_path or Path.cwd()
        self._sessions: dict[str, WebSession] = {}
        self._lock = asyncio.Lock()

    async def create_session(
        self,
        name: Optional[str] = None,
        agent: AgentType = AgentType.BUILD,
    ) -> WebSession:
        """Create a new session"""
        session_id = str(uuid.uuid4())

        async with self._lock:
            session = WebSession(
                session_id=session_id,
                name=name,
                agent=agent,
                project_path=self.project_path,
            )
            self._sessions[session_id] = session

        return session

    async def get_session(self, session_id: str) -> Optional[WebSession]:
        """Get a session by ID"""
        return self._sessions.get(session_id)

    async def get_or_create_session(
        self,
        session_id: Optional[str] = None,
        agent: AgentType = AgentType.BUILD,
    ) -> WebSession:
        """Get existing session or create new one"""
        if session_id:
            session = await self.get_session(session_id)
            if session:
                return session

        return await self.create_session(agent=agent)

    async def list_sessions(self) -> list[SessionInfo]:
        """List all sessions"""
        return [session.to_info() for session in self._sessions.values()]

    async def delete_session(self, session_id: str) -> bool:
        """Delete a session"""
        async with self._lock:
            if session_id in self._sessions:
                del self._sessions[session_id]
                return True
            return False

    async def clear_sessions(self) -> int:
        """Clear all sessions"""
        async with self._lock:
            count = len(self._sessions)
            self._sessions.clear()
            return count

    async def chat(
        self,
        session: WebSession,
        message: str,
        files: Optional[list[str]] = None,
    ) -> Message:
        """
        Send a message and get a response (non-streaming)

        Args:
            session: The session to use
            message: User message
            files: Optional files to reference

        Returns:
            Assistant's response message
        """
        # Add user message
        session.add_message(MessageRole.USER, message)

        # Get response from agent
        try:
            from groknroll.core.agent import GroknrollAgent

            agent = GroknrollAgent(session.project_path)

            # Build context with files
            context = message
            if files:
                context = f"Files: {', '.join(files)}\n\n{message}"

            response = agent.chat(context)

            # Add assistant message
            return session.add_message(MessageRole.ASSISTANT, response)

        except Exception as e:
            session.status = SessionStatus.ERROR
            return session.add_message(
                MessageRole.ASSISTANT,
                f"Error: {str(e)}",
            )

    async def chat_stream(
        self,
        session: WebSession,
        message: str,
        files: Optional[list[str]] = None,
    ) -> AsyncIterator[StreamChunk]:
        """
        Send a message and stream the response

        Args:
            session: The session to use
            message: User message
            files: Optional files to reference

        Yields:
            StreamChunk objects with response content
        """
        # Add user message
        session.add_message(MessageRole.USER, message)

        try:
            from groknroll.core.agent import GroknrollAgent

            agent = GroknrollAgent(session.project_path)

            # Build context with files
            context = message
            if files:
                context = f"Files: {', '.join(files)}\n\n{message}"

            # For now, simulate streaming by yielding the full response
            # In a real implementation, this would use streaming API
            response = agent.chat(context)

            # Yield response in chunks (simulated streaming)
            chunk_size = 50
            for i in range(0, len(response), chunk_size):
                chunk = response[i : i + chunk_size]
                yield StreamChunk(
                    session_id=session.id,
                    type="text",
                    content=chunk,
                )
                await asyncio.sleep(0.01)  # Small delay for streaming effect

            # Add complete message
            session.add_message(MessageRole.ASSISTANT, response)

            # Signal completion
            yield StreamChunk(
                session_id=session.id,
                type="done",
            )

        except Exception as e:
            session.status = SessionStatus.ERROR
            yield StreamChunk(
                session_id=session.id,
                type="error",
                content=str(e),
            )


# Singleton instance
_session_manager: Optional[WebSessionManager] = None


def get_session_manager(project_path: Optional[Path] = None) -> WebSessionManager:
    """Get the global session manager instance"""
    global _session_manager
    if _session_manager is None:
        _session_manager = WebSessionManager(project_path)
    return _session_manager


def reset_session_manager() -> None:
    """Reset the global session manager (for testing)"""
    global _session_manager
    _session_manager = None
