"""Admin router for system settings — LLM and image provider configuration."""
import asyncio
import os
import time
from typing import Optional, List

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession

from models.sql.user import UserModel
from services.database import get_async_session
from utils.auth_dependencies import require_client_admin

SETTINGS_ROUTER = APIRouter(tags=["Admin - Settings"])


class SystemSettings(BaseModel):
    llm_provider: Optional[str] = None
    llm_model: Optional[str] = None
    image_provider: Optional[str] = None
    anthropic_api_key_set: bool = False
    openai_api_key_set: bool = False
    google_api_key_set: bool = False


class SettingsUpdate(BaseModel):
    llm_provider: Optional[str] = None
    llm_model: Optional[str] = None
    image_provider: Optional[str] = None
    anthropic_api_key: Optional[str] = None
    openai_api_key: Optional[str] = None
    google_api_key: Optional[str] = None


LLM_PROVIDERS = ["anthropic", "openai", "google", "ollama", "custom"]
IMAGE_PROVIDERS = ["nanobanana_pro", "gemini_flash", "dall-e-3", "gpt-image-1.5", "pexels", "pixabay", "comfyui"]


@SETTINGS_ROUTER.get("/settings")
async def get_settings(
    admin: UserModel = Depends(require_client_admin),
    _session: AsyncSession = Depends(get_async_session),
):
    """Return current system settings (env-based config)."""
    if admin.role != "super_admin":
        raise HTTPException(status_code=403, detail="Super admin only")

    return {
        "llm_provider": os.getenv("LLM", "anthropic"),
        "llm_model": _get_current_model(),
        "image_provider": os.getenv("IMAGE_PROVIDER", "google"),
        "anthropic_api_key_set": bool(os.getenv("ANTHROPIC_API_KEY")),
        "openai_api_key_set": bool(os.getenv("OPENAI_API_KEY")),
        "google_api_key_set": bool(os.getenv("GOOGLE_API_KEY")),
        "available_llm_providers": LLM_PROVIDERS,
        "available_image_providers": IMAGE_PROVIDERS,
    }


@SETTINGS_ROUTER.put("/settings")
async def update_settings(
    body: SettingsUpdate,
    admin: UserModel = Depends(require_client_admin),
    session: AsyncSession = Depends(get_async_session),
):
    """Update system settings. Changes apply immediately and persist to database."""
    if admin.role != "super_admin":
        raise HTTPException(status_code=403, detail="Super admin only")

    # Validate providers
    if body.llm_provider is not None and body.llm_provider not in LLM_PROVIDERS:
        raise HTTPException(status_code=400, detail=f"Invalid LLM provider: {body.llm_provider}")
    if body.image_provider is not None and body.image_provider not in IMAGE_PROVIDERS:
        raise HTTPException(status_code=400, detail=f"Invalid image provider: {body.image_provider}")

    from services.settings_service import save_settings
    data = body.model_dump(exclude_none=True)
    changed = await save_settings(session, data)

    return {"ok": True, "changed": changed}


@SETTINGS_ROUTER.get("/settings/models")
async def list_models(
    provider: str = Query(..., description="Provider name"),
    admin: UserModel = Depends(require_client_admin),
    _session: AsyncSession = Depends(get_async_session),
):
    """List available models for a given provider."""
    if admin.role != "super_admin":
        raise HTTPException(status_code=403, detail="Super admin only")

    try:
        models = await _fetch_models_for_provider(provider)
        return {"provider": provider, "models": models}
    except Exception as e:
        return {"provider": provider, "models": [], "error": str(e)}


class ConnectionTestRequest(BaseModel):
    provider: str
    api_key: Optional[str] = None


@SETTINGS_ROUTER.post("/settings/test-connection")
async def test_connection(
    body: ConnectionTestRequest,
    admin: UserModel = Depends(require_client_admin),
    _session: AsyncSession = Depends(get_async_session),
):
    """Test connectivity to an LLM/API provider."""
    if admin.role != "super_admin":
        raise HTTPException(status_code=403, detail="Super admin only")

    start = time.time()
    try:
        ok, error = await _test_provider_connection(body.provider, body.api_key)
        latency_ms = int((time.time() - start) * 1000)
        return {"ok": ok, "error": error, "latency_ms": latency_ms}
    except Exception as e:
        latency_ms = int((time.time() - start) * 1000)
        return {"ok": False, "error": str(e), "latency_ms": latency_ms}


