from fxhnt.application.allocation_engine import inverse_vol_weights


def test_inverse_vol_weights_favour_low_vol_and_sum_to_one():
    rbs = {"lo": {"1": 0.001, "2": -0.001, "3": 0.001},
           "hi": {"1": 0.10,  "2": -0.10,  "3": 0.10}}
    w = inverse_vol_weights(rbs)
    assert abs(sum(w.values()) - 1.0) < 1e-9 and w["lo"] > w["hi"]


def test_inverse_vol_weights_all_degenerate_falls_back_to_equal():
    rbs = {"a": {"1": 0.0, "2": 0.0}, "b": {"1": 0.0, "2": 0.0}}
    w = inverse_vol_weights(rbs)
    assert abs(w["a"] - 0.5) < 1e-9 and abs(w["b"] - 0.5) < 1e-9


def test_compute_allocation_uses_inverse_vol_base_capped():
    from fxhnt.application.allocation_engine import compute_allocation
    from fxhnt.application.allocation_policy import AllocationPolicy
    n = 400
    rbs = {"lo": {str(i): (0.002 if i % 2 else -0.002) for i in range(n)},
           "hi": {str(i): (0.05 if i % 2 else -0.05) for i in range(n)}}
    pol = AllocationPolicy(marginal_gate=False, min_history_days=60, max_strategy_weight=0.9)
    w = compute_allocation(rbs, pol)
    assert w["lo"] > w["hi"]           # low-vol gets MORE (was equal under the old code)


def test_target_capital_caps_at_per_strategy_capacity():
    from fxhnt.application.allocation_engine import target_capital
    from fxhnt.application.allocation_policy import AllocationPolicy
    pol = AllocationPolicy(capital_ceiling=1_000_000.0)
    d = target_capital({"cap_limited": 0.5, "robust": 0.5}, equity=1_000_000.0, policy=pol,
                       capacity_ceiling={"cap_limited": 100_000.0})
    assert d["cap_limited"] <= 100_000.0 and d["robust"] > d["cap_limited"]


def test_target_capital_none_ceiling_unchanged():
    from fxhnt.application.allocation_engine import target_capital
    from fxhnt.application.allocation_policy import AllocationPolicy
    pol = AllocationPolicy(capital_ceiling=1_000_000.0)
    a = target_capital({"x": 0.5}, 1_000_000.0, pol)
    b = target_capital({"x": 0.5}, 1_000_000.0, pol, capacity_ceiling=None)
    assert a == b


def test_target_capital_caps_short_magnitude_sign_preserved():
    from fxhnt.application.allocation_engine import target_capital
    from fxhnt.application.allocation_policy import AllocationPolicy
    pol = AllocationPolicy(capital_ceiling=1_000_000.0)
    d = target_capital({"s": -0.5}, equity=1_000_000.0, policy=pol,
                       capacity_ceiling={"s": 100_000.0})
    assert d["s"] == -100_000.0   # short: -min(|d|, ceiling), sign preserved


def test_capacity_ceiling_is_last_aum_above_min_sharpe():
    from fxhnt.application.allocation_engine import capacity_ceiling_from_curve

    curve = {35_000: 3.5, 100_000: 2.5, 350_000: 0.3, 1_000_000: -2.5}   # xsfunding-shaped
    assert capacity_ceiling_from_curve(curve, 1.0) == 100_000            # last AUM with Sh >= 1.0
    robust = {35_000: 2.9, 1_000_000: 2.6, 10_000_000: 1.6}
    assert capacity_ceiling_from_curve(robust, 1.0) == 10_000_000        # never drops -> top of range
    # unviable at EVERY tested AUM -> ZERO capacity (0.0), NOT None: unviable-everywhere is the OPPOSITE of
    # unbounded, so target_capital caps its dollars to $0. Only an EMPTY curve is None (no info -> unbounded).
    assert capacity_ceiling_from_curve({35_000: 0.2}, 1.0) == 0.0        # unviable even at smallest -> $0
    assert capacity_ceiling_from_curve({35_000: 0.2, 100_000: -1.0}, 1.0) == 0.0
    assert capacity_ceiling_from_curve({}, 1.0) is None                 # empty -> unbounded sentinel


def test_target_capital_zero_ceiling_caps_to_zero():
    from fxhnt.application.allocation_engine import capacity_ceiling_from_curve, target_capital
    from fxhnt.application.allocation_policy import AllocationPolicy
    pol = AllocationPolicy(capital_ceiling=1_000_000.0)
    # a strategy unviable at every AUM -> 0.0 ceiling -> its dollars are capped to $0 (min(|d|, 0) == 0),
    # while a None-ceiling strategy is uncapped. Proves the sentinel fix end-to-end through target_capital.
    zero = capacity_ceiling_from_curve({35_000: 0.2}, 1.0)
    assert zero == 0.0
    d = target_capital({"dead": 0.5, "live": 0.5}, equity=1_000_000.0, policy=pol,
                       capacity_ceiling={"dead": zero})
    assert d["dead"] == 0.0 and d["live"] > 0.0
