"""Subscriptions resource for managing data stream subscriptions."""

from __future__ import annotations

import builtins
from collections.abc import AsyncIterator, Iterator
from typing import TYPE_CHECKING

from ticksupply.models.subscription import (
    PaginatedSubscriptions,
    Subscription,
    SubscriptionResponse,
    SubscriptionSpan,
)
from ticksupply.resources.base import AsyncResource, SyncResource

if TYPE_CHECKING:
    from ticksupply._base import AsyncHTTPClient, SyncHTTPClient


class SubscriptionsResource(SyncResource):
    """Synchronous resource for subscription operations.

    Subscriptions allow you to receive real-time market data for specific
    exchange/instrument/stream combinations.
    """

    def __init__(self, client: SyncHTTPClient) -> None:
        super().__init__(client)

    def list(
        self,
        *,
        limit: int | None = None,
        page_token: str | None = None,
    ) -> PaginatedSubscriptions:
        """List subscriptions for the authenticated account.

        Args:
            limit: Maximum number of subscriptions to return (default 50, max 100).
            page_token: Token for pagination (from previous response).

        Returns:
            Paginated list of subscriptions.

        Example:
            >>> page = client.subscriptions.list(limit=10)
            >>> for sub in page.items:
            ...     print(f"{sub.id}: {sub.status}")
            >>> if page.has_next:
            ...     next_page = client.subscriptions.list(page_token=page.next_page_token)
        """
        response = self._client.get(
            "/subscriptions",
            params={"limit": limit, "page_token": page_token},
        )
        return PaginatedSubscriptions.model_validate(response.json())

    def list_all(self, *, limit: int | None = None) -> Iterator[Subscription]:
        """Iterate over all subscriptions with automatic pagination.

        Args:
            limit: Page size for each request (default 50, max 100).

        Yields:
            Subscription objects.

        Example:
            >>> for sub in client.subscriptions.list_all():
            ...     print(f"{sub.id}: {sub.datastream.instrument}")
        """
        page_token: str | None = None
        while True:
            page = self.list(limit=limit, page_token=page_token)
            yield from page.items
            if not page.has_next:
                break
            page_token = page.next_page_token

    def get(self, subscription_id: str) -> Subscription:
        """Get a subscription by ID.

        Args:
            subscription_id: UUID of the subscription.

        Returns:
            Subscription details.

        Example:
            >>> sub = client.subscriptions.get("123e4567-e89b-12d3-a456-426614174000")
            >>> print(f"Status: {sub.status}")
        """
        response = self._client.get(f"/subscriptions/{subscription_id}")
        return Subscription.model_validate(response.json())

    def create(self, datastream_id: int) -> SubscriptionResponse:
        """Create a new subscription.

        Args:
            datastream_id: ID of the datastream to subscribe to.

        Returns:
            Created subscription details.

        Example:
            >>> # First, find the datastream_id for your desired data stream
            >>> datastreams = client.exchanges.get_datastreams("binance", "BTCUSDT", "trades")
            >>> datastream_id = datastreams[0].datastream_id
            >>>
            >>> # Create the subscription
            >>> sub = client.subscriptions.create(datastream_id)
            >>> print(f"Subscription created: {sub.id}")
        """
        response = self._client.post("/subscriptions", json_data={"datastream_id": datastream_id})
        return SubscriptionResponse.model_validate(response.json())

    def delete(self, subscription_id: str) -> None:
        """Delete a subscription.

        Args:
            subscription_id: UUID of the subscription to delete.

        Example:
            >>> client.subscriptions.delete("123e4567-e89b-12d3-a456-426614174000")
        """
        self._client.delete(f"/subscriptions/{subscription_id}")

    def pause(self, subscription_id: str) -> None:
        """Pause a subscription.

        Paused subscriptions stop receiving data but can be resumed later.

        Args:
            subscription_id: UUID of the subscription to pause.

        Example:
            >>> client.subscriptions.pause("123e4567-e89b-12d3-a456-426614174000")
        """
        self._client.post(f"/subscriptions/{subscription_id}/pause")

    def resume(self, subscription_id: str) -> None:
        """Resume a paused subscription.

        Args:
            subscription_id: UUID of the subscription to resume.

        Example:
            >>> client.subscriptions.resume("123e4567-e89b-12d3-a456-426614174000")
        """
        self._client.post(f"/subscriptions/{subscription_id}/resume")

    def list_spans(self, subscription_id: str) -> builtins.list[SubscriptionSpan]:
        """Get activity spans for a subscription.

        Spans represent periods when the subscription was active.

        Args:
            subscription_id: UUID of the subscription.

        Returns:
            List of subscription spans.

        Example:
            >>> spans = client.subscriptions.list_spans("123e4567-e89b-12d3-a456-426614174000")
            >>> for span in spans:
            ...     print(f"{span.started_at} - {span.ended_at or 'ongoing'}")
        """
        response = self._client.get(f"/subscriptions/{subscription_id}/spans")
        data = response.json()
        return [SubscriptionSpan.model_validate(item) for item in data]


