"""TP01 LIVE EXECUTE — loop di esecuzione GATED su Deribit mainnet (USDC linear).

Porta il conto reale al target di TP01 (causale, dati certificati): per ogni asset calcola il notional
bersaglio = min(0.5 * frazione * equity, max_notional), e apre/riduce/chiude per raggiungerlo.

DOPPIO GATE DI SICUREZZA (entrambi necessari per inviare ordini reali):
  1. config/live.json -> "execution_enabled": true   (master switch, default false)
  2. flag CLI --execute
Senza entrambi e' un DRY-RUN (stampa il piano, NON invia). Reconciliation dopo ogni ordine; log in
data/live/executions.jsonl. TP01 oggi e' FLAT -> target 0 -> nessuna azione finche' il segnale non gira.

  uv run python scripts/live/live_execute.py            # DRY-RUN (piano, nessun ordine)
  uv run python scripts/live/live_execute.py --execute   # esegue SOLO se execution_enabled=true
"""
from __future__ import annotations

import json
import sys
from pathlib import Path

import pandas as pd

PROJECT_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT_ROOT))

from src.live.deribit import INSTRUMENT
from src.live.execution import DeribitTrader
from src.live.notifier import notify
from src.live.shadow import ASSETS, WEIGHT, shadow_report

CONFIG = PROJECT_ROOT / "config" / "live.json"
LOG_DIR = PROJECT_ROOT / "data" / "live"
LOG = LOG_DIR / "executions.jsonl"


def load_config() -> dict:
    cfg = json.loads(CONFIG.read_text()) if CONFIG.exists() else {}
    cfg.setdefault("execution_enabled", False)
    cfg.setdefault("max_notional_per_asset_usd", 300.0)
    cfg.setdefault("min_order_usd", 5.0)
    cfg.setdefault("disaster_sl_pct", 0.30)
    return cfg


def log_event(rec: dict):
    LOG_DIR.mkdir(parents=True, exist_ok=True)
    with open(LOG, "a") as f:
        f.write(json.dumps(rec) + "\n")


def _run():
    cfg = load_config()
    want_execute = "--execute" in sys.argv[1:]
    enabled = bool(cfg["execution_enabled"])
    do_execute = want_execute and enabled
    max_notional = float(cfg["max_notional_per_asset_usd"])
    min_order = float(cfg["min_order_usd"])
    sl_pct = float(cfg["disaster_sl_pct"])

    r = shadow_report()                       # targets causali + conto/posizioni reali (online)
    equity = r["equity"]

    print("=" * 84)
    print("  TP01 LIVE EXECUTE — Deribit mainnet (USDC linear)")
    print("=" * 84)
    mode = ("ESECUZIONE REALE" if do_execute else
            ("ARMATO ma manca --execute" if enabled else "DRY-RUN (execution_enabled=false)"))
    print(f"  modo            : {mode}")
    print(f"  gate            : execution_enabled={enabled} | --execute={want_execute}")
    print(f"  conto reale     : ${r['real_equity']:,.2f}" if r["real_equity"] else f"  conto: {r['eq_basis']}")
    print(f"  sizing base     : ${equity:,.2f} | cap/asset ${max_notional:.0f} | min ${min_order:.0f} | disaster-SL -{sl_pct*100:.0f}%")
    print(f"  ultima barra    : {r['last_data']}\n")

    if not r["online"]:
        print("  conto non leggibile (offline) -> stop, non eseguo a cieco.")
        if do_execute:
            notify("⚠️ TP01 LIVE — conto offline", {"nota": "salto l'esecuzione, non opero a cieco"})
        return

    trader = DeribitTrader() if do_execute else None
    actions = []
    for a in r["assets"]:
        asset = a["asset"]; frac = a["target"]; mark = a["mark"]; cur = a["position_usd"]
        tgt = min(WEIGHT * frac * equity, max_notional) if frac > 0 else 0.0
        delta = tgt - cur
        if abs(delta) < min_order:
            act = "HOLD (a target)"
        elif tgt < 1.0 and cur > 1.0:
            act = f"CLOSE ${cur:,.0f}"
        elif delta > 0:
            act = f"BUY ${delta:,.0f}"
        else:
            act = f"REDUCE ${-delta:,.0f}"
        print(f"  {asset:<3} target {frac:+.3f}x -> ${tgt:,.0f} | pos ${cur:,.0f} | delta ${delta:+,.0f} -> {act}")

        if do_execute:
            if not act.startswith("HOLD"):
                fills = trader.rebalance_to(INSTRUMENT[asset], tgt, mark, min_usd=min_order)
                newpos = trader.position_usd(INSTRUMENT[asset])
                for f in fills:
                    print(f"      -> {f.side.upper()} {f.filled:.4f} @ ${f.price:,.1f} fee {f.fee_usdc:.5f} "
                          f"({'OK' if f.verified else 'NON VERIFICATO: ' + f.notes})")
                    log_event(dict(ts_utc=str(pd.Timestamp(r['last_data'])), asset=asset, action=act,
                                   side=f.side, filled=f.filled, price=f.price, fee=f.fee_usdc,
                                   verified=f.verified, notes=f.notes, pos_after=newpos))
                    det = dict(asset=asset, side=f.side, amount=round(f.filled, 4),
                               price=round(f.price or 0, 1), fee=round(f.fee_usdc, 5), pos_after=round(newpos, 0))
                    if f.verified:
                        notify(f"✅ TP01 {act}", det)
                    else:
                        notify("⚠️ TP01 ORDINE NON VERIFICATO", {**det, "notes": f.notes})
                print(f"      reconcile: pos ${newpos:,.0f}")
            ds = trader.ensure_disaster_sl(INSTRUMENT[asset], sl_pct)   # bracket: piazza se long, pulisce se flat
            print(f"      disaster-SL: {ds.get('state')}" + (f" @ ${ds['stop']:,.1f}" if ds.get("stop") else ""))
            if ds.get("state") == "placed":
                notify("🛡️ TP01 disaster-SL piazzato", {"asset": asset, "stop": round(ds.get("stop") or 0, 1),
                                                          "amount": round(ds.get("amount") or 0, 4)})
            elif ds.get("state") == "place-failed":
                notify("⚠️ TP01 disaster-SL FALLITO", {"asset": asset, "notes": ds.get("notes")})
        actions.append(act)

    print()
    if not do_execute:
        print("  => DRY-RUN: nessun ordine inviato." +
              ("" if enabled else " Per armare: config/live.json execution_enabled=true + --execute."))
    elif all(x.startswith("HOLD") for x in actions):
        print("  => Nessuna azione: conto gia' al target di TP01 (oggi flat).")
    else:
        print("  => Esecuzione completata (vedi data/live/executions.jsonl).")


def main():
    try:
        _run()
    except Exception as e:
        notify("🛑 TP01 LIVE — ERRORE", {"error": f"{type(e).__name__}: {e}"})
        raise


if __name__ == "__main__":
    main()
