"""Junction telemetry check for heartbeat monitoring.

TELEM-03: After sidecar restart, collects diagnostic data about the
REST->WS junction: trade IDs, forming bar state, committed_floors.
Purely informational -- NOT health-gating.
"""

from __future__ import annotations

import logging
import subprocess

import requests

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

_SIDECAR_HEALTH_URL = "http://localhost:8081/health"
_SIDECAR_STATUS_URL = "http://localhost:8081/status"


def collect_junction_telemetry(
    results: dict[str, bool | str],
) -> None:
    """Collect junction telemetry from sidecar health/status endpoints.

    Populates results with REST/WS trade IDs, forming bar state, and
    committed_floors. Falls back to journalctl logs if HTTP endpoints
    don't provide full data.
    """
    rest_last_tid = "unavailable"
    ws_first_tid = "unavailable"
    forming_bar = "unavailable"
    committed_floors = "unavailable"

    try:
        resp = requests.get(_SIDECAR_HEALTH_URL, timeout=5)
        if resp.status_code != 200:
            results["junction_telemetry"] = False
            results["junction_rest_last_tid"] = rest_last_tid
            results["junction_ws_first_tid"] = ws_first_tid
            results["junction_forming_bar"] = forming_bar
            results["junction_committed_floors"] = committed_floors
            return

        health_data = resp.json()

        # Try status endpoint for more detailed data
        status_data = {}
        try:
            status_resp = requests.get(_SIDECAR_STATUS_URL, timeout=5)
            if status_resp.status_code == 200:
                status_data = status_resp.json()
        except Exception:
            logger.debug("sidecar /status endpoint unavailable", exc_info=True)

        # Extract from health or status data (per-symbol)
        symbols_data = (
            status_data.get("symbols")
            or health_data.get("symbols")
            or {}
        )

        if symbols_data:
            # Aggregate across symbols
            rest_tids = []
            ws_tids = []
            forming_parts = []
            floor_parts = []

            for sym, sym_data in symbols_data.items():
                if isinstance(sym_data, dict):
                    r_tid = sym_data.get("rest_last_tid")
                    if r_tid is not None:
                        rest_tids.append(f"{sym}={r_tid}")
                    w_tid = sym_data.get("ws_first_tid")
                    if w_tid is not None:
                        ws_tids.append(f"{sym}={w_tid}")
                    fb = sym_data.get("forming_bar")
                    if fb is not None:
                        forming_parts.append(f"{sym}: {fb}")
                    floors = sym_data.get("committed_floors")
                    if floors is not None:
                        if isinstance(floors, dict):
                            floor_strs = [
                                f"{sym}@{t}={v}" for t, v in floors.items()
                            ]
                            floor_parts.extend(floor_strs)
                        else:
                            floor_parts.append(f"{sym}={floors}")

            if rest_tids:
                rest_last_tid = ", ".join(rest_tids)
            if ws_tids:
                ws_first_tid = ", ".join(ws_tids)
            if forming_parts:
                forming_bar = "; ".join(forming_parts)
            if floor_parts:
                committed_floors = ", ".join(floor_parts)

        # If HTTP didn't give us enough, try journal logs
        if rest_last_tid == "unavailable" or ws_first_tid == "unavailable":
            _try_journal_fallback(results, rest_last_tid, ws_first_tid)
            rest_last_tid = results.get("junction_rest_last_tid", rest_last_tid)
            ws_first_tid = results.get("junction_ws_first_tid", ws_first_tid)

        results["junction_telemetry"] = True

    except (requests.ConnectionError, requests.Timeout, OSError):
        logger.debug("sidecar unavailable for junction telemetry", exc_info=True)
        results["junction_telemetry"] = False

    results["junction_rest_last_tid"] = rest_last_tid
    results["junction_ws_first_tid"] = ws_first_tid
    results["junction_forming_bar"] = forming_bar
    results["junction_committed_floors"] = committed_floors


def _try_journal_fallback(
    results: dict[str, bool | str],
    current_rest: str,
    current_ws: str,
) -> None:
    """Parse sidecar journal logs for junction data as fallback."""
    try:
        r = subprocess.run(
            [
                "journalctl",
                "--user",
                "-u",
                "opendeviationbar-sidecar",
                "--since",
                "30 min ago",
                "--no-pager",
                "-o",
                "short-precise",
            ],
            capture_output=True,
            text=True,
            timeout=10,
            check=False,
        )
        if r.returncode != 0:
            return

        for line in reversed(r.stdout.splitlines()):
            if (
                current_rest == "unavailable"
                and "fill_from_rest" in line
                and "last_tid=" in line
            ):
                tid = line.split("last_tid=")[1].split()[0].strip(",")
                results["junction_rest_last_tid"] = tid
                current_rest = tid
            if current_ws == "unavailable" and "ws_first_tid=" in line:
                tid = line.split("ws_first_tid=")[1].split()[0].strip(",")
                results["junction_ws_first_tid"] = tid
                current_ws = tid

    except (FileNotFoundError, subprocess.TimeoutExpired, OSError):
        logger.debug("journalctl fallback failed", exc_info=True)
