#!/usr/bin/env python3
"""Weekly precision monitor for congressional trading signals.

Queries signal_outcomes, computes rolling 30d win rate (excess vs SPY)
for last 10 / last 20 / all-time settled signals, and outputs JSON for
the Nano task trigger:
  { "wakeAgent": true/false, "data": { ... } }

wakeAgent=true when the active precision window drops below 40% (floor).
Always logs a human-readable summary to stderr for the run log.
"""
import json
import sqlite3
import sys
import urllib.request
import urllib.error

DB_PATH = "/workspace/extra/projects/congressional-trading/data/congress_trades.db"
NTFY_URL = "https://ntfy.sh/congressWatchSignals"
WIN_RATE_FLOOR = 0.40  # BREAKER_MIN_WIN_RATE from config.py


def precision(vals: list) -> float | None:
    if not vals:
        return None
    wins = sum(1 for v in vals if (v or 0) > 0)
    return wins / len(vals)


def ntfy_alert(title: str, body: str) -> None:
    try:
        req = urllib.request.Request(
            NTFY_URL,
            data=body.encode(),
            headers={"Title": title, "Priority": "high", "Tags": "chart_with_downwards_trend,warning"},
            method="POST",
        )
        urllib.request.urlopen(req, timeout=10)
    except Exception as e:
        print(f"[congressional-monitor] ntfy failed: {e}", file=sys.stderr)


def main() -> None:
    try:
        conn = sqlite3.connect(DB_PATH)
        rows = conn.execute(
            """SELECT return_30d_excess_pct, ticker, notified_at, conviction
               FROM signal_outcomes
               WHERE fired=1 AND return_30d_pct IS NOT NULL
               ORDER BY notified_at DESC"""
        ).fetchall()
        conn.close()
    except Exception as e:
        print(json.dumps({"wakeAgent": False, "data": {"error": str(e)}}))
        return

    n = len(rows)
    if n == 0:
        print(json.dumps({"wakeAgent": False, "data": {"note": "no settled signals yet"}}))
        return

    excess_vals = [r[0] for r in rows]
    p_all = precision(excess_vals)
    p_20 = precision(excess_vals[:20]) if n >= 20 else None
    p_10 = precision(excess_vals[:10]) if n >= 10 else None

    # Active window = tightest settled window with ≥ 10 signals
    active_p = p_10 if p_10 is not None else p_all
    active_label = "last 10" if p_10 is not None else f"all {n}"

    summary = {
        "n_settled": n,
        "precision_all": round(p_all * 100, 1),
        "precision_last_20": round(p_20 * 100, 1) if p_20 is not None else None,
        "precision_last_10": round(p_10 * 100, 1) if p_10 is not None else None,
        "active_window": active_label,
        "active_precision": round(active_p * 100, 1),
        "floor_pct": WIN_RATE_FLOOR * 100,
        "alert": active_p < WIN_RATE_FLOOR,
    }

    print(
        f"[congressional-monitor] {n} settled | all={p_all*100:.1f}%"
        + (f" | last20={p_20*100:.1f}%" if p_20 else "")
        + (f" | last10={p_10*100:.1f}%" if p_10 else "")
        + f" | floor={WIN_RATE_FLOOR*100:.0f}%",
        file=sys.stderr,
    )

    if active_p < WIN_RATE_FLOOR:
        alert_msg = (
            f"CongressWatch precision alert: {active_label} win rate "
            f"{active_p*100:.1f}% is below the {WIN_RATE_FLOOR*100:.0f}% floor. "
            f"Consider tuning threshold or conviction gate."
        )
        print(f"[congressional-monitor] ALERT: {alert_msg}", file=sys.stderr)
        ntfy_alert("CongressWatch: precision below floor", alert_msg)
        print(json.dumps({"wakeAgent": True, "data": {**summary, "alert_message": alert_msg}}))
    else:
        print(
            f"[congressional-monitor] Precision holding ({active_label}: {active_p*100:.1f}%). No action needed.",
            file=sys.stderr,
        )
        print(json.dumps({"wakeAgent": False, "data": summary}))


if __name__ == "__main__":
    main()
