"""
weekly_diagnostic.py — V2 (Mattia 04/08/2026)
==============================================
Report diagnostico settimanale per live_deploy_v2.
Da schedulare via cron ogni domenica alle 23:00 Europe/Rome.

Uso:
    python3 weekly_diagnostic.py [--days N] [--out FILE]

Produce un report HTML con:
- Trade chiusi nel periodo (da Operations Bybit)
- Metriche: WR, PF, net PnL, max DD
- Breakdown per strategia / asset / lato
- Confronto vs settimana precedente
"""
import argparse
import json
import os
import sys
from datetime import datetime, timezone, timedelta
from pathlib import Path

import requests

sys.path.insert(0, str(Path(__file__).parent))
from bybit_demo_client import BybitDemoClient

LOG_DIR = Path("/opt/charter-live/live_deploy_v2/logs")
LOG_DIR.mkdir(parents=True, exist_ok=True)


def fetch_closed_pnl(client, days):
    """Scarica trade chiusi ultimi N giorni da Bybit Operations endpoint."""
    end_ms = int(datetime.now(timezone.utc).timestamp() * 1000)
    start_ms = int((datetime.now(timezone.utc) - timedelta(days=days)).timestamp() * 1000)
    all_trades = []
    cursor = None
    while True:
        params = {
            "category": "linear",
            "limit": 100,
            "startTime": start_ms,
            "endTime": end_ms,
        }
        if cursor:
            params["cursor"] = cursor
        try:
            d = client._request("GET", "/v5/position/closed-pnl", params, signed=True)
        except Exception as e:
            print(f"fetch_closed_pnl err: {e}")
            return all_trades
        items = d.get("result", {}).get("list", [])
        all_trades.extend(items)
        cursor = d.get("result", {}).get("nextPageCursor")
        if not cursor or len(items) < 100:
            break
    return all_trades


def compute_metrics(trades):
    """Calcola metriche base da lista di trade (closed pnl) o da lista di float (pnls gia' estratti)."""
    if not trades:
        return {"n": 0, "wr": 0, "net": 0, "pf": 0, "max_dd": 0}
    # accetta sia lista di dict {closedPnl: X} che lista di float (gia' estratti)
    if all(isinstance(t, (int, float)) for t in trades):
        pnls = [float(t) for t in trades]
    else:
        pnls = [float(t.get("closedPnl", 0)) for t in trades if isinstance(t, dict)]
    if not pnls:
        return {"n": 0, "wr": 0, "net": 0, "pf": 0, "max_dd": 0}
    n = len(pnls)
    wins = [p for p in pnls if p > 0]
    losses = [p for p in pnls if p <= 0]
    cum = 0
    peak = 0
    max_dd = 0
    for p in pnls:
        cum += p
        if cum > peak:
            peak = cum
        dd = peak - cum
        if dd > max_dd:
            max_dd = dd
    sum_wins = sum(wins)
    sum_losses = abs(sum(losses))
    return {
        "n": n,
        "wr": 100 * len(wins) / n if n else 0,
        "net": sum(pnls),
        "gross_wins": sum_wins,
        "gross_losses": sum_losses,
        "pf": sum_wins / sum_losses if sum_losses else None,
        "avg_win": sum_wins / len(wins) if wins else 0,
        "avg_loss": -sum_losses / len(losses) if losses else 0,
        "max_dd": max_dd,
        "best": max(pnls) if pnls else 0,
        "worst": min(pnls) if pnls else 0,
    }


def by_breakdown(trades, key):
    """Raggruppa per chiave (es. 'symbol', 'side')."""
    out = {}
    for t in trades:
        if not isinstance(t, dict):
            continue  # skip non-dict (es. error response)
        k = t.get(key, "?")
        if k is None:
            k = "?"
        out.setdefault(k, []).append(float(t.get("closedPnl", 0)))
    return {k: compute_metrics(v) for k, v in out.items()}


