"""
Memory management API routes.
Provides memory viewing, adding, and deletion features.
"""

import logging
from typing import Literal, Optional, List, Dict, Any
from fastapi import APIRouter, HTTPException, Header, Query
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field

logger = logging.getLogger('app')

router = APIRouter(prefix="/api/v1", tags=["memory"])


class MemoryItem(BaseModel):
    """Memory item data model."""
    id: str
    content: str
    created_at: Optional[str] = None
    updated_at: Optional[str] = None


class MemoryListResponse(BaseModel):
    """Memory list response."""
    memories: List[MemoryItem]
    total: int


class DeleteAllResponse(BaseModel):
    """Delete-all memories response."""
    deleted_count: int


class ConversationMessage(BaseModel):
    """Conversation message."""
    role: Literal["user", "assistant"]
    content: str = Field(..., min_length=1)


class AddMemoryRequest(BaseModel):
    """Request body for adding memories."""
    bot_id: str = Field(..., min_length=1)
    user_id: str = Field(..., min_length=1)
    messages: List[ConversationMessage] = Field(..., max_length=200)


class AddMemoryResponse(BaseModel):
    """Response for adding memories."""
    success: bool
    pairs_processed: int
    pairs_failed: int = 0


async def get_user_identifier_from_request(
    authorization: Optional[str],
    user_id: Optional[str] = None
) -> str:
    """
    Get the user identifier

    Prefer the user_id from request parameters; otherwise try to parse it from the Authorization header

    Args:
        authorization: Authorization header
        user_id: user_id from request parameters

    Returns:
        User identifier

    Raises:
        HTTPException: If the user identifier cannot be determined
    """
    if user_id:
        return user_id

    # Raise an exception if user_id is not provided
    # Note: According to the PRD, user_id is passed from the frontend
    raise HTTPException(
        status_code=400,
        detail="user_id is required"
    )


