"""REST endpoint for sending a message to an agent (non-streaming)."""

from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel

from navi.api.deps import get_agent, get_orchestrator, get_session_store, require_user
from navi.auth import User
from navi.auth.deps import check_session_access
from navi.core import Agent, SessionStore
from navi.exceptions import MaxIterationsReached, NaviError, SessionNotFound

router = APIRouter(prefix="/sessions", tags=["messages"])


class SendMessageRequest(BaseModel):
    content: str


@router.post("/{session_id}/messages")
async def send_message(
    session_id: str,
    body: SendMessageRequest,
    agent: Annotated[Agent, Depends(get_agent)],
    store: Annotated[SessionStore, Depends(get_session_store)],
    user: Annotated[User, Depends(require_user)],
) -> dict:
    session = await store.get(session_id)
    if session is None:
        raise HTTPException(status_code=404, detail="Session not found")
    check_session_access(session, user)

    # Guard against a second run on the same session (e.g. an active WS turn):
    # mark_busy publishes "running" to is_running()/stop() the same way the
    # WS path does. The lock is held only for the check-and-mark, not the run
    # itself, so a long REST turn does not stall other requests.
    orchestrator = get_orchestrator()
    async with orchestrator.session_lock(session_id):
        if orchestrator.is_running(session_id):
            raise HTTPException(status_code=409, detail="Agent is already running for this session")
        orchestrator.mark_busy(session_id)

    # Set user context for tool sandboxing (reset in finally — these
    # contextvars otherwise leak to the next request on the same task).
    from navi.tools._internal.base import current_user_id as _uid_var, current_user_role as _role_var, current_user_info as _uinfo_var
    uid_token = _uid_var.set(user.id)
    role_token = _role_var.set(user.role)
    uinfo_token = _uinfo_var.set(user.model_dump(mode="json"))

    try:
        reply = await agent.run(session_id, body.content)
        return {"role": "assistant", "content": reply}
    except SessionNotFound:
        raise HTTPException(status_code=404, detail="Session not found")
    except MaxIterationsReached as e:
        raise HTTPException(status_code=500, detail=str(e))
    except NaviError as e:
        raise HTTPException(status_code=500, detail=str(e))
    finally:
        _uid_var.reset(uid_token)
        _role_var.reset(role_token)
        _uinfo_var.reset(uinfo_token)
        await orchestrator.clear_busy(session_id)