def render_html(metrics_cur, metrics_prev, by_symbol, by_side, days):
    net_cur = metrics_cur["net"]
    net_prev = metrics_prev["net"]
    delta = net_cur - net_prev
    color = "#16a34a" if delta >= 0 else "#dc2626"

    sym_rows = "".join(
        f"<tr><td>{k}</td><td>{v['n']}</td><td>{v['wr']:.1f}%</td>"
        f"<td style='color:{(v['net']>=0 and '#16a34a') or '#dc2626'}'>{v['net']:+.2f}</td>"
        f"<td>{v.get('pf') or 0:.2f}</td><td>{v['avg_win']:+.2f}</td>"
        f"<td>{v['avg_loss']:+.2f}</td></tr>"
        for k, v in sorted(by_symbol.items(), key=lambda kv: -kv[1]["net"])
    )
    side_rows = "".join(
        f"<tr><td>{k}</td><td>{v['n']}</td><td>{v['wr']:.1f}%</td>"
        f"<td style='color:{(v['net']>=0 and '#16a34a') or '#dc2626'}'>{v['net']:+.2f}</td>"
        f"<td>{v.get('pf') or 0:.2f}</td></tr>"
        for k, v in sorted(by_side.items(), key=lambda kv: -kv[1]["net"])
    )
    return f"""<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Weekly Diagnostic V2</title>
<style>
body{{font-family:system-ui;background:#0f172a;color:#e2e8f0;padding:24px;max-width:1100px;margin:0 auto;}}
h1{{color:#f1f5f9;}}
h2{{color:#f1f5f9;border-left:4px solid #3b82f6;padding-left:12px;}}
.kpi{{background:#1e293b;padding:16px;border-radius:6px;display:inline-block;margin:6px;}}
.kpi-l{{font-size:12px;color:#94a3b8;}}
.kpi-v{{font-size:24px;font-weight:700;}}
table{{width:100%;border-collapse:collapse;background:#1e293b;border-radius:6px;margin:12px 0;}}
th,td{{padding:8px 12px;text-align:left;border-bottom:1px solid #334155;font-size:14px;}}
th{{background:#334155;}}
.ok{{background:#14532d;padding:12px;border-radius:4px;}}
.warn{{background:#7c2d12;padding:12px;border-radius:4px;}}
</style></head><body>
<h1>📊 Weekly Diagnostic V2 — ultimi {days}gg</h1>
<p style="color:#94a3b8">Generato: {datetime.now().strftime('%Y-%m-%d %H:%M')}</p>

<div class="kpi"><div class="kpi-l">Net PnL</div>
  <div class="kpi-v" style="color:{(net_cur>=0 and '#16a34a') or '#dc2626'}">{net_cur:+.2f}</div></div>
<div class="kpi"><div class="kpi-l">Δ vs prev {days}gg</div>
  <div class="kpi-v" style="color:{color}">{delta:+.2f}</div></div>
<div class="kpi"><div class="kpi-l">Trade</div>
  <div class="kpi-v">{metrics_cur['n']}</div></div>
<div class="kpi"><div class="kpi-l">Win Rate</div>
  <div class="kpi-v">{metrics_cur['wr']:.1f}%</div></div>
<div class="kpi"><div class="kpi-l">Profit Factor</div>
  <div class="kpi-v" style="color:{(metrics_cur.get('pf') or 0)>=1 and '#16a34a' or '#dc2626'}">{(metrics_cur.get('pf') or 0):.2f}</div></div>
<div class="kpi"><div class="kpi-l">Max DD</div>
  <div class="kpi-v" style="color:#dc2626">−{metrics_cur['max_dd']:.2f}</div></div>

<h2>Per symbol</h2>
<table><thead><tr><th>Symbol</th><th>N</th><th>WR</th><th>Net</th><th>PF</th><th>AvgW</th><th>AvgL</th></tr></thead>
<tbody>{sym_rows}</tbody></table>

<h2>Per lato</h2>
<table><thead><tr><th>Side</th><th>N</th><th>WR</th><th>Net</th><th>PF</th></tr></thead>
<tbody>{side_rows}</tbody></table>

</body></html>"""


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--days", type=int, default=7)
    parser.add_argument("--out", type=str, default=str(LOG_DIR / f"weekly_diag_{datetime.now().strftime('%Y%m%d_%H%M')}.html"))
    args = parser.parse_args()

    print(f"=== Weekly Diagnostic V2 — ultimi {args.days}gg ===")
    print(f"Output: {args.out}")

    client = BybitDemoClient()
    print(f"Account: {client.api_key[:10]}...{client.api_key[-4:]}")

    # Trade periodo corrente
    trades_cur = fetch_closed_pnl(client, args.days)
    print(f"Trade ultimi {args.days}gg: {len(trades_cur)}")

    # Trade periodo precedente (per confronto)
    trades_prev = fetch_closed_pnl(client, args.days * 2)
    cutoff_ms = int((datetime.now(timezone.utc) - timedelta(days=args.days)).timestamp() * 1000)
    trades_prev = [t for t in trades_prev if int(t.get("updatedTime", 0)) < cutoff_ms]
    print(f"Trade {args.days}-{args.days*2}gg fa: {len(trades_prev)}")

    # Metriche
    metrics_cur = compute_metrics(trades_cur)
    metrics_prev = compute_metrics(trades_prev)
    by_symbol = by_breakdown(trades_cur, "symbol")
    by_side = by_breakdown(trades_cur, "side")

    # Render HTML
    html = render_html(metrics_cur, metrics_prev, by_symbol, by_side, args.days)
    Path(args.out).write_text(html, encoding="utf-8")
    print(f"Report scritto: {args.out}")
    print()
    print(f"=== SUMMARY ===")
    print(f"Net {args.days}gg:   {metrics_cur['net']:+.2f} USDT")
    print(f"Net {args.days}gg prev: {metrics_prev['net']:+.2f} USDT")
    print(f"Delta: {metrics_cur['net'] - metrics_prev['net']:+.2f}")
    print(f"WR:    {metrics_cur['wr']:.1f}%")
    print(f"PF:    {(metrics_cur.get('pf') or 0):.2f}")
    print(f"Max DD: {metrics_cur['max_dd']:.2f}")


if __name__ == "__main__":
    main()
