"""Tests for yesterday completion (TELEM-02) and junction telemetry (TELEM-03)."""

from __future__ import annotations

from unittest.mock import MagicMock, patch


def _make_client(queries: dict[str, list[list]]) -> MagicMock:
    """Create a mock ClickHouse client returning canned results per query substring."""
    client = MagicMock()

    def _query(sql: str, **_kw: object) -> MagicMock:
        result = MagicMock()
        for substr, rows in queries.items():
            if substr in sql:
                result.result_rows = rows
                return result
        result.result_rows = []
        return result

    client.query.side_effect = _query
    return client


class TestYesterdayCompletion:
    """Tests for collect_yesterday_completion (TELEM-02)."""

    def test_clean_orphan_match(self):
        """Orphan last_agg_trade_id == crossover_tid - 1 -> True, detail 'clean'."""
        # Crossover TID = 5000, orphan last_tid = 4999 -> match
        client = _make_client({
            "yesterday()": [[4999]],  # max(last_agg_trade_id) WHERE yesterday()
        })
        results: dict = {}

        with patch(
            "heartbeat.checks.yesterday._get_midnight_crossover_tid",
            return_value=5000,
        ):
            from heartbeat.checks.yesterday import collect_yesterday_completion

            collect_yesterday_completion(client, results)

        assert results["yesterday_BTCUSDT"] is True
        assert results["yesterday_BTCUSDT_detail"] == "clean"
        assert results["yesterday_completion"] is True

    def test_orphan_mismatch(self):
        """Orphan last_agg_trade_id != crossover_tid - 1 -> False with detail."""
        # Crossover TID = 5000, orphan last_tid = 4990 -> mismatch
        client = _make_client({
            "yesterday()": [[4990]],
        })
        results: dict = {}

        with patch(
            "heartbeat.checks.yesterday._get_midnight_crossover_tid",
            return_value=5000,
        ):
            from heartbeat.checks.yesterday import collect_yesterday_completion

            collect_yesterday_completion(client, results)

        assert results["yesterday_BTCUSDT"] is False
        assert "expected 4999" in results["yesterday_BTCUSDT_detail"]
        assert "got 4990" in results["yesterday_BTCUSDT_detail"]
        assert results["yesterday_completion"] is False

    def test_no_orphan_bar(self):
        """No orphan bar for yesterday -> 'no_orphan' (not False)."""
        client = _make_client({
            "yesterday()": [[None]],  # max() returns NULL when no rows
        })
        results: dict = {}

        with patch(
            "heartbeat.checks.yesterday._get_midnight_crossover_tid",
            return_value=5000,
        ):
            from heartbeat.checks.yesterday import collect_yesterday_completion

            collect_yesterday_completion(client, results)

        assert results["yesterday_BTCUSDT"] == "no_orphan"
        # no_orphan is not False, so yesterday_completion should be True
        assert results["yesterday_completion"] is True

    def test_crossover_query_failure(self):
        """Crossover query returns None -> 'query_failed', not unhealthy."""
        client = _make_client({})
        results: dict = {}

        with patch(
            "heartbeat.checks.yesterday._get_midnight_crossover_tid",
            return_value=None,
        ):
            from heartbeat.checks.yesterday import collect_yesterday_completion

            collect_yesterday_completion(client, results)

        assert results["yesterday_BTCUSDT"] == "query_failed"
        # query_failed is not False, so yesterday_completion should be True
        assert results["yesterday_completion"] is True


class TestJunctionTelemetry:
    """Tests for collect_junction_telemetry (TELEM-03)."""

    def test_sidecar_health_available(self):
        """Sidecar health endpoint returns data -> junction populated."""
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "status": "running",
            "symbols": {
                "BTCUSDT": {
                    "rest_last_tid": 12345678,
                    "ws_first_tid": 12345679,
                    "forming_bar": "open=42000 trades=15",
                    "committed_floors": {"250": 12345677},
                }
            },
        }

        results: dict = {}

        with patch("heartbeat.checks.junction.requests.get", return_value=mock_response):
            from heartbeat.checks.junction import collect_junction_telemetry

            collect_junction_telemetry(results)

        assert results["junction_telemetry"] is True
        assert results["junction_rest_last_tid"] != "unavailable"
        assert results["junction_ws_first_tid"] != "unavailable"

    def test_sidecar_down(self):
        """Sidecar unavailable -> junction keys set to 'unavailable'."""
        import requests

        results: dict = {}

        with patch(
            "heartbeat.checks.junction.requests.get",
            side_effect=requests.ConnectionError("refused"),
        ):
            from heartbeat.checks.junction import collect_junction_telemetry

            collect_junction_telemetry(results)

        assert results["junction_telemetry"] is False
        assert results["junction_rest_last_tid"] == "unavailable"
        assert results["junction_ws_first_tid"] == "unavailable"
        assert results["junction_forming_bar"] == "unavailable"
        assert results["junction_committed_floors"] == "unavailable"
