"""Tests for the Query API app structure and helper functions."""
from datetime import datetime, timezone

from services.api.app import _parse_jsonb, _row_to_dict, app

# --- _parse_jsonb ---

def test_parse_jsonb_dict():
    assert _parse_jsonb({"a": 1}) == {"a": 1}


def test_parse_jsonb_list():
    assert _parse_jsonb([1, 2]) == [1, 2]


def test_parse_jsonb_string():
    assert _parse_jsonb('{"x": 1}') == {"x": 1}


def test_parse_jsonb_list_string():
    assert _parse_jsonb('["a", "b"]') == ["a", "b"]


def test_parse_jsonb_none():
    assert _parse_jsonb(None) is None


def test_parse_jsonb_invalid_string():
    assert _parse_jsonb("not json") == "not json"


# --- _row_to_dict ---

class FakeRecord(dict):
    """Mimics asyncpg.Record enough for _row_to_dict."""
    def items(self):
        return super().items()


def test_row_to_dict_converts_datetime():
    dt = datetime(2026, 4, 11, 12, 0, 0, tzinfo=timezone.utc)
    row = FakeRecord({"created_at": dt, "name": "test"})
    result = _row_to_dict(row)
    assert result["created_at"] == dt.isoformat()
    assert result["name"] == "test"


def test_row_to_dict_passes_primitives():
    row = FakeRecord({"count": 42, "active": True, "label": "ok", "val": None})
    result = _row_to_dict(row)
    assert result == {"count": 42, "active": True, "label": "ok", "val": None}


# --- App structure ---

def test_app_has_expected_routes():
    paths = [route.path for route in app.routes]
    assert "/health" in paths
    assert "/api/companies" in paths
    assert "/api/companies/{company_id}" in paths
    assert "/api/documents" in paths
    assert "/api/documents/{document_id}" in paths
    assert "/api/trends" in paths
    assert "/api/trends/{trend_id}" in paths
    assert "/api/trends/{trend_id}/evidence" in paths
    assert "/api/recommendations" in paths
    assert "/api/recommendations/{recommendation_id}" in paths
    assert "/api/recommendations/{recommendation_id}/evidence" in paths
    assert "/api/orders" in paths
    assert "/api/orders/{order_id}" in paths
    assert "/api/positions" in paths
    assert "/api/audit/{entity_type}/{entity_id}" in paths


def test_app_has_admin_routes():
    paths = [route.path for route in app.routes]
    # Source health
    assert "/api/admin/sources/health" in paths
    assert "/api/admin/sources/{source_id}/runs" in paths
    assert "/api/admin/sources/{source_id}/toggle" in paths
    assert "/api/admin/sources/{source_id}/credibility" in paths
    # Symbol configs
    assert "/api/admin/companies/{company_id}/toggle" in paths
    assert "/api/admin/companies/{company_id}/sector" in paths
    assert "/api/admin/companies/coverage" in paths
    # Trading mode
    assert "/api/admin/trading/config" in paths
    assert "/api/admin/trading/mode" in paths
    assert "/api/admin/trading/approvals" in paths
    assert "/api/admin/trading/approvals/{approval_id}" in paths
    assert "/api/admin/trading/lockouts" in paths
    # Macro toggle
    assert "/api/admin/macro/status" in paths
    assert "/api/admin/macro/toggle" in paths


def test_app_has_macro_routes():
    paths = [route.path for route in app.routes]
    assert "/api/macro/events" in paths
    assert "/api/macro/events/{event_id}" in paths
    assert "/api/macro/impacts/{ticker}" in paths
    assert "/api/trends/{trend_id}/projection" in paths

def test_app_has_ops_dashboard_routes():
    paths = [route.path for route in app.routes]
    assert "/api/ops/ingestion/throughput" in paths
    assert "/api/ops/ingestion/summary" in paths
    assert "/api/ops/model/failures" in paths
    assert "/api/ops/model/performance" in paths
    assert "/api/ops/pipeline/health" in paths
    assert "/api/ops/sources/coverage-gaps" in paths
