"""Mentor LLM client communicating with llama.cpp server (OpenAI API compatible)."""
import httpx
from typing import Dict, Any, Optional
from src.core.config import config
from src.core.prompts import get_mentor_prompt, get_socratic_prompt


def get_chat_completions_url(base_url: str) -> str:
    url = base_url.strip().rstrip("/")
    if url.endswith("/chat/completions"):
        return url
    if url.endswith("/v1"):
        return f"{url}/chat/completions"
    return f"{url}/v1/chat/completions"


class MentorClient:
    """LLM client for software engineering tutoring via OpenAI-compatible endpoints."""

    def __init__(self) -> None:
        self.config = config

    async def get_guidance_async(
        self, challenge: object, user_code: str, user_question: str = ""
    ) -> Dict[str, Any]:
        """Fetch mentor guidance asynchronously from the configured LLM endpoint."""
        prompt = get_mentor_prompt(challenge, user_code, user_question=user_question)
        endpoint = get_chat_completions_url(self.config.llm_base_url)

        user_content = (
            f"Question for Mentor: {user_question}\n\nPlease evaluate my code or answer my question for this challenge."
            if user_question.strip()
            else "Please review my code structure and provide guidance for my current step."
        )

        payload = {
            "model": self.config.llm_model,
            "messages": [
                {"role": "system", "content": prompt},
                {"role": "user", "content": user_content},
            ],
            "temperature": self.config.llm_temperature,
            "max_tokens": self.config.llm_max_tokens,
        }

        headers = {"Content-Type": "application/json"}
        if self.config.llm_api_key and self.config.llm_api_key != "not-needed":
            headers["Authorization"] = f"Bearer {self.config.llm_api_key}"

        try:
            async with httpx.AsyncClient(timeout=self.config.llm_timeout, follow_redirects=True) as client:
                response = await client.post(endpoint, json=payload, headers=headers)
                response.raise_for_status()
                data = response.json()

                content = (
                    data.get("choices", [{}])[0]
                    .get("message", {})
                    .get("content", "")
                    .strip()
                )

                if content:
                    return {
                        "status": "success",
                        "mentor_response": content,
                        "offline": False,
                    }
                else:
                    return {
                        "status": "error",
                        "mentor_response": "Received empty response from LLM server.",
                        "offline": False,
                    }
        except (httpx.ConnectError, httpx.TimeoutException, httpx.TransportError):
            return {
                "status": "offline",
                "mentor_response": (
                    f"⚠️ LLM Server offline or unreachable at {self.config.llm_base_url}.\n"
                    "Start your llama.cpp server with:\n"
                    "  ./llama-server -m <your-model.gguf> --port 8080\n\n"
                    "💡 Offline Hint:\n"
                    "How is your code structuring the initial state before entering your main logic loop?"
                ),
                "offline": True,
            }

        except Exception as e:
            return {
                "status": "error",
                "mentor_response": f"⚠️ Error consulting LLM mentor: {e}",
                "offline": False,
            }

    def get_guidance(
        self, challenge: object, user_code: str, user_question: str = ""
    ) -> Dict[str, Any]:
        """Synchronous wrapper for fetching mentor guidance."""
        import asyncio

        try:
            loop = asyncio.get_event_loop()
            if loop.is_running():
                import nest_asyncio
                nest_asyncio.apply()
                return loop.run_until_complete(
                    self.get_guidance_async(challenge, user_code, user_question=user_question)
                )
            else:
                return asyncio.run(
                    self.get_guidance_async(challenge, user_code, user_question=user_question)
                )
        except Exception:
            return asyncio.run(
                self.get_guidance_async(challenge, user_code, user_question=user_question)
            )


SocraticMentor = MentorClient
mentor = MentorClient()
