"""PERF-006: RequestObservabilityMiddleware logs route/method/status/duration
per request, and DB query count/time for slow requests only when opted in."""
import logging

import pytest
from django.test import RequestFactory

from apps.core.middleware import RequestObservabilityMiddleware, _route_name


@pytest.fixture
def factory():
    return RequestFactory()


def _make_middleware(get_response, settings, slow_threshold_ms=1000, db_stats=False):
    settings.REQUEST_SLOW_THRESHOLD_MS = slow_threshold_ms
    settings.REQUEST_OBSERVABILITY_DB_STATS = db_stats
    return RequestObservabilityMiddleware(get_response)


class TestRequestObservabilityMiddleware:
    def test_logs_normal_request_at_info(self, factory, settings, caplog):
        mw = _make_middleware(lambda req: _FakeResponse(200), settings)
        request = factory.get("/api/projects/")
        with caplog.at_level(logging.INFO, logger="request_observability"):
            mw(request)
        assert any(r.message == "request" for r in caplog.records)
        assert not any(r.message == "slow_request" for r in caplog.records)

    def test_logs_slow_request_as_warning(self, factory, settings, caplog):
        import time

        def slow_response(req):
            time.sleep(0.02)
            return _FakeResponse(200)

        mw = _make_middleware(slow_response, settings, slow_threshold_ms=10)
        request = factory.get("/api/projects/")
        with caplog.at_level(logging.INFO, logger="request_observability"):
            mw(request)
        assert any(r.message == "slow_request" for r in caplog.records)

    def test_skips_static_and_media_paths(self, factory, settings, caplog):
        mw = _make_middleware(lambda req: _FakeResponse(200), settings)
        request = factory.get("/static/app.css")
        with caplog.at_level(logging.INFO, logger="request_observability"):
            mw(request)
        assert caplog.records == []

    def test_route_name_uses_resolver_match_not_raw_path(self, factory):
        request = factory.get("/api/projects/123e4567-e89b-12d3-a456-426614174000/")

        class FakeMatch:
            view_name = "project-detail"
            route = "api/projects/<uuid:pk>/"

        request.resolver_match = FakeMatch()
        assert _route_name(request) == "project-detail"

    def test_route_name_falls_back_when_unresolved(self, factory):
        request = factory.get("/nonexistent/")
        request.resolver_match = None
        assert _route_name(request) == "unresolved"

    def test_db_stats_opt_in_off_by_default(self, factory, settings, caplog):
        mw = _make_middleware(lambda req: _FakeResponse(200), settings, slow_threshold_ms=0, db_stats=False)
        request = factory.get("/api/projects/")
        with caplog.at_level(logging.WARNING, logger="request_observability"):
            mw(request)
        record = next(r for r in caplog.records if r.message == "slow_request")
        assert "db_query_count" not in record.request_fields

    @pytest.mark.django_db
    def test_db_stats_captured_when_opted_in(self, factory, settings, caplog):
        from apps.companies.models import Organization

        def response_with_query(req):
            list(Organization.objects.all())
            return _FakeResponse(200)

        mw = _make_middleware(response_with_query, settings, slow_threshold_ms=0, db_stats=True)
        request = factory.get("/api/projects/")
        with caplog.at_level(logging.WARNING, logger="request_observability"):
            mw(request)
        record = next(r for r in caplog.records if r.message == "slow_request")
        assert record.request_fields["db_query_count"] >= 1


class _FakeResponse:
    def __init__(self, status_code):
        self.status_code = status_code
