"""Billing API endpoints.

Supports the multi-subscription plan series architecture:
- Plan Series: Groups of related plans
- Subscriptions: One per series per tenant
- Quotas: Per-series resource limits
- Usage: Usage-based billing tracking
- Invoices: Monthly billing statements
"""

from __future__ import annotations

from typing import TYPE_CHECKING
from uuid import UUID

from vikdata.models.common import PaginatedResponse
from vikdata.models.billing import (
    PlanSeries,
    Plan,
    Subscription,
    CreateSubscriptionRequest,
    UpdateSubscriptionRequest,
    CancelSubscriptionRequest,
    UsageSummary,
    Invoice,
    CheckoutSessionRequest,
    CheckoutSessionResponse,
    BillingPortalResponse,
)

if TYPE_CHECKING:
    from vikdata.client import VikdataClient


class BillingSeriesAPI:
    """Plan series management."""

    def __init__(self, client: "VikdataClient") -> None:
        self._client = client

    async def list(self) -> list[PlanSeries]:
        """List available plan series.

        Returns:
            List of plan series
        """
        response = await self._client.request(
            "GET",
            "/api/v1/billing/series",
        )
        if isinstance(response, dict) and "data" in response:
            return [PlanSeries.model_validate(s) for s in response["data"]]
        return [PlanSeries.model_validate(s) for s in response]

    async def get(self, slug: str) -> PlanSeries:
        """Get a specific series by slug.

        Args:
            slug: Series slug

        Returns:
            Plan series details
        """
        return await self._client.request(
            "GET",
            f"/api/v1/billing/series/{slug}",
            response_model=PlanSeries,
        )

    async def plans(
        self,
        slug: str,
        *,
        public_only: bool | None = None,
    ) -> list[Plan]:
        """List plans for a specific series.

        Args:
            slug: Series slug
            public_only: Only show public plans

        Returns:
            List of plans
        """
        params = {}
        if public_only is not None:
            params["public_only"] = public_only

        response = await self._client.request(
            "GET",
            f"/api/v1/billing/series/{slug}/plans",
            params=params if params else None,
        )
        if isinstance(response, dict) and "data" in response:
            return [Plan.model_validate(p) for p in response["data"]]
        return [Plan.model_validate(p) for p in response]


class BillingPlansAPI:
    """Plan management."""

    def __init__(self, client: "VikdataClient") -> None:
        self._client = client

    async def list(self, *, public_only: bool | None = None) -> list[Plan]:
        """List all available subscription plans across all series.

        Args:
            public_only: Only show public plans

        Returns:
            List of plans
        """
        params = {}
        if public_only is not None:
            params["public_only"] = public_only

        response = await self._client.request(
            "GET",
            "/api/v1/billing/plans",
            params=params if params else None,
        )
        if isinstance(response, dict) and "data" in response:
            return [Plan.model_validate(p) for p in response["data"]]
        return [Plan.model_validate(p) for p in response]

    async def get(self, plan_id: UUID) -> Plan:
        """Get a specific plan by ID.

        Args:
            plan_id: Plan ID

        Returns:
            Plan details
        """
        return await self._client.request(
            "GET",
            f"/api/v1/billing/plans/{plan_id}",
            response_model=Plan,
        )


class BillingSubscriptionsAPI:
    """Multi-subscription management.

    Tenants can have one subscription per series.
    """

    def __init__(self, client: "VikdataClient") -> None:
        self._client = client

    async def list(self) -> list[Subscription]:
        """List all subscriptions for the current tenant.

        Returns:
            List of subscriptions
        """
        response = await self._client.request(
            "GET",
            "/api/v1/billing/subscriptions",
        )
        if isinstance(response, dict) and "data" in response:
            return [Subscription.model_validate(s) for s in response["data"]]
        return [Subscription.model_validate(s) for s in response]

    async def get_for_series(self, series_id: UUID) -> Subscription | None:
        """Get subscription for a specific series.

        Args:
            series_id: Series ID

        Returns:
            Subscription if exists, None otherwise
        """
        return await self._client.request(
            "GET",
            f"/api/v1/billing/subscriptions/{series_id}",
            response_model=Subscription,
        )

    async def create(self, data: CreateSubscriptionRequest) -> Subscription:
        """Create a subscription (determines series from plan).

        Args:
            data: Subscription creation data

        Returns:
            Created subscription
        """
        return await self._client.request(
            "POST",
            "/api/v1/billing/subscriptions",
            json=data,
            response_model=Subscription,
        )

    async def update(
        self,
        series_id: UUID,
        data: UpdateSubscriptionRequest,
    ) -> Subscription:
        """Update a subscription to a new plan (within same series).

        Args:
            series_id: Series ID
            data: Subscription update data

        Returns:
            Updated subscription
        """
        return await self._client.request(
            "PUT",
            f"/api/v1/billing/subscriptions/{series_id}",
            json=data,
            response_model=Subscription,
        )

    async def cancel(
        self,
        series_id: UUID,
        data: CancelSubscriptionRequest | None = None,
    ) -> Subscription:
        """Cancel a subscription for a series.

        Args:
            series_id: Series ID
            data: Cancellation options (defaults to cancel at period end)

        Returns:
            Updated subscription
        """
        if data is None:
            data = CancelSubscriptionRequest(at_period_end=True)

        return await self._client.request(
            "DELETE",
            f"/api/v1/billing/subscriptions/{series_id}",
            json=data,
            response_model=Subscription,
        )


