"""
SkillBroker API client for interacting with the skill registry.
"""

import os
from typing import List, Optional, Dict, Any
import requests
from .models import Skill, SkillResponse, SearchResult


class SkillBrokerError(Exception):
    """Base exception for SkillBroker errors."""
    pass


class SkillNotFoundError(SkillBrokerError):
    """Raised when a skill is not found."""
    pass


class InvocationError(SkillBrokerError):
    """Raised when skill invocation fails."""
    pass


class SkillBrokerClient:
    """
    Client for interacting with the SkillBroker API.

    Args:
        api_url: Base URL for the SkillBroker API. Defaults to production.
        api_key: Optional API key for authenticated requests.
        timeout: Request timeout in seconds.

    Example:
        ```python
        from skillbroker_langchain import SkillBrokerClient

        client = SkillBrokerClient()

        # Search for skills
        results = client.search("tax advice")

        # Invoke a skill
        response = client.invoke("skill-id", "How do I deduct home office expenses?")
        print(response.response)
        ```
    """

    DEFAULT_API_URL = "https://api.skillbroker.io"

    def __init__(
        self,
        api_url: Optional[str] = None,
        api_key: Optional[str] = None,
        timeout: int = 30,
    ):
        self.api_url = api_url or os.getenv("SKILLBROKER_API_URL", self.DEFAULT_API_URL)
        self.api_key = api_key or os.getenv("SKILLBROKER_API_KEY")
        self.timeout = timeout
        self._session = requests.Session()

        if self.api_key:
            self._session.headers["Authorization"] = f"Bearer {self.api_key}"

        self._session.headers["Content-Type"] = "application/json"
        self._session.headers["User-Agent"] = "skillbroker-langchain/0.1.0"

    def _request(
        self,
        method: str,
        endpoint: str,
        **kwargs
    ) -> Dict[str, Any]:
        """Make an HTTP request to the API."""
        url = f"{self.api_url}{endpoint}"
        kwargs.setdefault("timeout", self.timeout)

        try:
            response = self._session.request(method, url, **kwargs)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.HTTPError as e:
            if e.response.status_code == 404:
                raise SkillNotFoundError(f"Resource not found: {endpoint}")
            raise SkillBrokerError(f"API error: {e}")
        except requests.exceptions.RequestException as e:
            raise SkillBrokerError(f"Request failed: {e}")

    def get_registry_info(self) -> Dict[str, Any]:
        """Get information about the skill registry."""
        return self._request("GET", "/api/Registry")

    def search(
        self,
        query: Optional[str] = None,
        category: Optional[str] = None,
        limit: int = 20,
    ) -> SearchResult:
        """
        Search for skills in the registry.

        Args:
            query: Search query string.
            category: Filter by category.
            limit: Maximum number of results.

        Returns:
            SearchResult containing matching skills.
        """
        params = {}
        if query:
            params["q"] = query
        if category:
            params["category"] = category
        if limit:
            params["limit"] = limit

        data = self._request("GET", "/api/Registry/search", params=params)

        skills = [Skill(**s) for s in data.get("skills", [])]
        return SearchResult(
            skills=skills,
            total_count=len(skills),
            query=query,
            category=category,
        )

    def get_skill(self, skill_id: str) -> Skill:
        """
        Get a skill by ID.

        Args:
            skill_id: The unique skill identifier.

        Returns:
            The Skill object.

        Raises:
            SkillNotFoundError: If skill doesn't exist.
        """
        data = self._request("GET", f"/api/Registry/skills/{skill_id}/manifest")
        return Skill(**data)

    def invoke(
        self,
        skill_id: str,
        query: str,
        context: Optional[Dict[str, Any]] = None,
    ) -> SkillResponse:
        """
        Invoke a skill with a query.

        Args:
            skill_id: The skill to invoke.
            query: The question or request.
            context: Optional context for the query.

        Returns:
            SkillResponse with the answer.

        Raises:
            InvocationError: If invocation fails.
        """
        payload = {"query": query}
        if context:
            payload["context"] = context

        try:
            data = self._request(
                "POST",
                f"/api/Registry/skills/{skill_id}/invoke",
                json=payload,
            )

            return SkillResponse(
                success=True,
                response=data.get("response", ""),
                skill_id=skill_id,
                skill_name=data.get("skillName", ""),
                tokens_used=data.get("tokensUsed"),
                cost=data.get("cost"),
            )
        except SkillBrokerError as e:
            raise InvocationError(f"Failed to invoke skill {skill_id}: {e}")

    def get_categories(self) -> List[Dict[str, Any]]:
        """Get all available skill categories."""
        return self._request("GET", "/api/Registry/categories")

    def get_top_skills(
        self,
        limit: int = 10,
        category: Optional[str] = None,
    ) -> List[Skill]:
        """
        Get top-rated skills from the leaderboard.

        Args:
            limit: Maximum number of skills.
            category: Filter by category.

        Returns:
            List of top-rated skills.
        """
        params = {"limit": limit}
        if category:
            params["category"] = category

        data = self._request("GET", "/api/quality/leaderboard", params=params)
        return [Skill(**s) for s in data.get("skills", [])]

    def get_recommendations(
        self,
        task_description: str,
        limit: int = 5,
    ) -> List[Skill]:
        """
        Get skill recommendations for a task.

        Args:
            task_description: Description of what you're trying to do.
            limit: Maximum number of recommendations.

        Returns:
            List of recommended skills.
        """
        payload = {
            "taskDescription": task_description,
            "limit": limit,
        }

        data = self._request("POST", "/api/quality/recommend", json=payload)
        return [Skill(**s) for s in data.get("recommendations", [])]