@router.post("/memory", response_model=AddMemoryResponse)
async def add_memory_from_conversation(data: AddMemoryRequest):
    """
    Extract and save memories from conversation messages

    Pairs user and assistant messages, then uses Mem0 to extract and store key facts.
    Used for scenarios such as realtime voice conversations that do not go through the Agent middleware.
    This endpoint is intended for internal services such as felo-mygpt and is not exposed to external users.
    """
    try:
        from agent.mem0_manager import get_mem0_manager
        from utils.settings import MEM0_ENABLED

        if not MEM0_ENABLED:
            raise HTTPException(
                status_code=503,
                detail="Memory feature is not enabled"
            )

        if not data.messages:
            return AddMemoryResponse(success=True, pairs_processed=0)

        manager = get_mem0_manager()

        # Pair messages into user-assistant pairs and then call add_memory
        pairs_processed = 0
        pairs_failed = 0
        i = 0
        while i < len(data.messages):
            msg = data.messages[i]
            if msg.role == 'user':
                # Collect consecutive user messages
                user_contents = [msg.content]
                j = i + 1
                while j < len(data.messages) and data.messages[j].role == 'user':
                    user_contents.append(data.messages[j].content)
                    j += 1

                user_text = '\n'.join(user_contents)

                # Check whether there is a corresponding assistant reply
                assistant_text = ""
                if j < len(data.messages) and data.messages[j].role == 'assistant':
                    assistant_text = data.messages[j].content or ""
                    j += 1

                if user_text and assistant_text:
                    conversation_text = f"User: {user_text}\nAssistant: {assistant_text}"
                    try:
                        await manager.add_memory(
                            text=conversation_text,
                            user_id=data.user_id,
                            agent_id=data.bot_id,
                            metadata={"type": "realtime_conversation"},
                        )
                        pairs_processed += 1
                    except Exception as pair_error:
                        pairs_failed += 1
                        logger.error(
                            f"Failed to add memory for pair: {pair_error}"
                        )

                i = j
            else:
                i += 1

        logger.info(
            f"Added {pairs_processed} memory pairs (failed={pairs_failed}) "
            f"for user={data.user_id}, bot={data.bot_id}"
        )
        return AddMemoryResponse(
            success=pairs_failed == 0,
            pairs_processed=pairs_processed,
            pairs_failed=pairs_failed,
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to add memory from conversation: {e}")
        raise HTTPException(
            status_code=500,
            detail="Failed to add memory from conversation"
        )


@router.get("/memory", response_model=MemoryListResponse)
async def get_memories(
    bot_id: str = Query(..., description="Bot ID (corresponds to agent_id)"),
    user_id: str = Query(..., description="User ID"),
    authorization: Optional[str] = Header(None, description="Authorization header"),
):
    """
    Get all memories for the current user under the specified bot

    Args:
        bot_id: Bot ID (corresponds to agent_id)
        user_id: User identifier
        authorization: Authorization header (for authentication)

    Returns:
        MemoryListResponse: Memory list
    """
    try:
        from agent.mem0_manager import get_mem0_manager
        from utils.settings import MEM0_ENABLED

        # Check whether the memory feature is enabled
        if not MEM0_ENABLED:
            raise HTTPException(
                status_code=503,
                detail="Memory feature is not enabled"
            )

        # Get the Mem0Manager instance
        manager = get_mem0_manager()

        # Get all memories
        memories = await manager.get_all_memories(
            user_id=user_id,
            agent_id=bot_id
        )

        # Convert to the response format
        memory_items = []
        for m in memories:
            memory_items.append(MemoryItem(
                id=m.get("id", ""),
                content=m.get("memory", ""),
                created_at=m.get("created_at"),
                updated_at=m.get("updated_at")
            ))

        return MemoryListResponse(
            memories=memory_items,
            total=len(memory_items)
        )

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to get memories: {e}")
        raise HTTPException(
            status_code=500,
            detail=f"Failed to get memories: {str(e)}"
        )


@router.delete("/memory/{memory_id}", status_code=204)
async def delete_memory(
    memory_id: str,
    bot_id: str = Query(..., description="Bot ID (used for permission validation)"),
    user_id: str = Query(..., description="User ID"),
    authorization: Optional[str] = Header(None, description="Authorization header"),
):
    """
    Delete a single memory

    Args:
        memory_id: Memory ID
        bot_id: Bot ID (used for permission validation)
        user_id: User identifier
        authorization: Authorization header

    Returns:
        204 No Content
    """
    try:
        from agent.mem0_manager import get_mem0_manager
        from utils.settings import MEM0_ENABLED

        # Check whether the memory feature is enabled
        if not MEM0_ENABLED:
            raise HTTPException(
                status_code=503,
                detail="Memory feature is not enabled"
            )

        # Get the Mem0Manager instance
        manager = get_mem0_manager()

        # Delete the memory
        success = await manager.delete_memory(
            memory_id=memory_id,
            user_id=user_id,
            agent_id=bot_id
        )

        if not success:
            raise HTTPException(
                status_code=404,
                detail="Memory not found or delete failed"
            )

        return JSONResponse(status_code=204, content=None)

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to delete memory {memory_id}: {e}")
        raise HTTPException(
            status_code=500,
            detail=f"Failed to delete memory: {str(e)}"
        )


@router.delete("/memory", response_model=DeleteAllResponse)
async def delete_all_memories(
    bot_id: str = Query(..., description="Bot ID"),
    user_id: str = Query(..., description="User ID"),
    authorization: Optional[str] = Header(None, description="Authorization header"),
):
    """
    Clear all memories for the current user under the specified bot

    Args:
        bot_id: Bot ID
        user_id: User identifier
        authorization: Authorization header

    Returns:
        DeleteAllResponse: Number of deleted memories
    """
    try:
        from agent.mem0_manager import get_mem0_manager
        from utils.settings import MEM0_ENABLED

        # Check whether the memory feature is enabled
        if not MEM0_ENABLED:
            raise HTTPException(
                status_code=503,
                detail="Memory feature is not enabled"
            )

        # Get the Mem0Manager instance
        manager = get_mem0_manager()

        # Delete all memories
        deleted_count = await manager.delete_all_memories(
            user_id=user_id,
            agent_id=bot_id
        )

        return DeleteAllResponse(deleted_count=deleted_count)

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to delete all memories: {e}")
        raise HTTPException(
            status_code=500,
            detail=f"Failed to delete all memories: {str(e)}"
        )
