"""Position management rules (audit Phase 7: centralized, non-bypassable).

Applied on every mark-to-market pass for open paper trades:
1. Breakeven trail — at +1R unrealized, the stop moves to entry. A winner
   can no longer turn into a full loser.
2. Scale-out — at +1.5R, half the position is banked at market; the rest
   runs toward target 2 with the breakeven stop.
3. Time stop — trades older than MAX_HOLD_DAYS close at market. Swing setups
   that go nowhere are dead capital and unbudgeted risk.

All thresholds are env-tunable. R is always measured from the ORIGINAL stop
(initial_stop) so trailing never distorts the math.
"""
import os
from datetime import datetime


def _f(name: str, default: float) -> float:
    try:
        return float(os.getenv(name, default))
    except (TypeError, ValueError):
        return default


def enabled() -> bool:
    return os.getenv("POSITION_MGMT_ENABLED", "true").lower() == "true"


def evaluate(trade, price: float, now: datetime) -> dict:
    """Pure decision function — returns actions, mutates nothing.

    Returns: {"new_stop": float|None, "scale_out_qty": int, "time_exit": bool,
              "r_multiple": float, "notes": [str]}
    """
    actions = {"new_stop": None, "scale_out_qty": 0, "time_exit": False,
               "r_multiple": 0.0, "notes": []}
    if not enabled():
        return actions

    long = trade.direction in ("CALL", "BUY")
    sign = 1 if long else -1
    initial_stop = trade.initial_stop if trade.initial_stop is not None else trade.stop_loss
    risk = abs(trade.entry_price - initial_stop)
    if risk <= 0:
        return actions

    r_mult = (price - trade.entry_price) * sign / risk
    actions["r_multiple"] = round(r_mult, 2)

    trail_trigger = _f("TRAIL_TRIGGER_R", 1.0)
    scale_trigger = _f("SCALE_OUT_R", 1.5)
    max_hold_days = int(_f("MAX_HOLD_DAYS", 10))

    # 1. Time stop
    held_days = (now - trade.opened_at).days
    if held_days >= max_hold_days:
        actions["time_exit"] = True
        actions["notes"].append(f"Time stop: held {held_days}d ≥ {max_hold_days}d limit")
        return actions

    # 2. Breakeven trail
    at_breakeven = (trade.stop_loss >= trade.entry_price) if long else (trade.stop_loss <= trade.entry_price)
    if r_mult >= trail_trigger and not at_breakeven:
        actions["new_stop"] = trade.entry_price
        actions["notes"].append(f"+{r_mult:.1f}R — stop trailed to breakeven")

    # 3. Scale out half
    if r_mult >= scale_trigger and not trade.scaled_out and trade.quantity >= 2:
        actions["scale_out_qty"] = trade.quantity // 2
        actions["notes"].append(
            f"+{r_mult:.1f}R — scaling out {trade.quantity // 2} of {trade.quantity}"
        )
    return actions
