"""
simulate_signals_today.py — Simulation de l'impact des signaux macro sur les trades du jour

Récupère les funding rates + taker ratios ACTUELS comme proxy des valeurs au moment des trades.
Montre : score signal au moment hypothétique de chaque trade + ce qui aurait changé.

Usage: python3 simulate_signals_today.py
"""

import json
import os
import sys
import requests
from datetime import datetime, timezone

SCRIPT_DIR   = os.path.dirname(os.path.abspath(__file__))
FAPI         = "https://fapi.binance.com"
CACHE_FILE   = os.path.join(SCRIPT_DIR, "signal_cache.json")
HISTORY_FILE = os.path.join(SCRIPT_DIR, "espion_history.json")

# Seuils identiques à signal_aggregator.py
FUNDING_BULL  = 0.01
FUNDING_BEAR  = -0.005
NETFLOW_HIGH  = 500_000
NETFLOW_MED   = 100_000
NETFLOW_WARN  = -200_000


def usdt_sym(sym):
    if sym.endswith("USDC"):
        return sym[:-4] + "USDT"
    return sym


def get(url, params=None):
    try:
        r = requests.get(url, params=params, timeout=8)
        r.raise_for_status()
        return r.json()
    except Exception:
        return None


def fetch_funding(sym):
    """Retourne (funding_pct, has_perp)."""
    fsym = usdt_sym(sym)
    d = get(f"{FAPI}/fapi/v1/premiumIndex", {"symbol": fsym})
    if d and "lastFundingRate" in d:
        return float(d["lastFundingRate"]) * 100, True
    return None, False


def fetch_taker_ratio(sym):
    """Retourne (net_flow_usd, buy_ratio, has_data)."""
    fsym = usdt_sym(sym)
    # Taker ratio 15min (4 dernières barres = 1h)
    data = get(f"{FAPI}/futures/data/takerlongshortRatio", {"symbol": fsym, "period": "15m", "limit": 4})
    price_d = get(f"{FAPI}/fapi/v1/ticker/price", {"symbol": fsym})
    if not data or not isinstance(data, list) or not price_d:
        return 0, 0.5, False
    price = float(price_d["price"])
    buy_vol, sell_vol = 0.0, 0.0
    for bar in data:
        buy_vol  += float(bar.get("buyVol",  0)) * price
        sell_vol += float(bar.get("sellVol", 0)) * price
    total = buy_vol + sell_vol
    if total == 0:
        return 0, 0.5, False
    return buy_vol - sell_vol, buy_vol / total, True


def funding_score(avg_funding):
    if avg_funding >= FUNDING_BULL:
        return 2.0
    elif avg_funding <= FUNDING_BEAR:
        return 8.0
    t = (avg_funding - FUNDING_BEAR) / (FUNDING_BULL - FUNDING_BEAR)
    return round(8.0 - 6.0 * t, 2)


def netflow_score(net_flow, buy_ratio):
    if net_flow >= NETFLOW_HIGH:
        s = 9.0
    elif net_flow >= NETFLOW_MED:
        s = 7.0
    elif net_flow >= 0:
        s = 5.5
    elif net_flow >= NETFLOW_WARN:
        s = 3.5
    else:
        s = 1.5
    if buy_ratio >= 0.60:
        s = min(10, s + 1.0)
    elif buy_ratio <= 0.40:
        s = max(0, s - 1.0)
    return round(s, 2)


def size_mod_from_score(total):
    if total >= 14:
        return 1.0
    elif total >= 10:
        return 0.85
    elif total >= 7:
        return 0.70
    else:
        return 0.50


def would_veto(total):
    """En observation mode, jamais de veto réel — mais on note si ça l'aurait été."""
    return total < 5


# ── Chargement des trades du jour ────────────────────────────────────────────

def load_today_trades():
    with open(HISTORY_FILE) as f:
        data = json.load(f)
    today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
    return [t for t in data if today in t.get("entry_time", "")]


# ── Récupération des signaux par coin ────────────────────────────────────────

