"""Chat session route handlers - /chat/*, /sessions/* endpoints."""

from __future__ import annotations

from datetime import UTC, datetime
from typing import TYPE_CHECKING, Any

from fastapi import HTTPException

from ..schemas import (
    ChatSession,
    ChatSessionsResponse,
    CreateChatSessionRequest,
    UpdateChatSessionRequest,
    TaskRunActionResponse,
)

if TYPE_CHECKING:
    pass


def get_sessions_store() -> dict[str, Any]:
    """Get or create chat sessions store."""
    from .. import _get_global_sessions_store

    return _get_global_sessions_store()


async def list_sessions_handler(
    agent_name: str | None = None, limit: int | None = None
) -> ChatSessionsResponse:
    """Handle GET /sessions - list all chat sessions."""
    store = get_sessions_store()
    all_sessions = [ChatSession.model_validate(s) for s in store.values()]

    if agent_name:
        filtered = [s for s in all_sessions if s.agent_name == agent_name]
    else:
        filtered = all_sessions

    total = len(filtered)

    if limit:
        filtered = filtered[:limit]

    return ChatSessionsResponse(
        sessions=filtered,
        total=total,
    )


async def get_session_handler(session_id: str, route_agent_name: str | None = None) -> ChatSession:
    """Handle GET /sessions/{session_id} - get single session."""
    store = get_sessions_store()
    not_found_msg = "Session not found" if route_agent_name is None else "session_not_found"

    if session_id not in store:
        raise HTTPException(status_code=404, detail=not_found_msg)

    session = ChatSession.model_validate(store[session_id])

    if route_agent_name and session.agent_name != route_agent_name:
        raise HTTPException(status_code=404, detail=not_found_msg)

    return session


async def create_session_handler(
    request: CreateChatSessionRequest, route_agent_name: str | None = None
) -> ChatSession:
    """Handle POST /sessions - create new session."""
    import uuid

    store = get_sessions_store()
    session_id = uuid.uuid4().hex[:12]

    effective_agent_name = route_agent_name if route_agent_name else request.agent_name

    session = ChatSession(
        id=session_id,
        name=request.name or f"Session {session_id[:8]}",
        agent_name=effective_agent_name,
        messages=[],
        task_runs=[],
        tokens_by_agent={},
        created_at=datetime.now(UTC).isoformat(),
        updated_at=None,
    )

    store[session_id] = session.model_dump()
    return session


async def update_session_handler(
    session_id: str, request: UpdateChatSessionRequest, route_agent_name: str | None = None
) -> ChatSession:
    """Handle PUT /sessions/{session_id} - update session."""
    store = get_sessions_store()
    not_found_msg = "Session not found" if route_agent_name is None else "session_not_found"

    if session_id not in store:
        raise HTTPException(status_code=404, detail=not_found_msg)

    session = ChatSession.model_validate(store[session_id])

    if route_agent_name and session.agent_name != route_agent_name:
        raise HTTPException(status_code=404, detail=not_found_msg)

    existing = store[session_id]

    if request.name is not None:
        existing["name"] = request.name
    if request.messages is not None:
        existing["messages"] = [
            m.model_dump() if hasattr(m, "model_dump") else m for m in request.messages
        ]
    if request.task_runs is not None:
        existing["task_runs"] = [
            t.model_dump() if hasattr(t, "model_dump") else t for t in request.task_runs
        ]
    if request.tokens_by_agent is not None:
        existing["tokens_by_agent"] = request.tokens_by_agent

    existing["updated_at"] = datetime.now(UTC).isoformat()
    store[session_id] = existing

    return ChatSession.model_validate(existing)


async def delete_session_handler(
    session_id: str, route_agent_name: str | None = None
) -> dict[str, str]:
    """Handle DELETE /sessions/{session_id} - delete session."""
    store = get_sessions_store()
    not_found_msg = "Session not found" if route_agent_name is None else "session_not_found"

    if session_id not in store:
        raise HTTPException(status_code=404, detail=not_found_msg)

    existing = store[session_id]
    if route_agent_name and existing.get("agent_name") != route_agent_name:
        raise HTTPException(status_code=404, detail=not_found_msg)

    del store[session_id]
    return {"status": "deleted"}


async def cancel_task_run_handler(
    session_id: str,
    task_run_id: str,
) -> TaskRunActionResponse:
    """Handle POST /sessions/{session_id}/task-runs/{task_run_id}/cancel - cancel task run."""
    store = get_sessions_store()
    if session_id not in store:
        raise HTTPException(status_code=404, detail="session_not_found")

    session = store[session_id]
    task_run = None

    for tr in session.get("task_runs", []):
        if tr.get("id") == task_run_id:
            task_run = tr
            break

    if not task_run:
        raise HTTPException(status_code=404, detail="Task run not found")

    current_status = task_run.get("status", "running")
    if current_status in ("completed", "failed", "paused"):
        return TaskRunActionResponse(
            status="already_terminal",
            session_id=session_id,
            task_run_id=task_run_id,
            task_run_status=current_status,  # type: ignore
        )

    task_run["status"] = "paused"
    store[session_id] = session

    return TaskRunActionResponse(
        status="cancel_requested",
        session_id=session_id,
        task_run_id=task_run_id,
        task_run_status="paused",  # type: ignore
    )


__all__ = [
    "list_sessions_handler",
    "get_session_handler",
    "create_session_handler",
    "update_session_handler",
    "delete_session_handler",
    "cancel_task_run_handler",
]
