"""S6: Observability i logi (CLI + API).

SCENARIUSZ: Pełny stos logowania i monitoringu.
"""
from __future__ import annotations

import pytest


class TestRingBufferLogs:
    """S6.1: Ring buffer zbiera logi z dekoratorów."""

    def test_logs_endpoint_returns_entries(self, authed_client):
        """Ring buffer dostępny przez API.

        MUSI:
        - Zwrócić listę logów
        - Każdy log ma: timestamp, level, source
        - Filtrowanie po level działa
        """
        r = authed_client.get("/observability/logs?limit=10")
        assert r.status_code == 200
        assert isinstance(r.json(), list)

    def test_logs_filtered_by_level(self, authed_client):
        """Filtrowanie po level.

        MUSI:
        - level=error → tylko errory
        - level=warning → tylko warningi
        """
        r = authed_client.get("/observability/logs?level=error&limit=50")
        assert r.status_code == 200
        for entry in r.json():
            assert entry.get("level") == "error"

    def test_logs_have_required_fields(self, authed_client):
        """Każdy log ma wymagane pola.

        MUSI:
        - timestamp: float
        - level: str
        - source: str
        """
        # Trigger some log entries by calling an endpoint
        authed_client.get("/dashboard/")

        r = authed_client.get("/observability/logs?limit=50")
        assert r.status_code == 200
        entries = r.json()
        for entry in entries:
            assert "timestamp" in entry
            assert "level" in entry
            assert "source" in entry

    def test_logs_limit_respected(self, authed_client):
        """Limit parameter ogranicza liczbę wyników.

        MUSI:
        - Zwrócić max N wpisów
        """
        r = authed_client.get("/observability/logs?limit=3")
        assert r.status_code == 200
        assert len(r.json()) <= 3


class TestHealthWatchdog:
    """S6.2: Watchdog wykrywa problemy."""

    def test_health_summary_structure(self, authed_client):
        """Health summary ma poprawną strukturę.

        MUSI:
        - active_issues: int
        - critical: int
        - warnings: int
        - recent: list
        """
        r = authed_client.get("/observability/health-summary")
        assert r.status_code == 200
        data = r.json()
        for key in ("active_issues", "critical", "warnings"):
            assert key in data
        assert isinstance(data.get("recent", []), list)

    def test_health_events_history(self, authed_client):
        """Historia zdarzeń zdrowia.

        MUSI:
        - Zwrócić listę HealthEvent
        - Każdy ma: severity, source, title, timestamp
        - Filtrowanie po severity działa
        """
        r = authed_client.get("/observability/health-events?limit=20")
        assert r.status_code == 200
        events = r.json()
        assert isinstance(events, list)
        for evt in events:
            assert "severity" in evt
            assert "source" in evt
            assert "title" in evt

    def test_health_events_severity_filter(self, authed_client):
        """Filtrowanie po severity.

        MUSI:
        - severity=critical → tylko critical
        """
        r = authed_client.get("/observability/health-events?severity=critical&limit=20")
        assert r.status_code == 200
        for evt in r.json():
            assert evt["severity"] == "critical"


class TestErrorSummary:
    """S6.3: Podsumowanie błędów."""

    def test_errors_endpoint_structure(self, authed_client):
        """Error summary ma poprawną strukturę.

        MUSI:
        - total_errors: int
        - total_logs: int
        - by_source: dict
        - recent_errors: list
        """
        r = authed_client.get("/observability/errors")
        assert r.status_code == 200
        data = r.json()
        assert isinstance(data["total_errors"], int)
        assert isinstance(data["total_logs"], int)
        assert isinstance(data["by_source"], dict)
        assert isinstance(data["recent_errors"], list)

    def test_errors_no_api_keys_leaked(self, authed_client):
        """Logi nie zawierają API keys.

        NIE MOŻE:
        - Zawierać "sk-" w logach
        - Zawierać "api_key" z wartością
        """
        r = authed_client.get("/observability/logs?limit=100")
        assert r.status_code == 200
        for entry in r.json():
            for val in entry.values():
                if isinstance(val, str):
                    assert "sk-ant-" not in val
                    assert "sk-or-" not in val