def fetch_signals_per_coin(symbols):
    """Retourne un dict {sym: {funding_pct, net_flow, buy_ratio, has_perp}}."""
    results = {}
    unique = list(set(symbols))
    for sym in unique:
        print(f"  Fetching {usdt_sym(sym)}...", end=" ", flush=True)
        funding, has_perp = fetch_funding(sym)
        net_flow, buy_ratio, has_taker = fetch_taker_ratio(sym)
        results[sym] = {
            "funding_pct": funding,
            "net_flow": net_flow,
            "buy_ratio": buy_ratio,
            "has_perp": has_perp,
            "has_taker": has_taker,
        }
        status = "✅" if has_perp else "❌ no perp"
        print(f"{status} funding={funding:+.5f}% netflow={net_flow:+.0f}$" if has_perp else status)
    return results


# ── Calcul score global (agrégé sur tous les coins actifs) ───────────────────

def compute_global_score(signals: dict) -> tuple:
    """Retourne (funding_score_avg, netflow_score_avg, total_score, interp)."""
    fundings, netflows = [], []
    for sym, s in signals.items():
        if not s["has_perp"]:
            continue
        f = s["funding_pct"]
        fs = funding_score(f)
        ns = netflow_score(s["net_flow"], s["buy_ratio"])
        fundings.append(fs)
        netflows.append(ns)

    if not fundings:
        return 5.0, 5.0, 10.0, "NEUTRAL"

    avg_f = sum(fundings) / len(fundings)
    avg_n = sum(netflows) / len(netflows)
    total = avg_f + avg_n  # 0-20

    if total >= 15:
        interp = "BULLISH_STRONG"
    elif total >= 12:
        interp = "BULLISH"
    elif total >= 9:
        interp = "NEUTRAL"
    elif total >= 6:
        interp = "BEARISH"
    else:
        interp = "BEARISH_STRONG"

    return round(avg_f, 2), round(avg_n, 2), round(total, 2), interp


# ── Rapport principal ─────────────────────────────────────────────────────────

