"""
charter_core/conversions.py
Mavis 2026-07-20 — Helper di conversione PnL% Charter.

REGOLA FONDAMENTALE (imparata 20/07/2026 da emergenza AERO):
- Bybit API `unrealisedPnl / nozionale` = % sul PREZZO
- Charter P006/P007/P005, trigger trailing, BE, partial close = % sul MARGINE
- Conversione: % MARGINE = % PREZZO × leva

QUESTO MODULO E' LA SINGLE SOURCE OF TRUTH per la conversione.
Tutti gli altri file (charter_engine, charter_config, sltp_engine, webhook_receiver,
trailing_stop_watchdog, bybit_demo_client) DEVONO importare da qui.
NON ricalcolare la conversione inline.
"""
from typing import Union

Number = Union[int, float]


def pct_margin_to_price(pct_margin: Number, leverage: Number, side: str = "Buy") -> float:
    """
    Converte una % sul MARGINE (Charter) nel corrispondente moltiplicatore sul PREZZO.

    Charter: P006 SL -3% MARGINE → con leva 3x → -1% PREZZO
    Charter: trailing +1% MARGINE → con leva 3x → +0.33% PREZZO

    Args:
        pct_margin: % sul margine (es. -3.0 per -3% Charter)
        leverage: leva della posizione (es. 3.0)
        side: "Buy" (long) o "Sell" (short). Per short, % negativa è in realta' gain.

    Returns:
        float: % sul prezzo (es. -1.0 per -3% margin con leva 3x)
    """
    if leverage <= 0:
        raise ValueError(f"leverage deve essere > 0, ricevuto {leverage}")
    return pct_margin / leverage


def pct_price_to_margin(pct_price: Number, leverage: Number) -> float:
    """
    Converte una % sul PREZZO (Bybit) nella corrispondente % sul MARGINE.

    Bybit unrealisedPnl → PnL% PREZZO → con leva 3x → PnL% MARGINE
    Esempio: BTC +1.06% PREZZO con leva 3x = +3.18% MARGINE

    Args:
        pct_price: % sul prezzo (es. +1.06)
        leverage: leva della posizione (es. 3.0)

    Returns:
        float: % sul margine
    """
    if leverage <= 0:
        raise ValueError(f"leverage deve essere > 0, ricevuto {leverage}")
    return pct_price * leverage


def price_change_to_margin(entry: Number, current: Number, leverage: Number, side: str = "Buy") -> float:
    """
    Calcola direttamente la % MARGINE data entry/current price.

    Args:
        entry: prezzo di entry
        current: prezzo corrente (mark)
        leverage: leva della posizione
        side: "Buy" o "Sell"

    Returns:
        float: % sul margine (signed: positivo = profit, negativo = loss)
    """
    if entry <= 0:
        raise ValueError(f"entry deve essere > 0, ricevuto {entry}")
    if side == "Buy":
        pct_price = (current - entry) / entry * 100.0
    elif side == "Sell":
        pct_price = (entry - current) / entry * 100.0
    else:
        raise ValueError(f"side deve essere Buy o Sell, ricevuto {side!r}")
    return pct_price_to_margin(pct_price, leverage)


def sl_price_from_margin_pct(entry: Number, pct_margin: Number, leverage: Number, side: str = "Buy") -> float:
    """
    Calcola il prezzo di SL data la % Charter sul MARGINE.

    Charter: P006 SL -3% MARGINE, entry 100, leva 3x → SL = 100 * (1 + (-3/3)/100) = 99.0

    Args:
        entry: prezzo di entry
        pct_margin: % Charter sul margine (negativa per SL, positiva per TP)
        leverage: leva della posizione
        side: "Buy" o "Sell"

    Returns:
        float: prezzo assoluto dello SL/TP
    """
    pct_price = pct_margin_to_price(pct_margin, leverage, side)
    return entry * (1.0 + pct_price / 100.0)


def trail_pct_for_bybit(trail_pct_margin: Number, leverage: Number) -> float:
    """
    Converte la % trailing Charter (MARGINE) nel parametro trailingStop Bybit (PREZZO).

    Bybit trailingStop = percentuale sul PREZZO del symbol.

    Args:
        trail_pct_margin: % trailing Charter sul margine (es. 0.5)
        leverage: leva della posizione

    Returns:
        float: trailingStop da passare a Bybit (in % prezzo)
    """
    return pct_margin_to_price(trail_pct_margin, leverage)


def format_pct_both(pct_margin: Number, leverage: Number) -> str:
    """
    Formatta una % Charter in forma 'X% margin (Y% price @ Lx)'.

    Esempio: format_pct_both(-3.0, 3.0) → "-3.00% margin (-1.00% price @ 3x)"

    Args:
        pct_margin: % Charter sul margine
        leverage: leva della posizione

    Returns:
        str: stringa formattata
    """
    pct_price = pct_margin_to_price(pct_margin, leverage)
    return f"{pct_margin:+.2f}% margin ({pct_price:+.2f}% price @ {leverage:.0f}x)"
