# tradedesk/subscriptions.py
"""
Subscription type definitions for market data streams.

Strategies declare their data needs using these subscription types,
and the framework handles the Lightstreamer subscription setup.
"""

from abc import ABC, abstractmethod
from dataclasses import dataclass, field


__all__ = [
    "ChartSubscription",
    "MarketSubscription",
    "Subscription",
]


@dataclass
class Subscription(ABC):
    """Base class for different subscription types."""

    instrument: str

    @abstractmethod
    def get_item_name(self) -> str: ...

    @abstractmethod
    def get_fields(self) -> list[str]: ...


@dataclass
class MarketSubscription(Subscription):
    """
    Subscribe to live tick-by-tick price updates for an instrument.

    Used for real-time bid/offer monitoring without candle aggregation.
    Triggers strategy's on_price_update() callback.

    Example:
        SUBSCRIPTIONS = [
            MarketSubscription("CS.D.GBPUSD.TODAY.IP"),
        ]
    """

    def get_item_name(self) -> str:
        """Returns Lightstreamer item name format."""
        return f"MARKET:{self.instrument}"

    def get_fields(self) -> list[str]:
        """Returns Lightstreamer fields to subscribe to."""
        return ["UPDATE_TIME", "BID", "OFFER", "MARKET_STATE"]


@dataclass
class ChartSubscription(Subscription):
    """
    Subscribe to OHLCV candle data for an instrument at a specific timeframe.

    This subscription provides a stream of completed candles, which triggers the
    strategy's `on_candle_close()` callback.

    Attributes:
        instrument: The instrument identifier (e.g., 'CS.D.GBPUSD.TODAY.IP').
        period: The candle period. Common values include "1MINUTE", "5MINUTE",
            "15MINUTE", "30MINUTE", "HOUR", "4HOUR", "DAY", "WEEK".
        fields: An optional list of custom provider-specific fields to subscribe
            to. If `None`, a default set of OHLCV and volume fields is used.

    Example:
        SUBSCRIPTIONS = [
            ChartSubscription("CS.D.GBPUSD.TODAY.IP", "5MINUTE"),
            ChartSubscription("CS.D.EURUSD.TODAY.IP", "1MINUTE"),
        ]
    """

    period: str
    fields: list[str] | None = field(default=None)

    def __post_init__(self) -> None:
        """Set default fields if not provided."""
        if self.fields is None:
            # Standard OHLCV fields plus metadata
            self.fields = [
                # Offer (ask) prices
                "OFR_OPEN",
                "OFR_HIGH",
                "OFR_LOW",
                "OFR_CLOSE",
                # Bid prices
                "BID_OPEN",
                "BID_HIGH",
                "BID_LOW",
                "BID_CLOSE",
                # Volume data
                "LTV",  # Last traded volume
                "CONS_TICK_COUNT",  # Consolidated tick count (volume proxy)
                # Metadata
                "CONS_END",  # Candle completion indicator
                "UTM",  # Update timestamp
            ]

    def get_item_name(self) -> str:
        """Returns Lightstreamer item name format."""
        return f"CHART:{self.instrument}:{self.period}"

    def get_fields(self) -> list[str]:
        """Returns Lightstreamer fields to subscribe to."""
        assert self.fields is not None  # Set in __post_init__
        return self.fields
