"""Centralized fee calculation service for trading operations."""

from decimal import Decimal
from typing import Dict, Optional, Any
from src.core.logger import get_logger
from src.core.config import get_config
from src.exchanges.base import BaseExchangeAdapter
from src.core.database import OrderType, OrderSide

logger = get_logger(__name__)


class FeeCalculator:
    """Centralized fee calculation service."""
    
    def __init__(self):
        """Initialize fee calculator."""
        self.config = get_config()
        self.logger = get_logger(__name__)
    
    def calculate_fee(
        self,
        quantity: Decimal,
        price: Decimal,
        order_type: OrderType,
        exchange_adapter: Optional[BaseExchangeAdapter] = None,
        is_maker: Optional[bool] = None
    ) -> Decimal:
        """Calculate trading fee for an order.
        
        Args:
            quantity: Trade quantity
            price: Trade price
            order_type: Order type (MARKET or LIMIT)
            exchange_adapter: Exchange adapter for fee structure (optional)
            is_maker: Explicit maker/taker flag (if None, determined from order_type)
            
        Returns:
            Trading fee amount
        """
        if quantity <= 0 or price <= 0:
            return Decimal(0)
        
        # Determine maker/taker if not explicitly provided
        if is_maker is None:
            is_maker = self._is_maker_order(order_type)
        
        # Get fee structure
        fee_structure = self._get_fee_structure(exchange_adapter)
        fee_rate = fee_structure['maker'] if is_maker else fee_structure['taker']
        
        # Calculate fee
        trade_value = quantity * price
        fee = trade_value * Decimal(str(fee_rate))
        
        # Apply minimum fee if configured
        min_fee = fee_structure.get('minimum', Decimal(0))
        if min_fee > 0 and fee < min_fee:
            fee = min_fee
        
        return fee
    
    def estimate_round_trip_fee(
        self,
        quantity: Decimal,
        price: Decimal,
        exchange_adapter: Optional[BaseExchangeAdapter] = None
    ) -> Decimal:
        """Estimate total fees for a round-trip trade (buy + sell).
        
        Args:
            quantity: Trade quantity
            price: Trade price
            exchange_adapter: Exchange adapter for fee structure (optional)
            
        Returns:
            Total estimated round-trip fee
        """
        # Estimate using taker fees (worst case)
        buy_fee = self.calculate_fee(quantity, price, OrderType.MARKET, exchange_adapter, is_maker=False)
        sell_fee = self.calculate_fee(quantity, price, OrderType.MARKET, exchange_adapter, is_maker=False)
        
        return buy_fee + sell_fee
    
    def get_minimum_profit_threshold(
        self,
        quantity: Decimal,
        price: Decimal,
        exchange_adapter: Optional[BaseExchangeAdapter] = None,
        multiplier: float = 2.0
    ) -> Decimal:
        """Calculate minimum profit threshold needed to break even after fees.
        
        Args:
            quantity: Trade quantity
            price: Trade price
            exchange_adapter: Exchange adapter for fee structure (optional)
            multiplier: Multiplier for minimum profit (default 2.0 = 2x fees)
            
        Returns:
            Minimum profit threshold
        """
        round_trip_fee = self.estimate_round_trip_fee(quantity, price, exchange_adapter)
        return round_trip_fee * Decimal(str(multiplier))
    
    def calculate_fee_reserve(
        self,
        position_value: Decimal,
        exchange_adapter: Optional[BaseExchangeAdapter] = None,
        reserve_percent: Optional[float] = None
    ) -> Decimal:
        """Calculate fee reserve amount for position sizing.
        
        Args:
            position_value: Intended position value
            exchange_adapter: Exchange adapter for fee structure (optional)
            reserve_percent: Override reserve percentage (default: 0.4% for round-trip)
            
        Returns:
            Fee reserve amount
        """
        if reserve_percent is None:
            # Default: 0.4% for round-trip (conservative estimate)
            reserve_percent = 0.004
        
        return position_value * Decimal(str(reserve_percent))
    
    def _is_maker_order(self, order_type: OrderType) -> bool:
        """Determine if order type is typically a maker order.
        
        Args:
            order_type: Order type
            
        Returns:
            True if maker order, False if taker order
        """
        # Limit orders that add liquidity = maker
        # Market orders that take liquidity = taker
        return order_type == OrderType.LIMIT
    
    def _get_fee_structure(
        self,
        exchange_adapter: Optional[BaseExchangeAdapter] = None
    ) -> Dict[str, Any]:
        """Get fee structure from exchange or config defaults.
        
        Args:
            exchange_adapter: Exchange adapter (optional)
            
        Returns:
            Fee structure dictionary with 'maker', 'taker', and optional 'minimum'
        """
        # Try to get from exchange adapter first
        if exchange_adapter:
            try:
                fee_structure = exchange_adapter.get_fee_structure()
                if fee_structure:
                    return fee_structure
            except Exception as e:
                self.logger.warning(f"Failed to get fee structure from exchange: {e}")
        
        # Get from config with exchange-specific overrides
        default_fees = self.config.get("trading.default_fees", {
            "maker": 0.001,  # 0.1%
            "taker": 0.001,  # 0.1%
            "minimum": 0.0
        })
        
        # Check for exchange-specific fees if adapter provided
        if exchange_adapter:
            exchange_name = exchange_adapter.name.lower()
            exchange_fees = self.config.get(f"trading.exchanges.{exchange_name}.fees")
            if exchange_fees:
                default_fees.update(exchange_fees)
        
        return default_fees
    
    def get_fee_structure_by_exchange_name(
        self,
        exchange_name: str
    ) -> Dict[str, Any]:
        """Get fee structure for a specific exchange by name (for paper trading).
        
        Args:
            exchange_name: Exchange name (e.g., 'coinbase', 'kraken', 'binance')
            
        Returns:
            Fee structure dictionary with 'maker', 'taker', and optional 'minimum'
        """
        # Get default fees
        default_fees = self.config.get("trading.default_fees", {
            "maker": 0.001,  # 0.1%
            "taker": 0.001,  # 0.1%
            "minimum": 0.0
        })
        
        # Check for exchange-specific fees
        exchange_fees = self.config.get(f"trading.exchanges.{exchange_name.lower()}.fees")
        if exchange_fees:
            return {**default_fees, **exchange_fees}
        
        return default_fees
    
    def calculate_fee_for_paper_trading(
        self,
        quantity: Decimal,
        price: Decimal,
        order_type: OrderType,
        is_maker: Optional[bool] = None
    ) -> Decimal:
        """Calculate trading fee for paper trading using configured exchange.
        
        Args:
            quantity: Trade quantity
            price: Trade price
            order_type: Order type (MARKET or LIMIT)
            is_maker: Explicit maker/taker flag (if None, determined from order_type)
            
        Returns:
            Trading fee amount
        """
        if quantity <= 0 or price <= 0:
            return Decimal(0)
        
        # Determine maker/taker if not explicitly provided
        if is_maker is None:
            is_maker = self._is_maker_order(order_type)
        
        # Get fee exchange from config
        fee_exchange = self.config.get("paper_trading.fee_exchange", "coinbase")
        fee_structure = self.get_fee_structure_by_exchange_name(fee_exchange)
        fee_rate = fee_structure['maker'] if is_maker else fee_structure['taker']
        
        # Calculate fee
        trade_value = quantity * price
        fee = trade_value * Decimal(str(fee_rate))
        
        # Apply minimum fee if configured
        min_fee = fee_structure.get('minimum', Decimal(0))
        if min_fee > 0 and fee < min_fee:
            fee = min_fee
        
        return fee
    
    def get_fee_percentage(
        self,
        order_type: OrderType,
        exchange_adapter: Optional[BaseExchangeAdapter] = None
    ) -> float:
        """Get fee percentage for order type.
        
        Args:
            order_type: Order type
            exchange_adapter: Exchange adapter (optional)
            
        Returns:
            Fee percentage (e.g., 0.001 for 0.1%)
        """
        is_maker = self._is_maker_order(order_type)
        fee_structure = self._get_fee_structure(exchange_adapter)
        return fee_structure['maker'] if is_maker else fee_structure['taker']


# Global fee calculator instance
_fee_calculator: Optional[FeeCalculator] = None


def get_fee_calculator() -> FeeCalculator:
    """Get global fee calculator instance.
    
    Returns:
        FeeCalculator instance
    """
    global _fee_calculator
    if _fee_calculator is None:
        _fee_calculator = FeeCalculator()
    return _fee_calculator

