"""Oghma RAG Proxy - Main FastAPI Application."""

from __future__ import annotations

import os
import time
from contextlib import asynccontextmanager
from typing import Any

import httpx
import structlog
import yaml
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import StreamingResponse

from .extractor import NPCExtractor
from .injector import LoreInjector
from .models import ChatCompletionRequest
from .retriever import OghmaRetriever

# Configure structured logging
structlog.configure(
    processors=[
        structlog.stdlib.filter_by_level,
        structlog.stdlib.add_logger_name,
        structlog.stdlib.add_log_level,
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.JSONRenderer(),
    ],
    wrapper_class=structlog.stdlib.BoundLogger,
    context_class=dict,
    logger_factory=structlog.stdlib.LoggerFactory(),
)

logger = structlog.get_logger()


def load_config(config_path: str = "config.yaml") -> dict:
    """Load configuration from YAML file."""
    # Try local config first, then default
    for path in ["config.local.yaml", config_path]:
        if os.path.exists(path):
            with open(path) as f:
                config = yaml.safe_load(f)
                logger.info("Loaded config", path=path)
                return config
    return {}


# Global instances
config = load_config()
extractor = NPCExtractor()
retriever: OghmaRetriever | None = None
injector: LoreInjector | None = None
http_client: httpx.AsyncClient | None = None


@asynccontextmanager
async def lifespan(app: FastAPI):
    """Application lifespan - setup and teardown."""
    global retriever, injector, http_client

    # Initialize components
    chroma_config = config.get("chromadb", {})
    retriever = OghmaRetriever(
        host=chroma_config.get("host", "iris-dev.eachpath.local"),
        port=chroma_config.get("port", 35000),
        collection_lore=chroma_config.get("collection_lore", "oghma_lore"),
        collection_basic=chroma_config.get("collection_basic", "oghma_basic"),
        max_results=config.get("retrieval", {}).get("max_results", 5),
        min_score=config.get("retrieval", {}).get("min_score", 0.55),
    )

    injection_config = config.get("injection", {})
    injector = LoreInjector(
        template=injection_config.get("template"),
        position=injection_config.get("position", "after_bio"),
    )

    upstream_config = config.get("upstream", {})
    http_client = httpx.AsyncClient(
        timeout=httpx.Timeout(
            connect=10.0,
            read=upstream_config.get("timeout", 120.0),
            write=30.0,
            pool=10.0,
        ),
        limits=httpx.Limits(max_connections=100, max_keepalive_connections=20),
    )

    logger.info(
        "Oghma RAG Proxy started",
        upstream_url=upstream_config.get("url", ""),
        chromadb_host=chroma_config.get("host"),
    )

    yield

    # Cleanup
    if http_client:
        await http_client.aclose()
    logger.info("Oghma RAG Proxy stopped")


app = FastAPI(
    title="Oghma RAG Proxy",
    description="RAG Proxy for SkyrimNet - Injects Tamrielic lore into NPC conversations",
    version="0.1.0",
    lifespan=lifespan,
)


@app.get("/health")
async def health_check():
    """Health check endpoint."""
    chromadb_healthy = retriever.health_check() if retriever else False

    return {
        "status": "healthy" if chromadb_healthy else "degraded",
        "components": {
            "proxy": "healthy",
            "chromadb": "healthy" if chromadb_healthy else "unhealthy",
        },
    }


# Debug: track recent RAG operations
_recent_rag_ops = []

@app.get("/stats")
async def get_stats():
    """Get proxy statistics."""
    return {
        "version": "0.1.0",
        "injection_enabled": config.get("injection", {}).get("enabled", True),
        "upstream_url": config.get("upstream", {}).get("url", ""),
    }

@app.get("/debug/rag")
async def debug_rag():
    """Debug endpoint to see recent RAG operations."""
    return {"recent_operations": _recent_rag_ops[-20:]}