class BillingUsageAPI:
    """Usage tracking for billing."""

    def __init__(self, client: "VikdataClient") -> None:
        self._client = client

    async def get_summary(self, series_id: UUID) -> UsageSummary:
        """Get usage summary for a series in the current billing period.

        Args:
            series_id: Series ID

        Returns:
            Usage summary with metrics and overage
        """
        return await self._client.request(
            "GET",
            f"/api/v1/billing/usage/{series_id}",
            response_model=UsageSummary,
        )


class BillingInvoicesAPI:
    """Invoice management."""

    def __init__(self, client: "VikdataClient") -> None:
        self._client = client

    async def list(
        self,
        *,
        page: int | None = None,
        per_page: int | None = None,
        series_id: UUID | None = None,
        status: str | None = None,
    ) -> PaginatedResponse[Invoice]:
        """List invoices for the current tenant.

        Args:
            page: Page number (default: 1)
            per_page: Items per page (default: 20, max: 100)
            series_id: Filter by series
            status: Filter by status (from lookup)

        Returns:
            Paginated list of invoices
        """
        params = {
            "page": page,
            "per_page": per_page,
            "series_id": str(series_id) if series_id else None,
            "status": status,
        }
        params = {k: v for k, v in params.items() if v is not None}

        return await self._client.request(
            "GET",
            "/api/v1/billing/invoices",
            params=params,
            response_model=PaginatedResponse[Invoice],
        )

    async def get(self, invoice_id: UUID) -> Invoice:
        """Get a specific invoice by ID.

        Args:
            invoice_id: Invoice ID

        Returns:
            Invoice details
        """
        return await self._client.request(
            "GET",
            f"/api/v1/billing/invoices/{invoice_id}",
            response_model=Invoice,
        )


class BillingCheckoutAPI:
    """Checkout session management."""

    def __init__(self, client: "VikdataClient") -> None:
        self._client = client

    async def create_session(
        self,
        data: CheckoutSessionRequest,
    ) -> CheckoutSessionResponse:
        """Create a checkout session for subscribing to a plan.

        Returns a URL to redirect the user to for payment.

        Args:
            data: Checkout session request

        Returns:
            Checkout session with URL
        """
        return await self._client.request(
            "POST",
            "/api/v1/billing/checkout",
            json=data,
            response_model=CheckoutSessionResponse,
        )


class BillingPortalAPI:
    """Billing portal management."""

    def __init__(self, client: "VikdataClient") -> None:
        self._client = client

    async def create_session(self, return_url: str) -> BillingPortalResponse:
        """Create a billing portal session for managing payment methods.

        Returns a URL to redirect the user to the billing portal.

        Args:
            return_url: URL to redirect after portal session

        Returns:
            Billing portal session with URL
        """
        return await self._client.request(
            "POST",
            "/api/v1/billing/portal",
            params={"return_url": return_url},
            response_model=BillingPortalResponse,
        )


class BillingAPI:
    """Billing API endpoints.

    Handles plan series, plans, subscriptions, usage, invoices, and checkout.
    """

    def __init__(self, client: "VikdataClient") -> None:
        self._client = client
        self.series = BillingSeriesAPI(client)
        self.plans = BillingPlansAPI(client)
        self.subscriptions = BillingSubscriptionsAPI(client)
        self.usage = BillingUsageAPI(client)
        self.invoices = BillingInvoicesAPI(client)
        self.checkout = BillingCheckoutAPI(client)
        self.portal = BillingPortalAPI(client)
