from abc import ABC, abstractmethod
from typing import Optional, List

import pandas as pd

from dexorder.utils import TimestampInput


class DataAPI(ABC):
    """
    API for accessing market data.

    Provides methods to query OHLC (Open, High, Low, Close) candlestick data
    for cryptocurrency markets.
    """

    @abstractmethod
    async def historical_ohlc(
        self,
        ticker: str,
        period_seconds: int,
        start_time: TimestampInput,
        end_time: TimestampInput,
        extra_columns: Optional[List[str]] = None,
    ) -> pd.DataFrame:
        """
        Fetch historical OHLC candlestick data for a market.

        Args:
            ticker: Market identifier in format "MARKET.EXCHANGE"
                   Examples: "BTC/USDT.BINANCE", "ETH/USD.COINBASE"
            period_seconds: Candle period in seconds
                   Common values:
                   - 60 (1 minute)
                   - 300 (5 minutes)
                   - 900 (15 minutes)
                   - 3600 (1 hour)
                   - 86400 (1 day)
                   - 604800 (1 week)
            start_time: Start of time range. Accepts:
                       - Unix timestamp in seconds (int/float): 1640000000
                       - Date string: "2021-12-20" or "2021-12-20 12:00:00"
                       - datetime object: datetime(2021, 12, 20)
                       - pandas Timestamp: pd.Timestamp("2021-12-20")
            end_time: End of time range. Same formats as start_time.
            extra_columns: Optional additional columns to include beyond the standard
                          OHLC columns. Available options:
                          - "volume" - Total volume (decimal float)
                          - "buy_vol" - Buy-side volume (decimal float)
                          - "sell_vol" - Sell-side volume (decimal float)
                          - "open_time", "high_time", "low_time", "close_time" (timestamps)
                          - "open_interest" (for futures markets)
                          - "ticker", "period_seconds"

        Returns:
            DataFrame with candlestick data sorted by timestamp (ascending).
            Standard columns (always included):
            - timestamp: Period start time in nanoseconds
            - open: Opening price (decimal float)
            - high: Highest price (decimal float)
            - low: Lowest price (decimal float)
            - close: Closing price (decimal float)

            Plus any columns specified in extra_columns.

            All prices and volumes are automatically converted to decimal floats
            using market metadata. No manual conversion is needed.

            Returns empty DataFrame if no data is available.

        Examples:
            # Basic OHLC with Unix timestamp
            df = await api.historical_ohlc(
                ticker="BTC/USDT.BINANCE",
                period_seconds=3600,
                start_time=1640000000,
                end_time=1640086400
            )

            # Using date strings with volume
            df = await api.historical_ohlc(
                ticker="BTC/USDT.BINANCE",
                period_seconds=3600,
                start_time="2021-12-20",
                end_time="2021-12-21",
                extra_columns=["volume"]
            )

            # Using datetime objects
            from datetime import datetime
            df = await api.historical_ohlc(
                ticker="ETH/USD.COINBASE",
                period_seconds=300,
                start_time=datetime(2021, 12, 20, 9, 30),
                end_time=datetime(2021, 12, 20, 16, 30),
                extra_columns=["volume", "buy_vol", "sell_vol"]
            )
        """
        pass

    @abstractmethod
    async def latest_ohlc(
        self,
        ticker: str,
        period_seconds: int,
        length: int = 1,
        extra_columns: Optional[List[str]] = None,
    ) -> pd.DataFrame:
        """
        Query the most recent OHLC candles for a ticker.

        This method fetches the latest N completed candles without needing to
        specify exact timestamps. Useful for real-time analysis and indicators.

        Args:
            ticker: Market identifier in format "MARKET.EXCHANGE"
                   Examples: "BTC/USDT.BINANCE", "ETH/USD.COINBASE"
            period_seconds: OHLC candle period in seconds
                   Common values: 60 (1m), 300 (5m), 900 (15m), 3600 (1h),
                                 86400 (1d), 604800 (1w)
            length: Number of most recent candles to return (default: 1)
            extra_columns: Optional list of additional column names to include.
                          Same column options as historical_ohlc:
                          - "volume", "buy_vol", "sell_vol"
                          - "open_time", "high_time", "low_time", "close_time"
                          - "open_interest", "ticker", "period_seconds"

        Returns:
            Pandas DataFrame with the same column structure as historical_ohlc,
            containing the N most recent completed candles sorted by timestamp.
            Returns empty DataFrame if no data is available.

        Examples:
            # Get the last candle
            df = await api.latest_ohlc(
                ticker="BTC/USDT.BINANCE",
                period_seconds=3600
            )
            # Returns: timestamp, open, high, low, close

            # Get the last 50 5-minute candles with volume
            df = await api.latest_ohlc(
                ticker="ETH/USD.COINBASE",
                period_seconds=300,
                length=50,
                extra_columns=["volume", "buy_vol", "sell_vol"]
            )

            # Get recent candles with all timing data
            df = await api.latest_ohlc(
                ticker="BTC/USDT.BINANCE",
                period_seconds=60,
                length=100,
                extra_columns=["open_time", "high_time", "low_time", "close_time"]
            )

        Note:
            This method returns only completed candles. The current (incomplete)
            candle is not included.
        """
        pass

