from __future__ import annotations

import os
from typing import Any

import httpx

from ._config import DEFAULT_BASE_URL, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT, VERSION
from ._exceptions import (
    STATUS_MAP,
    APIConnectionError,
    APITimeoutError,
    InternalServerError,
    RightNowError,
)


class BaseClient:
    """Shared configuration and helpers for sync/async clients."""

    base_url: str
    api_key: str
    timeout: float
    max_retries: int

    def __init__(
        self,
        *,
        api_key: str | None = None,
        base_url: str | None = None,
        timeout: float | None = None,
        max_retries: int | None = None,
    ) -> None:
        self.api_key = api_key or os.environ.get("RIGHTNOW_API_KEY", "")
        if not self.api_key:
            raise RightNowError(
                "API key is required. Pass api_key= or set RIGHTNOW_API_KEY env var."
            )
        self.base_url = (base_url or os.environ.get("RIGHTNOW_BASE_URL", DEFAULT_BASE_URL)).rstrip(
            "/"
        )
        self.timeout = timeout if timeout is not None else DEFAULT_TIMEOUT
        self.max_retries = max_retries if max_retries is not None else DEFAULT_MAX_RETRIES

    @property
    def _headers(self) -> dict[str, str]:
        return {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json",
            "User-Agent": f"rightnow-python/{VERSION}",
        }

    def _build_url(self, path: str) -> str:
        return f"{self.base_url}{path}"

    @staticmethod
    def _raise_for_status(response: httpx.Response) -> None:
        if response.is_success:
            return

        try:
            body = response.json()
        except Exception:
            body = {"error": {"message": response.text}}

        error_msg = body.get("error", {}).get("message", response.text) if isinstance(body, dict) else str(body)
        exc_cls = STATUS_MAP.get(response.status_code, InternalServerError)
        raise exc_cls(error_msg, status_code=response.status_code, body=body)

    @staticmethod
    def _wrap_connection_error(exc: Exception) -> RightNowError:
        if isinstance(exc, httpx.TimeoutException):
            return APITimeoutError(f"Request timed out: {exc}")
        return APIConnectionError(f"Connection error: {exc}")