def main():
    print("=" * 70)
    print("  SIMULATION IMPACT SIGNAUX MACRO — " + datetime.now().strftime("%Y-%m-%d"))
    print("=" * 70)
    print()

    trades = load_today_trades()
    if not trades:
        print("Aucun trade trouvé aujourd'hui.")
        return

    print(f"📋 {len(trades)} trades trouvés aujourd'hui\n")

    # Récupération signaux par coin unique
    symbols = list(set(t["symbol"] for t in trades))
    print(f"📡 Récupération des signaux pour {len(symbols)} coins...")
    per_coin = fetch_signals_per_coin(symbols)

    # Score global
    fs, ns, total, interp = compute_global_score(per_coin)
    mod = size_mod_from_score(total)
    veto = would_veto(total)

    print()
    print("─" * 70)
    print(f"  SCORE GLOBAL ACTUEL : {total:.1f}/20 ({interp})")
    print(f"  Composantes : funding_score={fs:.2f}/10  netflow_score={ns:.2f}/10")
    print(f"  Size modulator : ×{mod:.2f}  |  Veto (si activé) : {'OUI ⚠️' if veto else 'NON'}")
    print("─" * 70)
    print()

    # ── Tableau des trades ────────────────────────────────────────────────────
    print(f"{'#':>2} {'Heure':>5} {'Symbole':>15} {'PnL':>7} {'Max':>6} {'Exit':>22}  {'Signal/Perp':>12}  {'Impact hypothétique'}")
    print("─" * 110)

    total_real_pnl  = 0.0
    total_hypo_pnl  = 0.0
    trades_impacted = []

    for i, t in enumerate(trades, 1):
        sym      = t["symbol"]
        pnl      = t["pnl_pct"]
        max_pnl  = t["max_pnl"]
        reason   = t.get("exit_reason", "?")[:22]
        entry_ts = t.get("entry_time", "")[:19].split("T")[1][:5]

        total_real_pnl += pnl

        sig = per_coin.get(sym, {})
        has_perp = sig.get("has_perp", False)

        if not has_perp:
            perp_tag = "❌ no perp"
            coin_fund = None
            coin_fs   = 5.0
            coin_ns   = 5.0
            coin_total= 10.0
        else:
            coin_fund = sig["funding_pct"]
            coin_fs   = funding_score(coin_fund)
            coin_ns   = netflow_score(sig["net_flow"], sig["buy_ratio"])
            coin_total= coin_fs + coin_ns
            perp_tag  = f"{coin_total:.1f}/20"

        # Calcul impact hypothétique
        coin_mod  = size_mod_from_score(coin_total) if has_perp else 1.0
        coin_veto = would_veto(coin_total) if has_perp else False

        # Impact sur le PnL (modulation de taille × PnL)
        hypo_pnl = pnl * coin_mod  # Les pertes et gains sont réduits proportionnellement

        impact_str = ""
        if coin_veto and pnl < 0:
            impact_str = f"VETO → {pnl:+.3f}% évité"
            hypo_pnl   = 0.0  # Trade évité
        elif coin_veto:
            impact_str = f"VETO (gain manqué {pnl:+.3f}%)"
            hypo_pnl   = 0.0
        elif coin_mod < 1.0:
            delta = (pnl * coin_mod) - pnl
            impact_str = f"×{coin_mod:.2f} → {hypo_pnl:+.3f}% (Δ{delta:+.3f}%)"
        else:
            impact_str = f"×1.00 → identique"

        total_hypo_pnl += hypo_pnl

        if coin_mod < 0.99 or coin_veto:
            trades_impacted.append({
                "sym": sym, "pnl": pnl, "hypo": hypo_pnl,
                "mod": coin_mod, "veto": coin_veto, "fund": coin_fund,
                "score": coin_total if has_perp else None
            })

        pnl_color = "+" if pnl >= 0 else ""
        print(
            f"{i:>2} {entry_ts:>5} {sym:>15} {pnl_color}{pnl:>6.3f}% "
            f"{max_pnl:>6.3f}% {reason:>22}  {perp_tag:>12}  {impact_str}"
        )

    print("─" * 110)
    delta = total_hypo_pnl - total_real_pnl
    print(f"{'':>2} {'':>5} {'TOTAL':>15} {total_real_pnl:>+7.3f}%                                                  "
          f"{'':>12}  HYPO: {total_hypo_pnl:+.3f}% (Δ{delta:+.3f}%)")
    print()

    # ── Résumé par coin (funding + netflow) ──────────────────────────────────
    print("─" * 70)
    print("  DÉTAIL PAR COIN (signaux actuels)")
    print("─" * 70)
    print(f"{'Coin':>15} {'Perp':>5} {'Funding%':>10} {'NetFlow$':>12} {'Ratio':>7} {'FScore':>7} {'NScore':>7} {'Total':>7}")
    for sym in sorted(per_coin.keys()):
        s = per_coin[sym]
        if not s["has_perp"]:
            print(f"{sym:>15} {'❌':>5}")
            continue
        fs2 = funding_score(s["funding_pct"])
        ns2 = netflow_score(s["net_flow"], s["buy_ratio"])
        tot = fs2 + ns2
        flag = " ⚠️" if would_veto(tot) else ""
        print(f"{sym:>15} {'✅':>5} {s['funding_pct']:>+10.5f}% {s['net_flow']:>+12.0f} "
              f"{s['buy_ratio']:>7.4f} {fs2:>7.2f} {ns2:>7.2f} {tot:>7.2f}{flag}")

    print()
    print("─" * 70)
    print("  CONCLUSION")
    print("─" * 70)
    print(f"  Score global aujourd'hui : {total:.1f}/20 ({interp})")
    print(f"  PnL réel    : {total_real_pnl:+.3f}%")
    print(f"  PnL hypothétique (avec signaux) : {total_hypo_pnl:+.3f}%")
    print(f"  Delta       : {delta:+.3f}%")
    print()

    if not trades_impacted:
        print("  ✅ Aucun trade n'aurait été modifié avec ces signaux (score global neutre)")
    else:
        print(f"  {len(trades_impacted)} trade(s) auraient été impactés :")
        for t2 in trades_impacted:
            action = "VETO" if t2["veto"] else f"×{t2['mod']:.2f}"
            print(f"    {t2['sym']:>15}  pnl_réel={t2['pnl']:+.3f}%  "
                  f"pnl_hypo={t2['hypo']:+.3f}%  action={action}  "
                  f"score={t2['score']:.1f}/20 ({t2['fund']:+.5f}% funding)")
    print()

    # ── Vérifier si le cache live est disponible ──────────────────────────────
    if os.path.exists(CACHE_FILE):
        try:
            with open(CACHE_FILE) as f:
                cache = json.load(f)
            ts = cache.get("timestamp", "?")[:19]
            sc = cache.get("score_total", "?")
            print(f"  📦 Cache live disponible (maj {ts}) — score={sc}/20")
        except Exception:
            pass
    else:
        print("  ℹ️  Pas de cache live (signal_aggregator.py non démarré)")
    print()


if __name__ == "__main__":
    main()
