"""GrowFlow Billing Client - Main client class."""

from typing import Any

import httpx

from growflow_billing.config import GrowFlowConfig
from growflow_billing.endpoints.checkout import CheckoutMixin
from growflow_billing.endpoints.connect import ConnectMixin
from growflow_billing.endpoints.invoices import InvoicesMixin
from growflow_billing.endpoints.plans import PlansMixin
from growflow_billing.endpoints.products import ProductsMixin
from growflow_billing.endpoints.subscribers import SubscribersMixin
from growflow_billing.endpoints.subscriptions import SubscriptionsMixin
from growflow_billing.exceptions import (
    AuthenticationError,
    ConflictError,
    GrowFlowBillingError,
    NotFoundError,
    RateLimitError,
    ServerError,
    ValidationError,
)


class GrowFlowBillingClient(
    PlansMixin,
    SubscribersMixin,
    SubscriptionsMixin,
    CheckoutMixin,
    InvoicesMixin,
    ProductsMixin,
    ConnectMixin,
):
    """Async HTTP client for GrowFlow Billing API.

    Usage as context manager (recommended):
        async with GrowFlowBillingClient(api_key="sk_live_xxx") as client:
            plans = await client.get_plans()

    Usage without context manager:
        client = GrowFlowBillingClient(api_key="sk_live_xxx")
        try:
            plans = await client.get_plans()
        finally:
            await client.close()

    Args:
        api_key: GrowFlow Billing API key (sk_live_xxx or sk_test_xxx)
        base_url: API base URL (default: https://billing.growflow.studio/api/v1)
        timeout: Request timeout in seconds (default: 30.0)
        max_retries: Maximum retry attempts for failed requests (default: 3)
        retry_delay: Base delay between retries in seconds (default: 1.0)

    Example:
        async with GrowFlowBillingClient(api_key="sk_live_xxx") as client:
            # Get available plans
            plans = await client.get_plans()

            # Create a subscriber
            subscriber = await client.create_subscriber(
                external_id="customer_123",
                email="customer@example.com",
                name="My Customer"
            )

            # Create checkout session
            session = await client.create_checkout_session(
                customer_external_id="customer_123",
                plan_slug="pro",
                billing_cycle="monthly",
                success_url="https://app.com/billing?status=success",
                cancel_url="https://app.com/billing?status=canceled",
            )
            print(f"Checkout URL: {session.checkout_url}")
    """

    def __init__(
        self,
        api_key: str | None = None,
        base_url: str = "https://billing.growflow.studio/api/v1",
        timeout: float = 30.0,
        max_retries: int = 3,
        retry_delay: float = 1.0,
    ) -> None:
        if api_key:
            self.config = GrowFlowConfig(
                api_key=api_key,
                base_url=base_url,
                timeout=timeout,
                max_retries=max_retries,
                retry_delay=retry_delay,
            )
        else:
            # Try to load from environment
            self.config = GrowFlowConfig.from_env()
            self.config.base_url = base_url
            self.config.timeout = timeout
            self.config.max_retries = max_retries
            self.config.retry_delay = retry_delay

        self._client: httpx.AsyncClient | None = None

    @property
    def mode(self) -> str:
        """Detect environment mode from API key prefix."""
        if self.config.api_key and self.config.api_key.startswith("sk_test_"):
            return "test"
        return "live"

    async def __aenter__(self) -> "GrowFlowBillingClient":
        """Enter async context manager."""
        self._client = httpx.AsyncClient(
            base_url=self.config.base_url,
            timeout=self.config.timeout,
            headers=self._get_headers(),
        )
        return self

    async def __aexit__(
        self,
        exc_type: type[BaseException] | None,
        exc_val: BaseException | None,
        exc_tb: Any,
    ) -> None:
        """Exit async context manager."""
        await self.close()

    async def close(self) -> None:
        """Close the HTTP client."""
        if self._client:
            await self._client.aclose()
            self._client = None

    def _get_headers(self) -> dict[str, str]:
        """Get HTTP headers for requests."""
        return {
            "Authorization": f"Bearer {self.config.api_key}",
            "Content-Type": "application/json",
            "Accept": "application/json",
            "User-Agent": "growflow-billing-python/1.0.0",
        }

    def _get_client(self) -> httpx.AsyncClient:
        """Get or create HTTP client."""
        if self._client is None:
            self._client = httpx.AsyncClient(
                base_url=self.config.base_url,
                timeout=self.config.timeout,
                headers=self._get_headers(),
            )
        return self._client

    async def _request(
        self,
        method: str,
        path: str,
        params: dict[str, Any] | None = None,
        json: dict[str, Any] | None = None,
    ) -> Any:
        """Make HTTP request with error handling.

        Args:
            method: HTTP method (GET, POST, etc.)
            path: API path (e.g., "/plans")
            params: Query parameters
            json: JSON body

        Returns:
            Response JSON data

        Raises:
            AuthenticationError: Invalid API key (401)
            NotFoundError: Resource not found (404)
            ConflictError: Resource already exists (409)
            ValidationError: Invalid request data (422)
            RateLimitError: Rate limit exceeded (429)
            ServerError: Server error (5xx)
            GrowFlowBillingError: Other errors
        """
        client = self._get_client()

        try:
            response = await client.request(
                method=method,
                url=path,
                params=params,
                json=json,
            )

            # Handle errors
            if response.status_code == 401:
                raise AuthenticationError(
                    "Invalid or missing API key",
                    status_code=401,
                    response=self._safe_json(response),
                )

            if response.status_code == 404:
                raise NotFoundError(
                    f"Resource not found: {path}",
                    status_code=404,
                    response=self._safe_json(response),
                )

            if response.status_code == 409:
                raise ConflictError(
                    "Resource already exists",
                    status_code=409,
                    response=self._safe_json(response),
                )

            if response.status_code == 422:
                error_data = self._safe_json(response)
                message = (
                    error_data.get("detail", "Validation error")
                    if error_data
                    else "Validation error"
                )
                raise ValidationError(
                    str(message),
                    status_code=422,
                    response=error_data,
                )

            if response.status_code == 429:
                raise RateLimitError(
                    "Rate limit exceeded",
                    status_code=429,
                    response=self._safe_json(response),
                )

            if response.status_code >= 500:
                raise ServerError(
                    f"Server error: {response.status_code}",
                    status_code=response.status_code,
                    response=self._safe_json(response),
                )

            if response.status_code >= 400:
                error_data = self._safe_json(response)
                message = (
                    error_data.get("detail", f"Error {response.status_code}")
                    if error_data
                    else f"Error {response.status_code}"
                )
                raise GrowFlowBillingError(
                    str(message),
                    status_code=response.status_code,
                    response=error_data,
                )

            # Success - return JSON data
            if response.status_code == 204:
                return {}
            return response.json()

        except httpx.TimeoutException as e:
            raise GrowFlowBillingError(f"Request timeout: {e}") from e
        except httpx.ConnectError as e:
            raise GrowFlowBillingError(f"Connection error: {e}") from e
        except httpx.HTTPError as e:
            raise GrowFlowBillingError(f"HTTP error: {e}") from e

    def _safe_json(self, response: httpx.Response) -> dict[str, Any] | None:
        """Safely parse response JSON."""
        try:
            return response.json()
        except Exception:
            return None