class AsyncSubscriptionsResource(AsyncResource):
    """Asynchronous resource for subscription operations.

    Subscriptions allow you to receive real-time market data for specific
    exchange/instrument/stream combinations.
    """

    def __init__(self, client: AsyncHTTPClient) -> None:
        super().__init__(client)

    async def list(
        self,
        *,
        limit: int | None = None,
        page_token: str | None = None,
    ) -> PaginatedSubscriptions:
        """List subscriptions for the authenticated account.

        Args:
            limit: Maximum number of subscriptions to return (default 50, max 100).
            page_token: Token for pagination (from previous response).

        Returns:
            Paginated list of subscriptions.
        """
        response = await self._client.get(
            "/subscriptions",
            params={"limit": limit, "page_token": page_token},
        )
        return PaginatedSubscriptions.model_validate(response.json())

    async def list_all(self, *, limit: int | None = None) -> AsyncIterator[Subscription]:
        """Iterate over all subscriptions with automatic pagination.

        Args:
            limit: Page size for each request (default 50, max 100).

        Yields:
            Subscription objects.
        """
        page_token: str | None = None
        while True:
            page = await self.list(limit=limit, page_token=page_token)
            for item in page.items:
                yield item
            if not page.has_next:
                break
            page_token = page.next_page_token

    async def get(self, subscription_id: str) -> Subscription:
        """Get a subscription by ID.

        Args:
            subscription_id: UUID of the subscription.

        Returns:
            Subscription details.
        """
        response = await self._client.get(f"/subscriptions/{subscription_id}")
        return Subscription.model_validate(response.json())

    async def create(self, datastream_id: int) -> SubscriptionResponse:
        """Create a new subscription.

        Args:
            datastream_id: ID of the datastream to subscribe to.

        Returns:
            Created subscription details.
        """
        response = await self._client.post(
            "/subscriptions", json_data={"datastream_id": datastream_id}
        )
        return SubscriptionResponse.model_validate(response.json())

    async def delete(self, subscription_id: str) -> None:
        """Delete a subscription.

        Args:
            subscription_id: UUID of the subscription to delete.
        """
        await self._client.delete(f"/subscriptions/{subscription_id}")

    async def pause(self, subscription_id: str) -> None:
        """Pause a subscription.

        Paused subscriptions stop receiving data but can be resumed later.

        Args:
            subscription_id: UUID of the subscription to pause.
        """
        await self._client.post(f"/subscriptions/{subscription_id}/pause")

    async def resume(self, subscription_id: str) -> None:
        """Resume a paused subscription.

        Args:
            subscription_id: UUID of the subscription to resume.
        """
        await self._client.post(f"/subscriptions/{subscription_id}/resume")

    async def list_spans(self, subscription_id: str) -> builtins.list[SubscriptionSpan]:
        """Get activity spans for a subscription.

        Spans represent periods when the subscription was active.

        Args:
            subscription_id: UUID of the subscription.

        Returns:
            List of subscription spans.
        """
        response = await self._client.get(f"/subscriptions/{subscription_id}/spans")
        data = response.json()
        return [SubscriptionSpan.model_validate(item) for item in data]
