"""
Implementation of DataAPI using OHLCClient for smart caching.
"""

import logging
from typing import Optional, List
import pandas as pd

from dexorder.api.data_api import DataAPI
from dexorder.ohlc_client import OHLCClient
from dexorder.utils import TimestampInput, to_nanoseconds

log = logging.getLogger(__name__)

# Standard OHLC columns always returned
STANDARD_COLUMNS = ["timestamp", "open", "high", "low", "close"]

# All optional columns from the OHLC proto spec, returned by default when extra_columns=None
OHLC_OPTIONAL_COLUMNS = [
    "volume", "buy_vol", "sell_vol",
    "open_time", "high_time", "low_time", "close_time",
    "open_interest",
]

# All valid extra columns available in the Iceberg schema
VALID_EXTRA_COLUMNS = {
    "volume", "buy_vol", "sell_vol",
    "open_time", "high_time", "low_time", "close_time",
    "open_interest",
    "ticker", "period_seconds"
}


class DataAPIImpl(DataAPI):
    """
    Implementation of DataAPI using OHLCClient for querying OHLC data.

    This implementation provides:
    - Smart caching via Iceberg (checks cache first, fetches missing data on-demand)
    - Selective column queries to minimize data transfer
    - Integration with the historical data pipeline via relay
    """

    def __init__(
        self,
        iceberg_catalog_uri: str,
        relay_endpoint: str,
        notification_endpoint: str,
        namespace: str = "trading",
        s3_endpoint: Optional[str] = None,
        s3_access_key: Optional[str] = None,
        s3_secret_key: Optional[str] = None,
        s3_region: Optional[str] = None,
        request_timeout: float = 30.0,
    ):
        """
        Initialize DataAPI implementation.

        Args:
            iceberg_catalog_uri: URI of Iceberg REST catalog (e.g., "http://iceberg-catalog:8181")
            relay_endpoint: ZMQ endpoint for relay requests (e.g., "tcp://relay:5559")
            notification_endpoint: ZMQ endpoint for notifications (e.g., "tcp://relay:5558")
            namespace: Iceberg namespace (default: "trading")
            s3_endpoint: S3/MinIO endpoint URL (e.g., "http://minio:9000")
            s3_access_key: S3/MinIO access key
            s3_secret_key: S3/MinIO secret key
            s3_region: S3/MinIO region (e.g., "us-east-1")
            request_timeout: Default timeout for historical data requests in seconds (default: 30)
        """
        self.ohlc_client = OHLCClient(
            iceberg_catalog_uri=iceberg_catalog_uri,
            relay_endpoint=relay_endpoint,
            notification_endpoint=notification_endpoint,
            namespace=namespace,
            s3_endpoint=s3_endpoint,
            s3_access_key=s3_access_key,
            s3_secret_key=s3_secret_key,
            s3_region=s3_region,
        )
        self.request_timeout = request_timeout
        self._started = False

    async def start(self):
        """
        Start the DataAPI client.

        Must be called before making any queries. Initializes the background
        notification listener for historical data requests.
        """
        if not self._started:
            await self.ohlc_client.start()
            self._started = True

    async def stop(self):
        """
        Stop the DataAPI client and cleanup resources.
        """
        if self._started:
            await self.ohlc_client.stop()
            self._started = False

    async def historical_ohlc(
        self,
        ticker: str,
        period_seconds: int,
        start_time: TimestampInput,
        end_time: TimestampInput,
        extra_columns: Optional[List[str]] = None,
    ) -> pd.DataFrame:
        """
        Query historical OHLC data with smart caching.

        See DataAPI.historical_ohlc for full documentation.
        """
        if not self._started:
            await self.start()

        # Convert timestamps to nanoseconds
        start_nanos = to_nanoseconds(start_time)
        end_nanos = to_nanoseconds(end_time)

        log.debug(f"Fetching OHLC: {ticker}, period={period_seconds}s, "
                  f"start={start_time} ({start_nanos}ns), end={end_time} ({end_nanos}ns)")

        # Validate extra_columns
        if extra_columns:
            invalid = set(extra_columns) - VALID_EXTRA_COLUMNS
            if invalid:
                raise ValueError(f"Invalid extra columns: {invalid}. Valid options: {VALID_EXTRA_COLUMNS}")

        # Determine which columns to fetch
        columns_to_fetch = STANDARD_COLUMNS.copy()
        if extra_columns is None:
            columns_to_fetch.extend(OHLC_OPTIONAL_COLUMNS)
        elif extra_columns:
            columns_to_fetch.extend(extra_columns)

        # Use OHLCClient which handles smart caching:
        # 1. Check Iceberg for existing data
        # 2. Request missing data via relay if needed
        # 3. Wait for notification
        # 4. Return complete dataset
        df = await self.ohlc_client.fetch_ohlc(
            ticker=ticker,
            period_seconds=period_seconds,
            start_time=start_nanos,
            end_time=end_nanos,
            request_timeout=self.request_timeout
        )

        # Select only requested columns (filter out metadata and unrequested fields)
        if not df.empty:
            available_cols = [col for col in columns_to_fetch if col in df.columns]
            df = df[available_cols]

        return df

    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.

        See DataAPI.latest_ohlc for full documentation.

        Note: This method is not yet implemented.
        """
        raise NotImplementedError("latest_ohlc will be implemented in the future")

    async def __aenter__(self):
        """Support async context manager."""
        await self.start()
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """Support async context manager."""
        await self.stop()
