"""Chat endpoint — natural language queries over the corpus via LLM."""

from __future__ import annotations

import asyncio
import json
import logging
from pathlib import Path
from typing import Any

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

from sltk.api.dependencies import safe_error_detail

router = APIRouter(prefix="/api/chat", tags=["chat"])
logger = logging.getLogger(__name__)

SETTINGS_FILE = Path.home() / ".sltk" / "settings.json"


# ------------------------------------------------------------------
# Request / Response models
# ------------------------------------------------------------------


class ChatRequest(BaseModel):
    message: str = Field(..., min_length=1)
    history: list[dict[str, Any]] = Field(default_factory=list)
    model: str | None = None


class ToolCallInfo(BaseModel):
    name: str
    arguments: dict[str, Any] = Field(default_factory=dict)
    result_preview: str = ""
    result_data: Any = None


class ChatResponse(BaseModel):
    reply: str = ""
    tool_calls: list[ToolCallInfo] = Field(default_factory=list)
    history: list[dict[str, Any]] = Field(default_factory=list)
    error: str | None = None


# ------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------


def _load_settings() -> dict[str, Any]:
    if SETTINGS_FILE.exists():
        return json.loads(SETTINGS_FILE.read_text())
    return {}


def _get_corpus_db():
    """Get the CorpusDB for the active workspace."""
    from sltk.api.routers.corpus import _get_corpus_db as get_db

    return get_db()


def _get_all_workspace_dbs() -> tuple[str | None, dict]:
    """Return (active_name, {name: CorpusDB}) for all workspaces."""
    from sltk.api.routers.workspace import _ensure_loaded, _manager

    _ensure_loaded()

    active_name = None
    if _manager.active:
        active_name = _manager.active.name

    all_dbs = {}
    for ws_name in _manager._data.workspaces:
        try:
            db = _manager.get_corpus_db_by_name(ws_name)
            all_dbs[ws_name] = db
        except (ValueError, Exception):
            continue

    return active_name, all_dbs


# ------------------------------------------------------------------
# Endpoint
# ------------------------------------------------------------------


@router.post("", response_model=ChatResponse)
async def chat_endpoint(req: ChatRequest) -> ChatResponse:
    """Send a natural-language question about the corpus."""
    settings = _load_settings()

    provider = settings.get("ai_provider", "openai")

    # Resolve API key and model based on provider
    if provider == "anthropic":
        api_key = settings.get("anthropic_api_key")
        default_model = settings.get("anthropic_model", "claude-sonnet-4-5-20250929")
        key_label = "Anthropic"
    else:
        api_key = settings.get("openai_api_key")
        default_model = settings.get("openai_model", "gpt-4o")
        key_label = "OpenAI"

    if not api_key:
        return ChatResponse(
            error=f"{key_label} API key not configured. Go to Settings > AI to add your key."
        )

    model = req.model or default_model

    # Build messages list
    messages = list(req.history)
    messages.append({"role": "user", "content": req.message})

    try:
        db = _get_corpus_db()
    except HTTPException:
        return ChatResponse(error="No active workspace. Please select a workspace first.")

    # Gather all workspace DBs for cross-corpus awareness
    try:
        active_name, all_dbs = _get_all_workspace_dbs()
    except Exception:
        active_name = None
        all_dbs = {}

    try:
        from sltk.llm.agent import chat

        result = await asyncio.to_thread(
            chat,
            db,
            messages,
            api_key,
            model,
            provider,
            all_dbs,
            active_name,
        )

        return ChatResponse(
            reply=result["reply"],
            tool_calls=[ToolCallInfo(**tc) for tc in result["tool_calls"]],
            history=result["messages"],
        )
    except Exception as e:
        err_type = type(e).__name__
        err_str = str(e)

        # OpenAI errors
        if "AuthenticationError" in err_type:
            return ChatResponse(error=f"Invalid {key_label} API key. Check Settings > AI.")
        if "RateLimitError" in err_type:
            if "insufficient_quota" in err_str:
                return ChatResponse(
                    error="OpenAI quota exceeded. Check your billing at platform.openai.com."
                )
            return ChatResponse(error=f"{key_label} rate limit reached. Please wait and try again.")
        if "APIError" in err_type or "APIConnectionError" in err_type:
            return ChatResponse(
                error=f"Could not connect to {key_label}. Check your internet connection."
            )

        logger.exception("Chat error")
        return ChatResponse(error=safe_error_detail("Chat failed", e))
