"""BOOK DERIBIT-ONLY LIVE EXECUTE — TP01 + SKH01 NETTATI in software su un solo conto Deribit mainnet.

Porta il conto reale al target NETTO per asset (vedi src/live/book.py): per ogni asset combina la
frazione long-flat di TP01 (peso 0.75) e il segno L/S di SKH01 (peso 0.25), e manda UN ordine con
segno (long/short/flip) per raggiungerlo. Poi assicura un disaster-SL on-book sulla posizione NETTA.

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/book_executions.jsonl.

⚠️ CADENZA: SKH01 decide su griglia 230m -> questo script va lanciato ogni ~230 minuti con la feed
fresca all'ultima barra chiusa (NON il cron giornaliero, che mancherebbe gli ingressi). Gli exit di
SKH sono SOFTWARE (latenza fino a fine barra 230m); solo il disaster-SL (-30%) e' on-book.

  uv run python scripts/live/book_execute.py            # DRY-RUN (piano, nessun ordine)
  uv run python scripts/live/book_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.book import book_report
from src.live.execution import DeribitTrader
from src.live.notifier import notify

CONFIG = PROJECT_ROOT / "config" / "live.json"
LOG_DIR = PROJECT_ROOT / "data" / "live"
LOG = LOG_DIR / "book_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
    min_order = float(cfg["min_order_usd"])
    sl_pct = float(cfg["disaster_sl_pct"])

    r = book_report(live_feed=True)           # target NETTO + conto/posizioni reali (feed SKH fresco)
    equity = r["equity"]

    print("=" * 88)
    print("  BOOK DERIBIT LIVE EXECUTE — TP01(0.75)+SKH01(0.25) NETTATI — Deribit mainnet (USDC linear)")
    print("=" * 88)
    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 ${r['cap_per_asset']:.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("⚠️ BOOK 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, inst = a["asset"], a["instrument"]
        net, cur, mark = a["net_target"], a["position_usd"], a["mark"]
        sk = a["skh_state"]
        sk_txt = "flat" if sk == "flat" else f"{sk['dir']}@{sk.get('entry')}"
        order = a["order"]
        if order is None:
            act = "HOLD (a target)"
        elif order.get("is_close"):
            act = f"CLOSE ${cur:,.0f}"
        elif order.get("needs_flip"):
            act = f"FLIP -> ${net:,.0f}"
        else:
            act = f"{order['side'].upper()} ${order['delta']:+,.0f}"
        print(f"  {asset:<3} TP {a['tp_frac']:+.3f} · SKH {a['skh_sign']:+d}({sk_txt}) -> net ${net:+,.0f} "
              f"| pos ${cur:+,.0f} -> {act}")

        if do_execute and order is not None:
            fills = trader.rebalance_signed(inst, net, mark, min_usd=min_order)
            newpos = trader.position_usd(inst)
            for f in fills:
                print(f"      -> {f.side.upper()} {f.filled:.4f} @ ${f.price or 0:,.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, net_target=net, pos_after=newpos,
                               tp_frac=a["tp_frac"], skh_sign=a["skh_sign"]))
                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), net=round(net, 0), pos_after=round(newpos, 0))
                notify(f"✅ BOOK {act}" if f.verified else "⚠️ BOOK ORDINE NON VERIFICATO",
                       det if f.verified else {**det, "notes": f.notes})
            print(f"      reconcile: pos ${newpos:,.0f}")
        if do_execute:
            ds = trader.ensure_disaster_sl(inst, sl_pct)   # bracket su posizione NETTA (adatta long/short)
            print(f"      disaster-SL: {ds.get('state')}" + (f" @ ${ds['stop']:,.1f}" if ds.get("stop") else ""))
            if ds.get("state") == "placed":
                notify("🛡️ BOOK 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("⚠️ BOOK 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 netto del book.")
    else:
        print("  => Esecuzione completata (vedi data/live/book_executions.jsonl).")


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


if __name__ == "__main__":
    main()