def _get_current_model() -> str:
    provider = os.getenv("LLM", "anthropic")
    model_env_map = {
        "anthropic": "ANTHROPIC_MODEL",
        "openai": "OPENAI_MODEL",
        "google": "GOOGLE_MODEL",
        "ollama": "OLLAMA_MODEL",
        "custom": "CUSTOM_MODEL",
    }
    from constants.llm import DEFAULT_ANTHROPIC_MODEL, DEFAULT_OPENAI_MODEL, DEFAULT_GOOGLE_MODEL
    defaults = {
        "anthropic": DEFAULT_ANTHROPIC_MODEL,
        "openai": DEFAULT_OPENAI_MODEL,
        "google": DEFAULT_GOOGLE_MODEL,
    }
    env_key = model_env_map.get(provider, "ANTHROPIC_MODEL")
    return os.getenv(env_key, defaults.get(provider, ""))


# --- Known model lists (for providers without a list API) ---

ANTHROPIC_MODELS = [
    "claude-opus-4-6",
    "claude-sonnet-4-6",
    "claude-sonnet-4-5-20250929",
    "claude-haiku-4-5-20251001",
    "claude-sonnet-4-5-20250514",
    "claude-3-5-haiku-20241022",
]

GOOGLE_MODELS = [
    "models/gemini-2.5-flash",
    "models/gemini-2.5-pro",
    "models/gemini-2.0-flash",
    "models/gemini-2.0-flash-lite",
    "models/gemini-1.5-flash",
    "models/gemini-1.5-pro",
]


async def _fetch_models_for_provider(provider: str) -> List[str]:
    """Return a list of model IDs for the given provider."""
    if provider == "anthropic":
        return ANTHROPIC_MODELS

    if provider == "google":
        # Try listing via API, fallback to hardcoded
        key = os.getenv("GOOGLE_API_KEY")
        if key:
            try:
                def _list_google():
                    import google.genai as genai
                    client = genai.Client(api_key=key)
                    result = []
                    for m in client.models.list():
                        name = getattr(m, "name", str(m))
                        if "gemini" in name.lower():
                            result.append(name)
                    return sorted(result)
                return await asyncio.to_thread(_list_google)
            except Exception:
                pass
        return GOOGLE_MODELS

    if provider == "openai":
        key = os.getenv("OPENAI_API_KEY")
        if key:
            try:
                def _list_openai():
                    from openai import OpenAI
                    client = OpenAI(api_key=key)
                    models = client.models.list()
                    return sorted([m.id for m in models.data if "gpt" in m.id or "o1" in m.id or "o3" in m.id or "o4" in m.id])
                return await asyncio.to_thread(_list_openai)
            except Exception:
                pass
        return ["gpt-4.1", "gpt-4.1-mini", "gpt-4.1-nano", "gpt-4o", "gpt-4o-mini", "o3", "o4-mini"]

    if provider == "ollama":
        try:
            import httpx
            async with httpx.AsyncClient(timeout=5) as client:
                resp = await client.get(os.getenv("OLLAMA_URL", "http://localhost:11434") + "/api/tags")
                if resp.status_code == 200:
                    data = resp.json()
                    return [m["name"] for m in data.get("models", [])]
        except Exception:
            pass
        return []

    return []


async def _test_provider_connection(provider: str, api_key: Optional[str] = None) -> tuple:
    """Test provider connection. Returns (ok: bool, error: str | None)."""
    if provider == "anthropic":
        key = api_key or os.getenv("ANTHROPIC_API_KEY")
        if not key:
            return False, "No API key configured"
        try:
            def _test():
                import anthropic
                client = anthropic.Anthropic(api_key=key)
                client.messages.create(
                    model="claude-haiku-4-5-20251001",
                    max_tokens=5,
                    messages=[{"role": "user", "content": "hi"}],
                )
                return True
            await asyncio.to_thread(_test)
            return True, None
        except Exception as e:
            return False, str(e)

    if provider == "openai":
        key = api_key or os.getenv("OPENAI_API_KEY")
        if not key:
            return False, "No API key configured"
        try:
            def _test():
                from openai import OpenAI
                client = OpenAI(api_key=key)
                client.models.list()
                return True
            await asyncio.to_thread(_test)
            return True, None
        except Exception as e:
            return False, str(e)

    if provider == "google":
        key = api_key or os.getenv("GOOGLE_API_KEY")
        if not key:
            return False, "No API key configured"
        try:
            def _test():
                import google.genai as genai
                client = genai.Client(api_key=key)
                list(client.models.list())[:1]
                return True
            await asyncio.to_thread(_test)
            return True, None
        except Exception as e:
            return False, str(e)

    if provider == "ollama":
        try:
            import httpx
            async with httpx.AsyncClient(timeout=5) as client:
                resp = await client.get(os.getenv("OLLAMA_URL", "http://localhost:11434") + "/api/tags")
                if resp.status_code == 200:
                    return True, None
                return False, f"HTTP {resp.status_code}"
        except Exception as e:
            return False, str(e)

    return False, f"Unknown provider: {provider}"
