"""
Broker Factory for BrighterTrading.

Creates the appropriate broker instance based on the trading mode.
"""

import logging
from typing import Any, Optional, Callable

from .base_broker import BaseBroker
from .backtest_broker import BacktestBroker
from .paper_broker import PaperBroker
from .live_broker import LiveBroker

logger = logging.getLogger(__name__)


class TradingMode:
    """Trading mode constants."""
    BACKTEST = 'backtest'
    PAPER = 'paper'
    LIVE = 'live'


def create_broker(
    mode: str,
    initial_balance: float = 10000.0,
    commission: float = 0.001,
    slippage: float = 0.0,
    price_provider: Optional[Callable[[str], float]] = None,
    data_cache: Any = None,
    exchange: Any = None,
    testnet: bool = True,
    rate_limit: float = 2.0,
    **kwargs
) -> BaseBroker:
    """
    Factory function to create the appropriate broker for the trading mode.

    :param mode: Trading mode ('backtest', 'paper', 'live').
    :param initial_balance: Starting balance.
    :param commission: Commission rate.
    :param slippage: Slippage rate.
    :param price_provider: Callable for getting current prices (paper/live).
    :param data_cache: DataCache instance for persistence.
    :param exchange: Exchange instance for live trading.
    :param testnet: Use testnet for live trading (default True for safety).
    :param rate_limit: API calls per second limit for live trading.
    :param kwargs: Additional arguments passed to broker constructor.
    :return: Broker instance.
    """
    mode = mode.lower()

    if mode == TradingMode.BACKTEST:
        logger.info("Creating BacktestBroker")
        return BacktestBroker(
            initial_balance=initial_balance,
            commission=commission,
            slippage=slippage,
            **kwargs
        )

    elif mode == TradingMode.PAPER:
        logger.info("Creating PaperBroker")
        return PaperBroker(
            initial_balance=initial_balance,
            commission=commission,
            slippage=slippage if slippage > 0 else 0.0005,  # Default slippage for paper
            price_provider=price_provider,
            data_cache=data_cache,
            **kwargs
        )

    elif mode == TradingMode.LIVE:
        # Verify exchange is provided for live trading
        if exchange is None:
            raise ValueError(
                "Live trading requires an exchange instance. "
                "Please provide the 'exchange' parameter."
            )

        # Safety warning for production mode
        if not testnet:
            logger.warning(
                "Creating LiveBroker for PRODUCTION trading. "
                "Real money will be used!"
            )
        else:
            logger.info("Creating LiveBroker in TESTNET mode")

        return LiveBroker(
            exchange=exchange,
            testnet=testnet,
            initial_balance=initial_balance,
            commission=commission,
            slippage=slippage,
            data_cache=data_cache,
            rate_limit=rate_limit,
            **kwargs
        )

    else:
        raise ValueError(f"Invalid trading mode: {mode}. "
                        f"Must be one of: {TradingMode.BACKTEST}, "
                        f"{TradingMode.PAPER}, {TradingMode.LIVE}")


def get_available_modes() -> list:
    """Get list of available trading modes."""
    return [TradingMode.BACKTEST, TradingMode.PAPER, TradingMode.LIVE]
