"""Tests for satpass event path — wire adapter names route correctly.

Verifies:
 - celestrak_tle envelope routes to tle_handler and inserts sat_tles row
 - n2yo_visualpasses envelope routes to satpass_handler
 - satpass_predict envelope routes to satpass_handler
 - adapter_config reads min_elevation (not min_elevation_deg)
 - CENTRAL_ADAPTER_TO_SOURCE maps wire names to 'satpass'
 - stale adapter names removed from dispatch
"""

import json
import time

import pytest


# ── Realistic wire envelopes ────────────────────────────────────────

CELESTRAK_TLE_ENVELOPE = {
    "specversion": "1.0",
    "id": "tle-25544-1718200000",
    "source": "central",
    "type": "central.sat.tle",
    "data": {
        "id": "tle-25544-1718200000",
        "adapter": "celestrak_tle",
        "category": "sat.tle",
        "data": {
            "norad_id": 25544,
            "satellite_name": "ISS (ZARYA)",
            "tle_line1": "1 25544U 98067A   26163.51782528  .00020000  00000-0  35000-3 0  9999",
            "tle_line2": "2 25544  51.6416 247.4627 0006703 130.5360 325.0288 15.49815002    17",
            "epoch": "2026-06-12T12:25:40Z",
        },
    },
}

N2YO_PASS_ENVELOPE = {
    "specversion": "1.0",
    "id": "pass-25544-twinfalls-1718300000",
    "source": "central",
    "type": "central.sat.pass",
    "data": {
        "id": "pass-25544-twinfalls-1718300000",
        "adapter": "n2yo_visualpasses",
        "category": "sat.pass",
        "data": {
            "norad_id": 25544,
            "sat_name": "ISS (ZARYA)",
            "observer": "Twin Falls",
            "max_elevation": 72.5,
            "aos": "2026-06-13T04:15:00Z",
            "los": "2026-06-13T04:21:30Z",
            "direction": "visible",
        },
    },
}

SATPASS_PREDICT_ENVELOPE = {
    "specversion": "1.0",
    "id": "pass-25544-boise-1718300500",
    "source": "central",
    "type": "central.sat.pass",
    "data": {
        "id": "pass-25544-boise-1718300500",
        "adapter": "satpass_predict",
        "category": "sat.pass",
        "data": {
            "norad_id": 25544,
            "sat_name": "ISS (ZARYA)",
            "observer": "Boise",
            "max_elevation": 45.0,
            "aos": "2026-06-13T04:20:00Z",
            "los": "2026-06-13T04:26:00Z",
            "direction": "visible",
        },
    },
}


def _enable_satpass():
    """Set satpass.enabled=true in the test DB."""
    from meshai.persistence import get_db
    from meshai.adapter_config import invalidate_cache
    conn = get_db()
    conn.execute(
        "UPDATE adapter_config SET value_json='true' "
        "WHERE adapter='satpass' AND key='enabled'"
    )
    invalidate_cache()


# ── CENTRAL_ADAPTER_TO_SOURCE mapping ───────────────────────────────

def test_adapter_to_source_celestrak_tle():
    from meshai.central.consumer import CENTRAL_ADAPTER_TO_SOURCE
    assert CENTRAL_ADAPTER_TO_SOURCE["celestrak_tle"] == "satpass"


def test_adapter_to_source_n2yo_visualpasses():
    from meshai.central.consumer import CENTRAL_ADAPTER_TO_SOURCE
    assert CENTRAL_ADAPTER_TO_SOURCE["n2yo_visualpasses"] == "satpass"


def test_adapter_to_source_satpass_predict():
    from meshai.central.consumer import CENTRAL_ADAPTER_TO_SOURCE
    assert CENTRAL_ADAPTER_TO_SOURCE["satpass_predict"] == "satpass"


def test_no_stale_sat_names_in_adapter_map():
    """Wire names sat_passes / sat_tles / sat_tle must NOT appear."""
    from meshai.central.consumer import CENTRAL_ADAPTER_TO_SOURCE
    for stale in ("sat_passes", "sat_tles", "sat_tle"):
        assert stale not in CENTRAL_ADAPTER_TO_SOURCE, (
            f"stale adapter name {stale!r} still in CENTRAL_ADAPTER_TO_SOURCE"
        )


# ── TLE handler route ──────────────────────────────────────────────

