"""Define API routes for agent."""

from __future__ import annotations

import json
from typing import AsyncGenerator, List, Optional

from fastapi import APIRouter, HTTPException
from fastapi.responses import StreamingResponse

from dataclasses import asdict

from app.api.models import (
    AskRequest,
    AskResponse,
    ChatRequest,
    ChatResponse,
    FeedbackRequest,
    SessionInfo,
)
from app.config.settings import settings
from app.shared.async_utils import iter_in_thread
from app.shared.bootstrap import (
    get_agent_conversation_service,
    get_agent_session_service,
    get_agentic_conversation_service,
)
# Keep route handlers close to their transport-layer wiring for easier auditing.


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


@router.post("/ask", response_model=AskResponse)
async def ask_question(request: AskRequest):
    """Handle ask question."""
    try:
        _, result = get_agent_conversation_service().ask(
            query=request.query,
            filters=request.filters,
            provider=request.provider or settings.llm_provider,
            model=request.model or settings.llm_model,
            top_k=request.top_k or settings.rag_top_k,
            prompt_template=request.prompt_template,
        )
        return AskResponse(
            answer=result.answer,
            sources=[asdict(source) for source in result.sources],
            model=result.model,
            latency_ms=result.latency_ms,
            retrieved_count=result.retrieved_count,
            context_tokens=result.context_tokens,
            truncated=result.truncated,
            error=result.error,
        )
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc))


@router.post("/chat", response_model=ChatResponse)
async def chat_with_session(request: ChatRequest):
    """Handle chat with session."""
    try:
        session_id, result = get_agent_conversation_service().chat(
            query=request.query,
            session_id=request.session_id,
            filters=request.filters,
            provider=request.provider or settings.llm_provider,
            model=request.model or settings.llm_model,
            top_k=request.top_k or settings.rag_top_k,
        )
        session = get_agent_session_service().get_session(session_id)
        return ChatResponse(
            session_id=session_id,
            answer=result.answer,
            sources=[asdict(source) for source in result.sources],
            model=result.model,
            latency_ms=result.latency_ms,
            message_count=len(session.messages) if session else 0,
        )
    except ValueError as exc:
        raise HTTPException(status_code=404, detail=str(exc))
    except Exception as exc:
        raise HTTPException(status_code=500, detail=str(exc))


@router.get("/chat/stream")
async def chat_stream_get(
    query: str,
    session_id: Optional[str] = None,
    filters: Optional[str] = None,
    provider: Optional[str] = None,
    model: Optional[str] = None,
):
    """Handle chat stream get."""
    async def generate_sse() -> AsyncGenerator[str, None]:
        """Handle generate sse."""
        try:
            session_id_, event_stream = get_agent_conversation_service().stream_chat(
                query=query,
                session_id=session_id,
                filters=filters,
                provider=provider or settings.llm_provider,
                model=model or settings.llm_model,
                top_k=settings.rag_top_k,
            )
            yield f"event: session\ndata: {json.dumps({'session_id': session_id_})}\n\n"
            async for event_data in iter_in_thread(event_stream):
                event_type = event_data.get("event", "content")
                data = event_data.get("data", "")
                if isinstance(data, (dict, list)):
                    yield f"event: {event_type}\ndata: {json.dumps(data, ensure_ascii=False)}\n\n"
                else:
                    yield f"event: {event_type}\ndata: {data}\n\n"
        except Exception as exc:
            yield f"event: error\ndata: {str(exc)}\n\n"

    return StreamingResponse(
        generate_sse(),
        media_type="text/event-stream",
        headers={"Cache-Control": "no-cache", "Connection": "keep-alive", "X-Accel-Buffering": "no"},
    )


@router.post("/chat/stream")
async def chat_stream(request: ChatRequest):
    """Handle chat stream."""
    return await chat_stream_get(
        query=request.query,
        session_id=request.session_id,
        filters=request.filters,
        provider=request.provider,
        model=request.model,
    )


@router.get("/session/{session_id}", response_model=SessionInfo)
async def get_session_info(session_id: str):
    """Return session info."""
    try:
        session = get_agent_session_service().get_session(session_id)
        return SessionInfo(
            session_id=session.session_id,
            message_count=len(session.messages),
            created_at=session.created_at,
            updated_at=session.updated_at,
        )
    except ValueError as exc:
        raise HTTPException(status_code=404, detail=str(exc))


@router.get("/session/{session_id}/history")
async def get_session_history(session_id: str, max_turns: int = 5):
    """Return session history."""
    try:
        history = get_agent_session_service().get_history(session_id=session_id, max_turns=max_turns)
        return {"session_id": session_id, "history": history}
    except ValueError as exc:
        raise HTTPException(status_code=404, detail=str(exc))


@router.delete("/session/{session_id}")
async def delete_session(session_id: str):
    """Delete session."""
    try:
        get_agent_session_service().delete_session(session_id)
        return {"message": "会话已删除", "session_id": session_id}
    except ValueError as exc:
        raise HTTPException(status_code=404, detail=str(exc))


@router.get("/sessions", response_model=List[SessionInfo])
async def list_sessions():
    """List sessions."""
    return [SessionInfo(**item) for item in get_agent_session_service().list_sessions()]


@router.post("/feedback")
async def submit_feedback(request: FeedbackRequest):
    """Submit feedback."""
    try:
        result = get_agent_session_service().submit_feedback(
            session_id=request.session_id,
            message_index=request.message_index,
        )
        return {"message": "反馈已提交", "session_id": result.session_id, "message_index": result.message_index}
    except ValueError as exc:
        raise HTTPException(status_code=404, detail=str(exc))


# ── P0-1: Agentic RAG endpoint ────────────────────────────────────────────────

@router.post("/agentic/stream")
async def agentic_stream(request: ChatRequest):
    """Stream an Agentic RAG response with live multi-step reasoning trace.

    Unlike the standard ``/chat/stream`` endpoint this route runs a full pipeline:
    intent analysis → query planning → iterative retrieval → grounding check →
    answer generation.

    Extra SSE event types beyond the standard ones:

    * ``thinking`` — reasoning sub-step progress; data is a JSON object with
      ``step`` (intent_analysis / query_planning / retrieving / grounding_check),
      ``status`` (running / done), and step-specific fields.

    The ``sources``, ``content``, and ``done`` events are identical to the standard
    chat-stream contract so the existing frontend parser can handle them without
    changes.
    """
    async def generate_sse() -> AsyncGenerator[str, None]:
        """Handle SSE generation for the agentic chat endpoint."""
        try:
            session_id_, event_stream = get_agentic_conversation_service().stream_agentic_chat(
                query=request.query,
                session_id=request.session_id,
                filters=request.filters,
                provider=request.provider or settings.llm_provider,
                model=request.model or settings.llm_model,
                top_k=request.top_k or settings.rag_top_k,
                context_text=request.context_text,
                context_filename=request.context_filename,
            )
            yield f"event: session\ndata: {json.dumps({'session_id': session_id_})}\n\n"
            async for event_data in iter_in_thread(event_stream):
                event_type = event_data.get("event", "content")
                data = event_data.get("data", "")
                if isinstance(data, (dict, list)):
                    yield f"event: {event_type}\ndata: {json.dumps(data, ensure_ascii=False)}\n\n"
                else:
                    yield f"event: {event_type}\ndata: {data}\n\n"
        except Exception as exc:
            yield f"event: error\ndata: {str(exc)}\n\n"

    return StreamingResponse(
        generate_sse(),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "X-Accel-Buffering": "no",
        },
    )
