"""dashboard.py — Learning system health and transparency aggregator.

Aggregates data from trading_brain.db, pattern_miner, lesson_learner,
and brain_scheduler into a single human-readable dashboard payload.

Consumed by GET /api/learning/dashboard → GUI React panel.

Usage::

    from src.learning.dashboard import build_learning_dashboard
    payload = build_learning_dashboard()
"""

from __future__ import annotations

import time
from typing import Any


def _backfill_trade_events_from_ledger(brain) -> int:
    try:
        from skill_trading_memory import query_trades
        from src.learning.feature_extractor import extract_trade_features
    except Exception:
        return 0

    inserted = 0
    try:
        trades = query_trades(limit=None, since_days=3650)
    except Exception:
        return 0

    for trade in trades:
        try:
            features = extract_trade_features(trade, {}, {})
            if brain.record_trade(features["entry_features"], features["outcome"]) is not None:
                inserted += 1
        except Exception:
            continue
    return inserted


def build_learning_dashboard() -> dict[str, Any]:
    """Build a complete learning dashboard payload.

    Returns:
        {
            "available": bool,
            "brain": {table_sizes, trade_count, judgment_count},
            "performance": {overall_wr, aligned_wr, counter_wr, by_regime_session},
            "patterns": {win_patterns[], top_features[]},
            "lessons": {active[], pending[], total},
            "scheduler": {ring2_triggered, ring3_triggered, trade_count, last_runs},
            "judgments": {accuracy, total, avg_confidence},
            "recent_events": [{type, ts, detail}],
        }
    """
    payload: dict[str, Any] = {
        "available": False,
        "brain": {},
        "performance": {},
        "patterns": {"win_patterns": [], "top_features": []},
        "lessons": {"active": [], "pending": [], "total": 0},
        "scheduler": {},
        "judgments": {},
        "recent_events": [],
        "generated_at": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()),
    }

    try:
        from src.learning.trading_brain import get_brain
        brain = get_brain()
    except Exception:
        return payload

    try:
        sizes = brain.table_sizes()
        trade_count = sizes.get("trade_events", 0)
        judgment_count = sizes.get("agent_judgments", 0)
        if trade_count == 0:
            inserted = _backfill_trade_events_from_ledger(brain)
            if inserted > 0:
                sizes = brain.table_sizes()
                trade_count = sizes.get("trade_events", 0)
                payload["recent_events"].append({
                    "type": "trade_backfill",
                    "ts": payload["generated_at"],
                    "detail": f"Recovered {inserted} closed trades from trading ledger",
                })
        payload["available"] = trade_count > 0
        payload["brain"] = {
            "table_sizes": sizes,
            "trade_count": trade_count,
            "judgment_count": judgment_count,
            "db_path": str(brain._path),
        }
    except Exception:
        return payload

    # ── Performance ──
    try:
        overall = brain.query_win_rate()
        aligned = brain.query_win_rate(agent_aligned=1)
        counter = brain.query_win_rate(agent_aligned=0)
        by_rs = brain.query_by_regime_session()
        payload["performance"] = {
            "overall": overall,
            "aligned": aligned,
            "counter": counter,
            "by_regime_session": by_rs,
        }
        payload["recent_events"].append({
            "type": "performance_snapshot",
            "ts": payload["generated_at"],
            "detail": f"Overall WR: {overall['win_rate']:.0%} ({overall['n']} trades)"
        })
    except Exception:
        pass

    # ── Patterns ──
    try:
        patterns_rows = brain._conn.execute(
            "SELECT * FROM trade_events WHERE is_win=1 ORDER BY opened_at DESC LIMIT 50"
        ).fetchall()
        # Count win patterns from recent trades
        win_regimes: dict[str, int] = {}
        for r in patterns_rows:
            reg = str(r["regime"] or "").strip()
            ses = str(r["session"] or "").strip()
            if reg and ses:
                key = f"{reg}/{ses}"
                win_regimes[key] = win_regimes.get(key, 0) + 1
        top_combos = sorted(win_regimes.items(), key=lambda x: -x[1])[:5]
        payload["patterns"]["win_patterns"] = [
            {"combo": k, "wins": v, "label": f"Best: {k} ({v} wins)"}
            for k, v in top_combos
        ]
    except Exception:
        pass

    # ── Lessons ──
    try:
        brain._conn.execute("""
            CREATE TABLE IF NOT EXISTS loss_lessons (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                learned_at TEXT DEFAULT (datetime('now')),
                lesson_type TEXT NOT NULL UNIQUE,
                label TEXT DEFAULT '',
                conditions TEXT DEFAULT '[]',
                loss_count INTEGER DEFAULT 0,
                total_pnl REAL DEFAULT 0.0,
                win_rate REAL DEFAULT 0.0,
                avoidance_rule TEXT DEFAULT '',
                action TEXT DEFAULT '',
                applied INTEGER DEFAULT 0,
                applied_at TEXT DEFAULT '',
                created_at TEXT DEFAULT (datetime('now'))
            )
        """)
        active_rows = brain._conn.execute(
            "SELECT * FROM loss_lessons WHERE applied=1 ORDER BY win_rate ASC"
        ).fetchall()
        pending_rows = brain._conn.execute(
            "SELECT * FROM loss_lessons WHERE applied=0 ORDER BY win_rate ASC"
        ).fetchall()
        payload["lessons"]["active"] = [
            {"type": r["lesson_type"], "label": r["label"],
             "win_rate": r["win_rate"], "rule": r["avoidance_rule"],
             "loss_count": r["loss_count"], "applied_at": r["applied_at"]}
            for r in active_rows
        ]
        payload["lessons"]["pending"] = [
            {"type": r["lesson_type"], "label": r["label"],
             "win_rate": r["win_rate"], "rule": r["avoidance_rule"],
             "loss_count": r["loss_count"]}
            for r in pending_rows
        ]
        payload["lessons"]["total"] = len(active_rows) + len(pending_rows)
    except Exception:
        pass

    # ── Scheduler state ──
    try:
        import json
        from pathlib import Path
        import config_manager
        sp = config_manager.get_data_dir() / "learning" / "brain_scheduler_state.json"
        if sp.exists():
            sched = json.loads(sp.read_text(encoding="utf-8"))
            payload["scheduler"] = {
                "last_ring2_trade_count": sched.get("last_ring2_trade_count", 0),
                "last_ring3_trade_count": sched.get("last_ring3_trade_count", 0),
                "ring2_last_run": sched.get("ring2_last_run_ts", ""),
                "ring3_last_run": sched.get("ring3_last_run_ts", ""),
                "next_ring2_at": sched.get("last_ring2_trade_count", 0) + 20,
                "next_ring3_at": sched.get("last_ring3_trade_count", 0) + 100,
                "progress_ring2_pct": min(100, round(
                    (trade_count - sched.get("last_ring2_trade_count", 0)) / 20 * 100, 1
                )) if trade_count > 0 else 0,
                "progress_ring3_pct": min(100, round(
                    (trade_count - sched.get("last_ring3_trade_count", 0)) / 100 * 100, 1
                )) if trade_count > 0 else 0,
            }
    except Exception:
        pass

    # ── Judgments ──
    try:
        acc = brain.query_judgment_accuracy()
        payload["judgments"] = {
            "total": acc.get("n", 0),
            "accuracy": acc.get("accuracy", 0.0),
            "avg_confidence": acc.get("avg_confidence", 0.0),
        }
    except Exception:
        pass

    return payload
