#!/usr/bin/env python3
"""Token Budget Tracker -- real-time spend dashboard for pipelines."""

import argparse, json, os, sqlite3, sys, time
from datetime import datetime
from pathlib import Path

DB_PATH = Path.home() / ".hermes" / "pipelines" / "token_usage.db"
ALERT_THRESHOLDS = [0.5, 0.8, 1.0]
DEFAULT_BUDGETS = {
    "knowledge-mine": 200_000_000,
    "training-factory": 215_000_000,
    "playground": 16_000_000,
    "adversary": 17_000_000,
}

def get_db():
    DB_PATH.parent.mkdir(parents=True, exist_ok=True)
    conn = sqlite3.connect(str(DB_PATH))
    conn.row_factory = sqlite3.Row
    conn.execute("PRAGMA journal_mode=WAL")
    conn.executescript("""
        CREATE TABLE IF NOT EXISTS token_usage (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            pipeline TEXT NOT NULL,
            worker TEXT NOT NULL,
            tokens INTEGER NOT NULL,
            recorded_at REAL NOT NULL,
            hour_bucket TEXT NOT NULL
        );
        CREATE TABLE IF NOT EXISTS pipeline_budgets (
            pipeline TEXT PRIMARY KEY,
            target_tokens INTEGER NOT NULL,
            updated_at REAL NOT NULL
        );
        CREATE TABLE IF NOT EXISTS alerts_sent (
            pipeline TEXT NOT NULL,
            threshold REAL NOT NULL,
            sent_at REAL NOT NULL,
            PRIMARY KEY (pipeline, threshold)
        );
        CREATE INDEX IF NOT EXISTS idx_usage_pipeline_hour
            ON token_usage(pipeline, hour_bucket);
    """)
    for name, target in DEFAULT_BUDGETS.items():
        conn.execute(
            "INSERT OR IGNORE INTO pipeline_budgets (pipeline, target_tokens, updated_at) VALUES (?, ?, ?)",
            (name, target, time.time())
        )
    conn.commit()
    return conn

def log_usage(conn, pipeline, worker, tokens):
    now = time.time()
    hour = datetime.now().strftime("%Y-%m-%d %H:00")
    conn.execute(
        "INSERT INTO token_usage (pipeline, worker, tokens, recorded_at, hour_bucket) VALUES (?, ?, ?, ?, ?)",
        (pipeline, worker, tokens, now, hour)
    )
    conn.commit()
    check_alerts(conn, pipeline)

def get_pipeline_stats(conn):
    rows = conn.execute("""
        SELECT u.pipeline, COALESCE(b.target_tokens, 0) as target,
            SUM(u.tokens) as used, MIN(u.recorded_at) as started_at,
            COUNT(DISTINCT u.worker) as workers
        FROM token_usage u
        LEFT JOIN pipeline_budgets b ON u.pipeline = b.pipeline
        GROUP BY u.pipeline ORDER BY used DESC
    """).fetchall()
    return [dict(r) for r in rows]

def fmt(n):
    if n >= 1_000_000_000: return f"{n/1_000_000_000:.1f}B"
    if n >= 1_000_000: return f"{n/1_000_000:.1f}M"
    if n >= 1_000: return f"{n/1_000:.1f}K"
    return str(n)

def bar(ratio, w=8):
    filled = int(ratio * w)
    return "█" * filled + "░" * (w - filled)

def eta(used, target, started):
    if used <= 0 or started <= 0: return "--"
    elapsed = (time.time() - started) / 3600
    if elapsed <= 0: return "--"
    rate = used / elapsed
    remaining = target - used
    if remaining <= 0: return "DONE"
    h = remaining / rate
    return f"{h/24:.1f}d" if h >= 24 else f"{h:.1f}h"

def render_dashboard(conn):
    stats = get_pipeline_stats(conn)
    if not stats:
        print("No pipeline data recorded yet.")
        return
    print()
    print(f"{'Pipeline':<20} {'Tokens Used':>12} {'Target':>10} {'Progress':>10} {'ETA':>8} {'Workers':>8}")
    print("-" * 72)
    total_used = total_target = 0
    for s in stats:
        used = s["used"] or 0
        target = s["target"] or 1
        ratio = min(used / target, 1.0) if target > 0 else 0
        print(f"{s['pipeline']:<20} {fmt(used):>12} {fmt(target):>10} {bar(ratio):>10} {eta(used, target, s['started_at'] or 0):>8} {s['workers'] or 0:>8}")
        total_used += used
        total_target += target
    print("-" * 72)
    r = min(total_used / total_target, 1.0) if total_target > 0 else 0
    print(f"{'TOTAL':<20} {fmt(total_used):>12} {fmt(total_target):>10} {bar(r):>10}")
    print()

