"""Constants and configuration for heartbeat monitoring."""

from __future__ import annotations

import logging
import os
from functools import lru_cache
from pathlib import Path

# Healthy messages are deleted after this many seconds
TTL_SECONDS = 15 * 60  # 15 minutes

# State file: stores [{message_id, sent_at}, ...] for pending deletions
STATE_DIR = Path.home() / ".cache" / "opendeviationbar" / "heartbeat"
STATE_FILE = STATE_DIR / "pending_messages.json"
STATHERA_STATE_FILE = STATE_DIR / "stathera_counts.json"

# Suppress duplicate alerts for 1 hour
ALERT_DEDUP_TTL = 3600

# Aion mode: rolling-window freshness check (replaces yesterday completion)
# Default 30 min -- generous for high thresholds (1000 dbps produce fewer bars)
AION_FRESHNESS_WINDOW_MIN = int(
    os.environ.get("OPENDEVIATIONBAR_AION_FRESHNESS_WINDOW_MIN", "30")
)

# Priority symbols shown first in the freshness section (matches kintsugi)
# DEPRECATED: Use get_heartbeat_symbols() instead for dynamic registry-based lookup.
HEARTBEAT_PRIORITY_SYMBOLS = ("BTCUSDT", "ETHUSDT")


@lru_cache(maxsize=1)
def get_heartbeat_symbols() -> tuple[str, ...]:
    """Get all enabled Binance spot symbols from the symbol registry.

    Returns a sorted tuple of symbol names filtered to exchange="binance"
    and market="spot". Falls back to HEARTBEAT_PRIORITY_SYMBOLS on any
    exception (ImportError, registry corruption, etc.).

    The result is cached for the lifetime of the process (heartbeat runs
    every 5 minutes as a fresh systemd oneshot, so no stale-cache risk).
    """
    try:
        from opendeviationbar.symbol_registry import get_symbol_entries

        entries = get_symbol_entries()
        symbols = [
            name
            for name, entry in entries.items()
            if entry.exchange == "binance"
            and entry.market == "spot"
            and entry.enabled
        ]
        return tuple(sorted(symbols))
    except Exception:
        logging.getLogger("health-heartbeat").warning(
            "Failed to load symbol registry, falling back to %s",
            HEARTBEAT_PRIORITY_SYMBOLS,
            exc_info=True,
        )
        return HEARTBEAT_PRIORITY_SYMBOLS

# 4-tier health level system: CRITICAL > WARNING > DEGRADED > HEALTHY
# Each key is assigned to a tier based on blast radius:
#
# CRITICAL: Data integrity at risk. Immediate action needed.
#   Stathera gaps/overlaps growing without healing, circuit breaker open,
#   ClickHouse down, sidecar/kintsugi services down.
#
# WARNING: Operational issue but data is safe. Will self-heal or needs attention.
#   Kintsugi repair failures, stuck repairs, version drift, memory pressure,
#   seeder failures, cross-midnight bars.
#
# DEGRADED: Minor issue, informational. No action needed.
#   Kintsugi telemetry stale, yesterday completion query failed.
#
# Telegram behavior per level:
#   HEALTHY:  💚 ephemeral (auto-delete 15min), silent
#   DEGRADED: 🟡 ephemeral (auto-delete 15min), silent
#   WARNING:  🟠 persistent, silent notification
#   CRITICAL: 🔴 persistent, LOUD notification

CRITICAL_KEYS = frozenset({
    "clickhouse",
    "sidecar",
    "kintsugi",
    "disk",
    "stathera_overlaps",
    "stathera_gaps",              # v7.2: gates on pipeline_gap_count only (exchange gaps excluded)
    "stathera_today_gaps",        # #295 P0-3: kintsugi can't fix today (#280)
    "stathera_today_overlaps",    # #295 P0-3: kintsugi can't fix today (#280)
    "circuit_breaker_healthy",
    "checksum_ok",                # v6.0: checksum failure = potentially corrupted data (LOUD)
    "ch_writer_dead_letters_ok",  # Issue #318: Rust CH writer dead letters = bars lost (LOUD)
    "ws_errors_healthy",          # 429/IP ban blocks ALL trades — CRITICAL, not unclassified
})

WARNING_KEYS = frozenset({
    "kintsugi_stuck",
    "kintsugi_failures",
    "kintsugi_memory",
    "version_drift",
    "seeder_ok",
    "ratelimit_ok",
})

DEGRADED_KEYS = frozenset({
    "kintsugi_telemetry",
    "yesterday_completion",
})

# Union of all tiers — backward compat for code that references HEALTH_GATE_KEYS
HEALTH_GATE_KEYS = CRITICAL_KEYS | WARNING_KEYS | DEGRADED_KEYS

# Known Stathera gap fingerprints — specific (symbol, threshold, first_agg_trade_id,
# prev_last_tid) combos where the root cause is definitively identified.
# When ALL active gaps match a known fingerprint, the Telegram alert shows a detailed
# diagnostic block instead of a generic 🔴 alert, so the reader immediately knows
# it's a known transient and no manual action is needed.
# Cleared for v7.0 Aion recompute. Re-add only if gaps reappear post-recompute.
KNOWN_GAP_FINGERPRINTS: dict[tuple, dict] = {}
