"""Aion freshness check for heartbeat monitoring.

MON-01: Per-symbol rolling-window freshness check — verifies the last
committed bar is within the configured freshness window.
"""

from __future__ import annotations

import logging
import time

from heartbeat.config import AION_FRESHNESS_WINDOW_MIN, get_heartbeat_symbols

logger = logging.getLogger("health-heartbeat")


def collect_yesterday_completion(
    client: object,
    results: dict[str, bool | str],
) -> None:
    """Check per-symbol freshness via rolling-window check.

    For each enabled Binance spot symbol (via get_heartbeat_symbols()):
    verifies the last committed bar is within the configured freshness window.
    """
    from opendeviationbar.clickhouse.stathera_query import FULL_TABLE

    checked_symbols: list[str] = []

    for symbol in get_heartbeat_symbols():
        checked_symbols.append(symbol)
        _check_aion_freshness(client, symbol, results, FULL_TABLE)

    # Aggregate health gate: True unless a real mismatch (False) is detected
    results["yesterday_completion"] = all(
        results.get(f"yesterday_{s}") is not False for s in checked_symbols
    )


def _check_aion_freshness(
    client: object,
    symbol: str,
    results: dict[str, bool | str],
    full_table: str,
) -> None:
    """Rolling-window freshness check for Aion symbols.

    Three states:
    - aion:fresh — last committed bar within freshness window
    - aion:developing — bar not committed yet, but sidecar is actively
      receiving WS trades (healthy, threshold not yet breached)
    - aion:stale — no committed bar AND sidecar not streaming this symbol
    """
    try:
        row = client.query(
            f"""
            SELECT max(close_time_us), max(last_agg_trade_id)
            FROM {full_table} FINAL
            WHERE symbol = '{symbol}'
              AND ouroboros_mode = 'aion'
              AND close_time_us > 0
            """
        )
    except Exception:
        logger.warning(
            "Aion freshness query failed for %s", symbol, exc_info=True
        )
        results[f"yesterday_{symbol}"] = "query_failed"
        return

    max_close_us = row.result_rows[0][0] if row.result_rows else None
    max_committed_tid = row.result_rows[0][1] if row.result_rows else None
    if max_close_us is None:
        results[f"yesterday_{symbol}"] = "no_bars"
        return

    now_us = int(time.time() * 1_000_000)
    stale_min = (now_us - max_close_us) / 60_000_000

    if stale_min <= AION_FRESHNESS_WINDOW_MIN:
        results[f"yesterday_{symbol}"] = True
        results[f"yesterday_{symbol}_detail"] = (
            f"aion:fresh ({stale_min:.0f}m ago)"
        )
        return

    # Bar is older than window — check if sidecar is actively streaming
    # (forming bar receiving trades but hasn't breached threshold yet)
    sidecar_active = False
    try:
        import json as _json
        import urllib.request

        resp = urllib.request.urlopen(
            "http://localhost:8081/status", timeout=3
        )
        status = _json.loads(resp.read())
        sym_status = (status.get("symbols") or status).get(symbol, {})
        ws_tid = sym_status.get("ws_first_tid")
        if ws_tid and max_committed_tid and ws_tid > max_committed_tid:
            sidecar_active = True
    except (OSError, ValueError, KeyError):
        logger.debug("Sidecar /status unreachable for %s — treating as stale", symbol)

    if sidecar_active:
        # Healthy: bar is developing, trades flowing, threshold not yet breached
        results[f"yesterday_{symbol}"] = True
        results[f"yesterday_{symbol}_detail"] = (
            f"aion:developing ({stale_min:.0f}m, threshold not breached)"
        )
    else:
        results[f"yesterday_{symbol}"] = False
        results[f"yesterday_{symbol}_detail"] = (
            f"aion:stale ({stale_min:.0f}m, window={AION_FRESHNESS_WINDOW_MIN}m)"
        )