def render_watch(conn, interval=5):
    try:
        while True:
            os.system("clear" if os.name != "nt" else "cls")
            print(f"Token Budget Tracker -- {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
            print("Press Ctrl+C to exit")
            render_dashboard(conn)
            time.sleep(interval)
    except KeyboardInterrupt:
        print("\nExiting.")

def render_daily_summary(conn):
    since = time.time() - 86400
    rows = conn.execute("""
        SELECT pipeline, SUM(tokens) as total, COUNT(DISTINCT worker) as workers, COUNT(*) as entries
        FROM token_usage WHERE recorded_at >= ? GROUP BY pipeline ORDER BY total DESC
    """, (since,)).fetchall()
    if not rows:
        print("No usage in last 24 hours.")
        return
    print(f"\nDaily Summary -- last 24 hours")
    print(f"{'Pipeline':<20} {'Total Tokens':>14} {'Workers':>8} {'Entries':>8}")
    print("-" * 54)
    gt = 0
    for r in rows:
        print(f"{r['pipeline']:<20} {fmt(r['total']):>14} {r['workers']:>8} {r['entries']:>8}")
        gt += r["total"]
    print("-" * 54)
    print(f"{'TOTAL':<20} {fmt(gt):>14}\n")

def check_alerts(conn, pipeline):
    row = conn.execute(
        "SELECT SUM(u.tokens) as used, COALESCE(b.target_tokens, 0) as target "
        "FROM token_usage u LEFT JOIN pipeline_budgets b ON u.pipeline = b.pipeline "
        "WHERE u.pipeline = ?", (pipeline,)
    ).fetchone()
    if not row or row["target"] <= 0: return
    ratio = row["used"] / row["target"]
    for t in ALERT_THRESHOLDS:
        if ratio >= t:
            existing = conn.execute("SELECT 1 FROM alerts_sent WHERE pipeline = ? AND threshold = ?", (pipeline, t)).fetchone()
            if not existing:
                print(f"⚠️ BUDGET ALERT: {pipeline} at {int(t*100)}% ({fmt(row['used'])}/{fmt(row['target'])})", file=sys.stderr)
                conn.execute("INSERT INTO alerts_sent (pipeline, threshold, sent_at) VALUES (?, ?, ?)", (pipeline, t, time.time()))
                conn.commit()

def set_budget(conn, pipeline, target):
    conn.execute("INSERT OR REPLACE INTO pipeline_budgets (pipeline, target_tokens, updated_at) VALUES (?, ?, ?)",
        (pipeline, int(target), time.time()))
    conn.execute("DELETE FROM alerts_sent WHERE pipeline = ?", (pipeline,))
    conn.commit()
    print(f"Budget set: {pipeline} = {fmt(int(target))} tokens")

def main():
    parser = argparse.ArgumentParser(description="Token Budget Tracker")
    parser.add_argument("--watch", action="store_true")
    parser.add_argument("--watch-interval", type=int, default=5)
    parser.add_argument("--summary", action="store_true")
    parser.add_argument("--log", nargs=3, metavar=("PIPELINE", "WORKER", "TOKENS"))
    parser.add_argument("--budget", nargs=2, metavar=("PIPELINE", "TARGET"))
    parser.add_argument("--db", type=str, default=str(DB_PATH))
    args = parser.parse_args()
    global DB_PATH
    DB_PATH = Path(args.db)
    conn = get_db()
    if args.log:
        log_usage(conn, args.log[0], args.log[1], int(args.log[2]))
        print(f"Logged: {args.log[0]}/{args.log[1]} = {fmt(int(args.log[2]))} tokens")
    elif args.budget:
        set_budget(conn, args.budget[0], args.budget[1])
    elif args.summary:
        render_daily_summary(conn)
    elif args.watch:
        render_watch(conn, interval=args.watch_interval)
    else:
        render_dashboard(conn)
    conn.close()

if __name__ == "__main__":
    main()