def test_tle_handler_inserts_sat_tles_row():
    """A celestrak_tle envelope must land a row in sat_tles."""
    from meshai.central.tle_handler import handle_tle
    from meshai.persistence import get_db

    _enable_satpass()

    # Reset the disabled-logged flag if set
    if hasattr(handle_tle, "_disabled_logged"):
        del handle_tle._disabled_logged

    result = handle_tle(
        CELESTRAK_TLE_ENVELOPE,
        "central.sat.tle.25544",
        now=int(time.time()),
    )

    # TLE handler always returns None (storage-only)
    assert result is None

    conn = get_db()
    row = conn.execute(
        "SELECT norad_id, name, line1, line2, epoch FROM sat_tles WHERE norad_id=25544"
    ).fetchone()
    assert row is not None, "TLE row not inserted into sat_tles"
    assert row["name"] == "ISS (ZARYA)"
    assert row["line1"].startswith("1 25544U")
    assert row["line2"].startswith("2 25544")
    assert row["epoch"] == "2026-06-12T12:25:40Z"


def test_tle_handler_drops_when_disabled():
    """When satpass.enabled=false, TLE handler drops and returns None."""
    from meshai.central.tle_handler import handle_tle
    from meshai.persistence import get_db

    # enabled=false is the default from conftest seed
    if hasattr(handle_tle, "_disabled_logged"):
        del handle_tle._disabled_logged

    result = handle_tle(
        CELESTRAK_TLE_ENVELOPE,
        "central.sat.tle.25544",
        now=int(time.time()),
    )
    assert result is None

    conn = get_db()
    row = conn.execute(
        "SELECT norad_id FROM sat_tles WHERE norad_id=25544"
    ).fetchone()
    assert row is None, "TLE row should NOT be inserted when disabled"


# ── Pass handler route ──────────────────────────────────────────────

def test_satpass_handler_accepts_n2yo_envelope():
    """n2yo_visualpasses must not be rejected by the adapter guard."""
    inner = N2YO_PASS_ENVELOPE["data"]
    adapter = inner.get("adapter")
    assert adapter == "n2yo_visualpasses"
    assert adapter in ("n2yo_visualpasses", "satpass_predict")


def test_satpass_handler_accepts_satpass_predict_envelope():
    """satpass_predict must not be rejected by the adapter guard."""
    inner = SATPASS_PREDICT_ENVELOPE["data"]
    adapter = inner.get("adapter")
    assert adapter == "satpass_predict"
    assert adapter in ("n2yo_visualpasses", "satpass_predict")


def test_satpass_handler_rejects_wrong_adapter():
    """An envelope with adapter='celestrak_tle' must be rejected."""
    from meshai.central.satpass_handler import handle_satpass
    if hasattr(handle_satpass, "_disabled_logged"):
        del handle_satpass._disabled_logged
    result = handle_satpass(CELESTRAK_TLE_ENVELOPE, "central.sat.tle.25544")
    assert result is None


# ── Config key consistency ──────────────────────────────────────────

def test_registry_has_min_elevation_not_deg():
    """The REGISTRY key must be 'min_elevation', not 'min_elevation_deg'."""
    from meshai.adapter_config.defaults import REGISTRY
    assert ("satpass", "min_elevation") in REGISTRY
    assert ("satpass", "min_elevation_deg") not in REGISTRY


def test_handler_reads_min_elevation():
    """satpass_handler must read cfg.min_elevation (matching REGISTRY key)."""
    import inspect
    from meshai.central import satpass_handler
    src = inspect.getsource(satpass_handler)
    assert "min_elevation" in src
    assert "min_elevation_deg" not in src


# ── Dispatch routing in consumer._normalize ─────────────────────────

def test_consumer_dispatch_celestrak_tle():
    """consumer._normalize dispatch must route celestrak_tle to tle_handler."""
    import inspect
    from meshai.central import consumer
    src = inspect.getsource(consumer)
    assert '"celestrak_tle"' in src
    assert '"sat_tles"' not in src
    assert '"sat_tle"' not in src


def test_consumer_dispatch_n2yo_and_satpass_predict():
    """consumer._normalize dispatch must route n2yo/satpass_predict to satpass_handler."""
    import inspect
    from meshai.central import consumer
    src = inspect.getsource(consumer)
    assert '"n2yo_visualpasses"' in src
    assert '"satpass_predict"' in src
    assert '"sat_passes"' not in src