@app.post("/v1/chat/completions")
async def chat_completions(request: Request):
    """
    Proxy chat completions with RAG enrichment.

    This endpoint intercepts OpenRouter-compatible requests,
    enriches them with relevant Tamrielic lore, and forwards
    to the upstream LLM.
    """
    start_time = time.perf_counter()

    # Parse request body
    body = await request.json()
    messages = body.get("messages", [])
    stream = body.get("stream", False)

    # Extract NPC profile from messages
    npc_profile = extractor.extract(messages)

    # Get conversation context for RAG query
    context = extractor.extract_conversation_context(messages)

    # Retrieve relevant lore
    lore_entries = []
    query_time_ms = 0.0
    if (
        retriever
        and injector
        and config.get("injection", {}).get("enabled", True)
        and context
    ):
        lore_entries, query_time_ms = retriever.retrieve(context, npc_profile)

        # Inject lore into messages
        if lore_entries:
            messages, injection_result = injector.inject(
                messages,
                npc_profile,
                lore_entries,
                query_time_ms,
            )
            body["messages"] = messages

        # Track for debug endpoint
        _recent_rag_ops.append({
            "npc": npc_profile.name,
            "race": npc_profile.race,
            "query": context[:100] if context else "",
            "lore_found": len(lore_entries),
            "topics": [e.topic for e in lore_entries[:3]],
            "time_ms": round(query_time_ms, 2),
        })
        if len(_recent_rag_ops) > 50:
            _recent_rag_ops.pop(0)

    # Forward to upstream
    upstream_config = config.get("upstream", {})
    upstream_url = upstream_config.get("url", "https://openrouter.ai/api/v1")
    api_key = upstream_config.get("api_key", os.environ.get("OPENROUTER_API_KEY", ""))

    headers = {
        "Content-Type": "application/json",
    }
    if api_key:
        headers["Authorization"] = f"Bearer {api_key}"

    # Copy relevant headers from original request
    for header in ["HTTP-Referer", "X-Title"]:
        if value := request.headers.get(header):
            headers[header] = value

    try:
        if stream:
            # Streaming response
            return StreamingResponse(
                stream_upstream(f"{upstream_url}/chat/completions", headers, body),
                media_type="text/event-stream",
            )
        else:
            # Regular response
            response = await http_client.post(
                f"{upstream_url}/chat/completions",
                json=body,
                headers=headers,
            )
            response.raise_for_status()

            total_time = (time.perf_counter() - start_time) * 1000
            logger.info(
                "Request completed",
                npc_name=npc_profile.name,
                lore_entries=len(lore_entries),
                rag_time_ms=round(query_time_ms, 2),
                total_time_ms=round(total_time, 2),
            )

            return response.json()

    except httpx.HTTPError as e:
        logger.error("Upstream request failed", error=str(e))
        raise HTTPException(status_code=502, detail=f"Upstream error: {e}")


async def stream_upstream(url: str, headers: dict, body: dict):
    """Stream response from upstream with error handling."""
    try:
        async with http_client.stream("POST", url, json=body, headers=headers) as response:
            async for chunk in response.aiter_bytes():
                yield chunk
    except httpx.ReadError as e:
        logger.error("Upstream stream dropped", error=str(e))
    except httpx.HTTPError as e:
        logger.error("Upstream stream error", error=str(e))


@app.post("/v1/completions")
async def completions(request: Request):
    """Legacy completions endpoint - passthrough."""
    body = await request.json()

    upstream_config = config.get("upstream", {})
    upstream_url = upstream_config.get("url", "https://openrouter.ai/api/v1")
    api_key = upstream_config.get("api_key", os.environ.get("OPENROUTER_API_KEY", ""))

    headers = {
        "Content-Type": "application/json",
    }
    if api_key:
        headers["Authorization"] = f"Bearer {api_key}"

    response = await http_client.post(
        f"{upstream_url}/completions",
        json=body,
        headers=headers,
    )
    return response.json()


def main():
    """Run the proxy server."""
    import uvicorn

    proxy_config = config.get("proxy", {})
    uvicorn.run(
        "oghma_proxy.main:app",
        host=proxy_config.get("host", "0.0.0.0"),
        port=proxy_config.get("port", 8100),
        workers=proxy_config.get("workers", 1),
        log_level="info",
    )


if __name__ == "__main__":
    main()
