"""Base pricing provider interface."""

from abc import ABC, abstractmethod
from decimal import Decimal
from typing import Dict, List, Optional, Any, Callable
from datetime import datetime
from src.core.logger import get_logger

logger = get_logger(__name__)


class BasePricingProvider(ABC):
    """Base class for pricing data providers.
    
    Pricing providers are responsible for fetching market data (prices, OHLCV)
    without requiring API keys. They differ from exchange adapters which handle
    trading operations.
    """
    
    def __init__(self):
        """Initialize pricing provider."""
        self.logger = get_logger(f"provider.{self.__class__.__name__}")
        self._connected = False
        self._subscribers: Dict[str, List[Callable]] = {}
    
    @property
    @abstractmethod
    def name(self) -> str:
        """Provider name."""
        pass
    
    @property
    @abstractmethod
    def supports_websocket(self) -> bool:
        """Whether this provider supports WebSocket connections."""
        pass
    
    @abstractmethod
    def connect(self) -> bool:
        """Connect to the provider.
        
        Returns:
            True if connection successful
        """
        pass
    
    @abstractmethod
    def disconnect(self):
        """Disconnect from the provider."""
        pass
    
    @abstractmethod
    def get_ticker(self, symbol: str) -> Dict[str, Any]:
        """Get current ticker data for a symbol.
        
        Args:
            symbol: Trading pair symbol (e.g., 'BTC/USD')
            
        Returns:
            Dictionary with ticker data:
            - 'symbol': str
            - 'bid': Decimal
            - 'ask': Decimal
            - 'last': Decimal (last price)
            - 'high': Decimal (24h high)
            - 'low': Decimal (24h low)
            - 'volume': Decimal (24h volume)
            - 'timestamp': int (Unix timestamp in milliseconds)
        """
        pass
    
    @abstractmethod
    def get_ohlcv(
        self,
        symbol: str,
        timeframe: str = '1h',
        since: Optional[datetime] = None,
        limit: int = 100
    ) -> List[List]:
        """Get OHLCV (candlestick) data.
        
        Args:
            symbol: Trading pair symbol
            timeframe: Timeframe (1m, 5m, 15m, 1h, 1d, etc.)
            since: Start datetime
            limit: Number of candles
            
        Returns:
            List of [timestamp_ms, open, high, low, close, volume]
        """
        pass
    
    @abstractmethod
    def subscribe_ticker(self, symbol: str, callback: Callable) -> bool:
        """Subscribe to ticker updates.
        
        Args:
            symbol: Trading pair symbol
            callback: Callback function(data) called on price updates
            
        Returns:
            True if subscription successful
        """
        pass
    
    def unsubscribe_ticker(self, symbol: str, callback: Optional[Callable] = None):
        """Unsubscribe from ticker updates.
        
        Args:
            symbol: Trading pair symbol
            callback: Specific callback to remove, or None to remove all
        """
        key = f"ticker_{symbol}"
        if key in self._subscribers:
            if callback:
                if callback in self._subscribers[key]:
                    self._subscribers[key].remove(callback)
                if not self._subscribers[key]:
                    del self._subscribers[key]
            else:
                del self._subscribers[key]
    
    def normalize_symbol(self, symbol: str) -> str:
        """Normalize symbol format for this provider.
        
        Args:
            symbol: Symbol to normalize
            
        Returns:
            Normalized symbol
        """
        # Default: uppercase and replace dashes with slashes
        return symbol.upper().replace('-', '/')
    
    def is_connected(self) -> bool:
        """Check if provider is connected.
        
        Returns:
            True if connected
        """
        return self._connected
    
    def get_supported_symbols(self) -> List[str]:
        """Get list of supported trading symbols.
        
        Returns:
            List of supported symbols, or empty list if not available
        """
        # Default implementation - override in subclasses
        return []
