"""
Position sizing: fixed fractional risk model.
Size = (Balance × risk_pct) / (SL_distance × price_per_unit)
Respects max_position_usdt and leverage limits.
"""
import logging
from tabdeal_bot.config.settings import TradingConfig

logger = logging.getLogger(__name__)


class PositionSizer:
    def __init__(self, cfg: TradingConfig):
        self.cfg = cfg

    def calculate(
        self,
        balance_usdt: float,
        entry_price: float,
        sl_price: float,
        price_precision: int = 2,
        qty_precision: int = 3,
    ) -> float:
        """
        Returns the position quantity in base currency (e.g. BTC).
        Returns 0.0 if the trade should not be entered.
        """
        if balance_usdt <= 0:
            logger.warning("Zero or negative balance — cannot size position")
            return 0.0

        sl_distance = abs(entry_price - sl_price)
        if sl_distance <= 0:
            logger.warning("SL distance is zero — cannot size position")
            return 0.0

        # Dollar risk per trade
        risk_usdt = balance_usdt * self.cfg.risk_per_trade

        # With leverage, margin required = notional / leverage
        # risk_usdt = qty * sl_distance (unrealized loss at SL)
        qty = risk_usdt / sl_distance

        # Cap notional value
        max_qty_by_cap = (self.cfg.max_position_usdt * self.cfg.leverage) / entry_price
        qty = min(qty, max_qty_by_cap)

        # Round to exchange precision
        factor = 10 ** qty_precision
        qty = int(qty * factor) / factor  # floor

        total_fees = entry_price * qty * (self.cfg.taker_fee + self.cfg.slippage) * 2
        if total_fees >= risk_usdt * 0.5:
            logger.warning("Fees (%.4f USDT) eat >50%% of risk budget — skipping", total_fees)
            return 0.0

        logger.info(
            "Position size: %.4f (risk=%.2f USDT, sl_dist=%.4f, leverage=%dx)",
            qty, risk_usdt, sl_distance, self.cfg.leverage,
        )
        return qty
