"""Custom exceptions and LLM-friendly error formatting for Influ2 MCP."""

from __future__ import annotations


class Influ2Error(Exception):
    """Base error for all Influ2 API errors."""

    def __init__(
        self,
        message: str,
        status_code: int | None = None,
        suggestion: str | None = None,
        retry_possible: bool = False,
    ):
        super().__init__(message)
        self.message = message
        self.status_code = status_code
        self.suggestion = suggestion
        self.retry_possible = retry_possible


class Influ2AuthError(Influ2Error):
    """Authentication or authorization failure (401/403)."""

    def __init__(self, message: str | None = None):
        super().__init__(
            message=message
            or (
                "Authentication failed. Verify your INFLU2_API_KEY is correct "
                "and has access to this client."
            ),
            status_code=401,
            suggestion="Check your INFLU2_API_KEY environment variable.",
            retry_possible=False,
        )


class Influ2NotFoundError(Influ2Error):
    """Resource not found (404)."""

    def __init__(self, resource: str = "Resource", resource_id: str = ""):
        msg = f"{resource} not found"
        if resource_id:
            msg += f" (id: {resource_id})"
        msg += "."
        super().__init__(
            message=msg,
            status_code=404,
            suggestion=f"Use the appropriate list tool to find valid {resource.lower()} IDs.",
            retry_possible=False,
        )


class Influ2ValidationError(Influ2Error):
    """Request validation failure (400/422)."""

    def __init__(self, detail: str = "Invalid request"):
        super().__init__(
            message=f"Validation error: {detail}",
            status_code=400,
            suggestion="Check the parameters and try again.",
            retry_possible=False,
        )


class Influ2RateLimitError(Influ2Error):
    """Rate limit exceeded (429)."""

    def __init__(self, retry_after: int | None = None):
        wait_msg = f" Wait {retry_after} seconds." if retry_after else ""
        super().__init__(
            message=f"Rate limited by Influ2 API.{wait_msg}",
            status_code=429,
            suggestion="Wait and try again.",
            retry_possible=True,
        )


class Influ2ServerError(Influ2Error):
    """Influ2 API server error (5xx)."""

    def __init__(self, status_code: int = 500):
        super().__init__(
            message="Influ2 API server error. This is temporary — try again in a minute.",
            status_code=status_code,
            suggestion="Retry after a short wait.",
            retry_possible=True,
        )


class Influ2JobTimeoutError(Influ2Error):
    """Async job polling timed out."""

    def __init__(self, job_id: str, last_status: str = "processing"):
        super().__init__(
            message=(
                f"Operation still in progress after timeout (job_id: {job_id}, "
                f"last status: {last_status}). Use influ2_check_job to monitor."
            ),
            suggestion=f"Call influ2_check_job with job_id='{job_id}' to check progress.",
            retry_possible=False,
        )
        self.job_id = job_id
        self.last_status = last_status


def format_error_for_llm(error: Exception) -> dict:
    """Convert an exception into a structured dict that LLMs can reason about."""
    if isinstance(error, Influ2Error):
        result = {
            "error": True,
            "message": error.message,
            "retry_possible": error.retry_possible,
        }
        if error.status_code:
            result["status_code"] = error.status_code
        if error.suggestion:
            result["suggestion"] = error.suggestion
        if isinstance(error, Influ2JobTimeoutError):
            result["job_id"] = error.job_id
            result["last_status"] = error.last_status
        return result

    return {
        "error": True,
        "message": f"Unexpected error: {str(error)}",
        "retry_possible": False,
        "suggestion": "Try again or check the Influ2 API status.",
    }
