"""
Web API Routes - REST and WebSocket endpoints

Provides API endpoints for:
- Chat completion (streaming and non-streaming)
- Session management
- Tool execution
- Provider and model listing
"""

import json
import time
from pathlib import Path
from typing import Any, Optional

from groknroll import __version__
from groknroll.web.session_manager import (
    get_session_manager,
)
from groknroll.web.types import (
    AgentType,
    ChatRequest,
    ChatResponse,
    HealthResponse,
    MessageRole,
    ModelInfo,
    ProviderInfo,
    SessionCreateRequest,
    SessionDetail,
    SessionExportRequest,
    SessionInfo,
    StatsResponse,
    ToolCallRequest,
    ToolCallResult,
    ToolInfo,
)

# Store start time for uptime calculation
_start_time = time.time()


def create_routes(app: Any, project_path: Optional[Path] = None) -> None:
    """
    Create all API routes on the FastAPI app

    Args:
        app: FastAPI application instance
        project_path: Project path for session manager
    """
    from fastapi import HTTPException, WebSocket, WebSocketDisconnect
    from fastapi.responses import StreamingResponse

    session_manager = get_session_manager(project_path)

    # Health endpoints
    @app.get("/health", response_model=HealthResponse, tags=["Health"])
    async def health_check():
        """Check API health"""
        return HealthResponse(
            status="ok",
            version=__version__,
            uptime_seconds=time.time() - _start_time,
        )

    @app.get("/api/v1/health", response_model=HealthResponse, tags=["Health"])
    async def health_check_v1():
        """Check API health (v1)"""
        return await health_check()

    # Session endpoints
    @app.post("/api/v1/sessions", response_model=SessionInfo, tags=["Sessions"])
    async def create_session(request: SessionCreateRequest):
        """Create a new chat session"""
        session = await session_manager.create_session(
            name=request.name,
            agent=request.agent,
        )
        return session.to_info()

    @app.get("/api/v1/sessions", response_model=list[SessionInfo], tags=["Sessions"])
    async def list_sessions():
        """List all sessions"""
        return await session_manager.list_sessions()

    @app.get("/api/v1/sessions/{session_id}", response_model=SessionDetail, tags=["Sessions"])
    async def get_session(session_id: str):
        """Get session details"""
        session = await session_manager.get_session(session_id)
        if not session:
            raise HTTPException(status_code=404, detail="Session not found")
        return session.to_detail()

    @app.delete("/api/v1/sessions/{session_id}", tags=["Sessions"])
    async def delete_session(session_id: str):
        """Delete a session"""
        deleted = await session_manager.delete_session(session_id)
        if not deleted:
            raise HTTPException(status_code=404, detail="Session not found")
        return {"status": "deleted"}

    @app.post("/api/v1/sessions/{session_id}/export", tags=["Sessions"])
    async def export_session(session_id: str, request: SessionExportRequest):
        """Export session to specified format"""
        session = await session_manager.get_session(session_id)
        if not session:
            raise HTTPException(status_code=404, detail="Session not found")

        if request.format == "markdown":
            content = _export_to_markdown(session)
            return {"content": content, "format": "markdown"}
        elif request.format == "json":
            return {"content": session.to_detail().model_dump(), "format": "json"}
        else:
            raise HTTPException(status_code=400, detail=f"Unknown format: {request.format}")

    # Chat endpoints
    @app.post("/api/v1/chat", response_model=ChatResponse, tags=["Chat"])
    async def chat(request: ChatRequest):
        """Send a chat message (non-streaming)"""
        session = await session_manager.get_or_create_session(
            session_id=request.session_id,
            agent=request.agent,
        )

        message = await session_manager.chat(
            session=session,
            message=request.message,
            files=request.files,
        )

        return ChatResponse(
            session_id=session.id,
            message=message,
            done=True,
        )

    @app.post("/api/v1/chat/stream", tags=["Chat"])
    async def chat_stream(request: ChatRequest):
        """Send a chat message with streaming response"""
        session = await session_manager.get_or_create_session(
            session_id=request.session_id,
            agent=request.agent,
        )

        async def generate():
            async for chunk in session_manager.chat_stream(
                session=session,
                message=request.message,
                files=request.files,
            ):
                yield f"data: {chunk.model_dump_json()}\n\n"

        return StreamingResponse(
            generate(),
            media_type="text/event-stream",
        )

    # WebSocket for real-time chat
    @app.websocket("/ws/chat")
    async def websocket_chat(websocket: WebSocket):
        """WebSocket endpoint for real-time chat"""
        await websocket.accept()

        session = None

        try:
            while True:
                data = await websocket.receive_text()
                request_data = json.loads(data)

                # Handle different message types
                msg_type = request_data.get("type", "message")

                if msg_type == "create_session":
                    session = await session_manager.create_session(
                        name=request_data.get("name"),
                        agent=AgentType(request_data.get("agent", "build")),
                    )
                    await websocket.send_json(
                        {
                            "type": "session_created",
                            "session_id": session.id,
                        }
                    )

                elif msg_type == "message":
                    if not session:
                        session = await session_manager.create_session()
                        await websocket.send_json(
                            {
                                "type": "session_created",
                                "session_id": session.id,
                            }
                        )

                    message = request_data.get("message", "")
                    files = request_data.get("files", [])

                    # Stream response
                    async for chunk in session_manager.chat_stream(
                        session=session,
                        message=message,
                        files=files,
                    ):
                        await websocket.send_json(chunk.model_dump())

                elif msg_type == "ping":
                    await websocket.send_json({"type": "pong"})

        except WebSocketDisconnect:
            pass
        except Exception as e:
            await websocket.send_json(
                {
                    "type": "error",
                    "content": str(e),
                }
            )

    # Tool endpoints
    @app.get("/api/v1/tools", response_model=list[ToolInfo], tags=["Tools"])
    async def list_tools():
        """List available tools"""
        from groknroll.tools import ToolRegistry

        registry = ToolRegistry()
        registry.auto_discover()

        tools = []
        for tool in registry.list_tools():
            tools.append(
                ToolInfo(
                    name=tool.name,
                    description=tool.description,
                    parameters={},  # Would need schema extraction
                )
            )

        return tools

    @app.post("/api/v1/tools/call", response_model=ToolCallResult, tags=["Tools"])
    async def call_tool(request: ToolCallRequest):
        """Call a tool directly"""
        from groknroll.tools import ToolRegistry

        registry = ToolRegistry()
        registry.auto_discover()

        tool = registry.get(request.tool)
        if not tool:
            raise HTTPException(status_code=404, detail=f"Tool not found: {request.tool}")

        start_time = time.time()
        try:
            result = await tool.execute(**request.arguments)
            return ToolCallResult(
                tool=request.tool,
                success=True,
                result=result,
                duration_ms=int((time.time() - start_time) * 1000),
            )
        except Exception as e:
            return ToolCallResult(
                tool=request.tool,
                success=False,
                result=None,
                error=str(e),
                duration_ms=int((time.time() - start_time) * 1000),
            )

    # Provider endpoints
    @app.get("/api/v1/providers", response_model=list[ProviderInfo], tags=["Providers"])
    async def list_providers():
        """List configured LLM providers"""
        try:
            import os

            from groknroll.connect.providers import PROVIDERS

            providers = []
            for name, provider in PROVIDERS.items():
                # Check if provider is configured (has API key)
                enabled = all(os.environ.get(var) for var in provider.env_vars)
                providers.append(
                    ProviderInfo(
                        name=name,
                        display_name=provider.display_name,
                        enabled=enabled,
                        models=provider.models,
                    )
                )

            return providers
        except ImportError:
            return []

    @app.get("/api/v1/models", response_model=list[ModelInfo], tags=["Models"])
    async def list_models():
        """List available models"""
        try:
            import os

            from groknroll.connect.providers import PROVIDERS

            models = []
            for name, provider in PROVIDERS.items():
                # Check if provider is configured
                enabled = all(os.environ.get(var) for var in provider.env_vars)
                if enabled:
                    for model in provider.models:
                        models.append(
                            ModelInfo(
                                id=model,
                                name=model,
                                provider=name,
                            )
                        )

            return models
        except ImportError:
            return []

    # Stats endpoint
    @app.get("/api/v1/stats", response_model=StatsResponse, tags=["Stats"])
    async def get_stats():
        """Get usage statistics"""
        sessions = await session_manager.list_sessions()
        total_messages = sum(s.message_count for s in sessions)

        return StatsResponse(
            total_sessions=len(sessions),
            total_messages=total_messages,
            total_cost=0.0,  # Would need cost tracking
            total_tokens=0,  # Would need token tracking
            average_response_time_ms=0.0,  # Would need timing tracking
        )


def _export_to_markdown(session: Any) -> str:
    """Export session to Markdown format"""
    lines = [
        f"# Session: {session.name or session.id}",
        "",
        f"**Created:** {session.created_at.isoformat()}",
        f"**Agent:** {session.agent.value}",
        "",
        "---",
        "",
    ]

    for msg in session.messages:
        role = "**User:**" if msg.role == MessageRole.USER else "**Assistant:**"
        lines.append(role)
        lines.append("")
        lines.append(msg.content)
        lines.append("")
        lines.append("---")
        lines.append("")

    return "\n".join(lines)
