"""PostgREST integration tests for api/db layer.

Validates that the db functions construct correct PostgREST URLs,
headers, and payloads without needing a real Supabase instance.
Mocks at the ``requests`` level to verify HTTP protocol correctness.
"""

from __future__ import annotations

import json
import urllib.parse
from unittest.mock import MagicMock, call, patch

import pytest
import requests

# ---------------------------------------------------------------------------
# Constants shared across tests
# ---------------------------------------------------------------------------
FAKE_SUPABASE_URL = "https://test-project.supabase.co"
FAKE_SERVICE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test-service-key"
FAKE_ORG_ID = "org_test456"
FAKE_PROJECT_ID = "proj_abc123"
FAKE_RUN_ID = "550e8400-e29b-41d4-a716-446655440000"
FAKE_SESSION_ID = "880e8400-e29b-41d4-a716-446655440000"


# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------
@pytest.fixture(autouse=True)
def _set_env(monkeypatch):
    """Inject Supabase env vars for every test in this module."""
    monkeypatch.setenv("SUPABASE_URL", FAKE_SUPABASE_URL)
    monkeypatch.setenv("SUPABASE_SERVICE_ROLE_KEY", FAKE_SERVICE_KEY)


def _ok_response(json_body=None, status_code=200, headers=None):
    """Build a mock ``requests.Response`` that looks like a successful reply."""
    resp = MagicMock(spec=requests.Response)
    resp.ok = True
    resp.status_code = status_code
    resp.json.return_value = json_body if json_body is not None else []
    resp.headers = headers or {}
    resp.reason = "OK"
    resp.url = ""
    return resp


def _error_response(status_code, reason="Error", body=None):
    """Build a mock ``requests.Response`` for an error."""
    resp = MagicMock(spec=requests.Response)
    resp.ok = False
    resp.status_code = status_code
    resp.reason = reason
    resp.url = f"{FAKE_SUPABASE_URL}/rest/v1/runs"
    resp.json.return_value = body or {"message": reason}
    resp.headers = {}
    resp.raise_for_status.side_effect = requests.exceptions.HTTPError(
        f"{status_code} {reason}", response=resp
    )
    return resp


# ===================================================================
# TestPostgRESTHelpers
# ===================================================================
class TestPostgRESTHelpers:
    """Tests for _supabase_url, _headers, _raise_for_status, _encode_filter_value, _parse_content_range_total."""

    def test_supabase_url_returns_trimmed(self, monkeypatch):
        """_supabase_url strips trailing slashes."""
        monkeypatch.setenv("SUPABASE_URL", "https://example.supabase.co/")
        from api.db.core import _supabase_url
        assert _supabase_url() == "https://example.supabase.co"

    def test_supabase_url_raises_when_missing(self, monkeypatch):
        """_supabase_url raises RuntimeError when env var is absent."""
        monkeypatch.delenv("SUPABASE_URL", raising=False)
        from api.db.core import _supabase_url
        with pytest.raises(RuntimeError, match="SUPABASE_URL not set"):
            _supabase_url()

    def test_headers_contains_required_keys(self):
        """_headers returns Authorization, apikey, Content-Type, Prefer."""
        from api.db.core import _headers
        h = _headers()
        assert h["Authorization"] == f"Bearer {FAKE_SERVICE_KEY}"
        assert h["apikey"] == FAKE_SERVICE_KEY
        assert h["Content-Type"] == "application/json"
        assert h["Prefer"] == "return=representation"

    def test_headers_raises_when_key_missing(self, monkeypatch):
        """_headers raises RuntimeError when service key is absent."""
        monkeypatch.delenv("SUPABASE_SERVICE_ROLE_KEY", raising=False)
        from api.db.core import _headers
        with pytest.raises(RuntimeError, match="SUPABASE_SERVICE_ROLE_KEY not set"):
            _headers()

    def test_raise_for_status_noop_on_success(self):
        """_raise_for_status does nothing on 2xx responses."""
        from api.db.core import _raise_for_status
        resp = _ok_response()
        _raise_for_status(resp)  # should not raise

    def test_raise_for_status_retryable_on_500(self):
        """_raise_for_status raises RetryableHTTPError for 500."""
        from api.db.core import RetryableHTTPError, _raise_for_status
        resp = _error_response(500, "Internal Server Error")
        with pytest.raises(RetryableHTTPError):
            _raise_for_status(resp)

    def test_raise_for_status_retryable_on_429(self):
        """_raise_for_status raises RetryableHTTPError for 429 rate limit."""
        from api.db.core import RetryableHTTPError, _raise_for_status
        resp = _error_response(429, "Too Many Requests")
        with pytest.raises(RetryableHTTPError):
            _raise_for_status(resp)

    def test_raise_for_status_non_retryable_on_400(self):
        """_raise_for_status raises plain HTTPError for 4xx (not 429)."""
        from api.db.core import RetryableHTTPError, _raise_for_status
        resp = _error_response(400, "Bad Request")
        with pytest.raises(requests.exceptions.HTTPError):
            _raise_for_status(resp)
        # Ensure it is NOT a RetryableHTTPError
        try:
            _raise_for_status(resp)
        except RetryableHTTPError:
            pytest.fail("400 should not be retryable")
        except requests.exceptions.HTTPError:
            pass

    def test_encode_filter_value_encodes_specials(self):
        """_encode_filter_value URL-encodes dangerous characters."""
        from api.db.core import _encode_filter_value
        assert _encode_filter_value("hello world") == "hello%20world"
        assert _encode_filter_value("eq.foo") == "eq.foo"
        # Parentheses, commas
        assert _encode_filter_value("a,b") == "a%2Cb"

    def test_parse_content_range_normal(self):
        """_parse_content_range_total parses '0-19/150'."""
        from api.db.core import _parse_content_range_total
        assert _parse_content_range_total("0-19/150") == 150

    def test_parse_content_range_star_total(self):
        """_parse_content_range_total returns 0 for unknown total '*/*'."""
        from api.db.core import _parse_content_range_total
        assert _parse_content_range_total("*/*") == 0

    def test_parse_content_range_empty(self):
        """_parse_content_range_total returns 0 for empty/None."""
        from api.db.core import _parse_content_range_total
        assert _parse_content_range_total("") == 0
        assert _parse_content_range_total(None) == 0

    def test_parse_content_range_star_slash_number(self):
        """_parse_content_range_total parses '*/42'."""
        from api.db.core import _parse_content_range_total
        assert _parse_content_range_total("*/42") == 42


# ===================================================================
# TestRunOperations
# ===================================================================
class TestRunOperations:
    """Verify run CRUD constructs correct PostgREST requests."""

    @patch("api.db.runs.requests.post")
    def test_create_run_url_and_payload(self, mock_post):
        """create_run POSTs to /rest/v1/runs with correct payload."""
        mock_post.return_value = _ok_response(status_code=201)

        from api.db.runs import create_run
        create_run(
            run_id=FAKE_RUN_ID,
            org_id=FAKE_ORG_ID,
            project_id=FAKE_PROJECT_ID,
            entry_cmd={"command": "pytest", "args": ["-v"]},
            env_fingerprint={"python_version": "3.11"},
            trace_id="trace_xyz",
            test_name="test_example",
        )

        mock_post.assert_called_once()
        args, kwargs = mock_post.call_args
        url = args[0] if args else kwargs.get("url", "")

        # URL must target the runs table
        assert url == f"{FAKE_SUPABASE_URL}/rest/v1/runs"

        # Payload includes all fields
        payload = kwargs["json"]
        assert payload["id"] == FAKE_RUN_ID
        assert payload["org_id"] == FAKE_ORG_ID
        assert payload["status"] == "CREATED"
        assert payload["entry_cmd"]["command"] == "pytest"
        assert payload["trace_id"] == "trace_xyz"
        assert payload["test_name"] == "test_example"

        # Headers must contain auth
        headers = kwargs["headers"]
        assert headers["Authorization"].startswith("Bearer ")
        assert headers["apikey"] == FAKE_SERVICE_KEY

    @patch("api.db.runs.requests.get")
    def test_get_run_url_pattern(self, mock_get):
        """get_run uses eq. filter and select columns."""
        mock_get.return_value = _ok_response([{"id": FAKE_RUN_ID, "status": "FAILED"}])

        from api.db.runs import get_run
        result = get_run(FAKE_RUN_ID)

        mock_get.assert_called_once()
        url = mock_get.call_args[0][0]

        assert "/rest/v1/runs?" in url
        assert f"id=eq.{FAKE_RUN_ID}" in url
        assert "select=" in url
        assert result["id"] == FAKE_RUN_ID

    @patch("api.db.runs.requests.get")
    def test_get_run_returns_none_when_empty(self, mock_get):
        """get_run returns None when PostgREST returns empty array."""
        mock_get.return_value = _ok_response([])

        from api.db.runs import get_run
        assert get_run("nonexistent") is None

    @patch("api.db.runs.requests.patch")
    def test_set_run_status_validates_status(self, mock_patch):
        """set_run_status rejects invalid statuses before making HTTP call."""
        from api.db.runs import set_run_status
        with pytest.raises(ValueError, match="Invalid run status"):
            set_run_status(FAKE_RUN_ID, "BANANA")
        mock_patch.assert_not_called()

    @patch("api.db.runs.requests.patch")
    def test_set_run_status_url_and_body(self, mock_patch):
        """set_run_status PATCHes with eq. filter and status body."""
        mock_patch.return_value = _ok_response()

        from api.db.runs import set_run_status
        set_run_status(FAKE_RUN_ID, "PASSED")

        url = mock_patch.call_args[0][0]
        assert f"id=eq.{FAKE_RUN_ID}" in url
        assert mock_patch.call_args[1]["json"] == {"status": "PASSED"}

    @patch("api.db.runs.requests.patch")
    def test_finalize_run_exit_code_zero_completed(self, mock_patch):
        """finalize_run with exit_code=0 sets status to COMPLETED."""
        mock_patch.return_value = _ok_response()

        from api.db.runs import finalize_run
        finalize_run(FAKE_RUN_ID, duration=12.5, exit_code=0, io_count=42)

        payload = mock_patch.call_args[1]["json"]
        assert payload["status"] == "COMPLETED"
        assert payload["duration"] == 12.5
        assert payload["io_count"] == 42

    @patch("api.db.runs.requests.patch")
    def test_finalize_run_nonzero_exit_code_failed(self, mock_patch):
        """finalize_run with exit_code=1 sets status to FAILED."""
        mock_patch.return_value = _ok_response()

        from api.db.runs import finalize_run
        finalize_run(FAKE_RUN_ID, duration=5.0, exit_code=1)

        payload = mock_patch.call_args[1]["json"]
        assert payload["status"] == "FAILED"

    @patch("api.db.runs.requests.get")
    def test_list_runs_pagination_headers(self, mock_get):
        """list_runs sets Range header and Prefer: count=exact."""
        mock_get.return_value = _ok_response(
            json_body=[{"id": "r1", "status": "PASSED", "entry_cmd": {}, "created_at": "2025-01-01T00:00:00Z"}],
            headers={"Content-Range": "0-19/1"},
        )

        from api.db.runs import list_runs
        result = list_runs(FAKE_ORG_ID, page=2, per_page=10)

        headers = mock_get.call_args[1]["headers"]
        # page 2, per_page 10 -> offset 10, so Range: 10-19
        assert headers["Range"] == "10-19"
        assert headers["Prefer"] == "count=exact"

        url = mock_get.call_args[0][0]
        assert f"org_id=eq.{FAKE_ORG_ID}" in url
        assert "order=created_at.desc" in url
        assert result["total"] == 1

    @patch("api.db.runs.requests.get")
    def test_list_runs_with_search_uses_ilike(self, mock_get):
        """list_runs passes search term through ilike filter."""
        mock_get.return_value = _ok_response(
            json_body=[],
            headers={"Content-Range": "*/0"},
        )

        from api.db.runs import list_runs
        list_runs(FAKE_ORG_ID, search="test_login")

        url = mock_get.call_args[0][0]
        assert "ilike" in url
        assert "test_login" in url

    @patch("api.db.runs.requests.get")
    def test_get_runs_by_ids_in_filter(self, mock_get):
        """get_runs_by_ids uses PostgREST in.() filter syntax."""
        mock_get.return_value = _ok_response([
            {"id": "r1", "created_at": "2025-01-01T00:00:00Z"},
            {"id": "r2", "created_at": "2025-01-02T00:00:00Z"},
        ])

        from api.db.runs import get_runs_by_ids
        result = get_runs_by_ids(["r1", "r2"])

        url = mock_get.call_args[0][0]
        assert "id=in.(" in url
        assert "r1" in url
        assert "r2" in url
        assert len(result) == 2

    def test_get_runs_by_ids_empty_list(self):
        """get_runs_by_ids returns [] immediately for empty input."""
        from api.db.runs import get_runs_by_ids
        assert get_runs_by_ids([]) == []

    @patch("api.db.runs.requests.post")
    @patch("api.db.runs.requests.get")
    def test_store_root_cause_analysis_upsert_header(self, mock_get, mock_post):
        """store_root_cause_analysis sets Prefer: resolution=merge-duplicates."""
        mock_get.return_value = _ok_response([{"id": FAKE_RUN_ID, "org_id": FAKE_ORG_ID}])
        mock_post.return_value = _ok_response(status_code=201)

        from api.db.runs import store_root_cause_analysis
        store_root_cause_analysis(FAKE_RUN_ID, {
            "summary": "Race condition in setup",
            "confidence": 0.9,
            "category": "concurrency",
        })

        post_headers = mock_post.call_args[1]["headers"]
        assert post_headers["Prefer"] == "resolution=merge-duplicates"

        post_url = mock_post.call_args[0][0]
        assert "/rest/v1/root_cause_analyses" in post_url


# ===================================================================
# TestSessionOperations
# ===================================================================
class TestSessionOperations:
    """Verify session CRUD constructs correct PostgREST requests."""

    @patch("api.db.sessions.requests.post")
    def test_create_session_url_and_payload(self, mock_post):
        """create_session POSTs to /rest/v1/sessions."""
        mock_post.return_value = _ok_response(status_code=201)

        from api.db.sessions import create_session
        create_session(
            session_id=FAKE_SESSION_ID,
            org_id=FAKE_ORG_ID,
            project_id=FAKE_PROJECT_ID,
            metadata={"browser": "chrome"},
            trace_id="trace_999",
        )

        url = mock_post.call_args[0][0]
        assert url == f"{FAKE_SUPABASE_URL}/rest/v1/sessions"

        payload = mock_post.call_args[1]["json"]
        assert payload["id"] == FAKE_SESSION_ID
        assert payload["status"] == "RECORDING"
        assert payload["metadata"]["browser"] == "chrome"
        assert payload["trace_id"] == "trace_999"

    @patch("api.db.sessions.requests.get")
    def test_get_session_eq_filter(self, mock_get):
        """get_session uses eq. filter on id."""
        mock_get.return_value = _ok_response([{"id": FAKE_SESSION_ID, "status": "FINALIZED"}])

        from api.db.sessions import get_session
        result = get_session(FAKE_SESSION_ID)

        url = mock_get.call_args[0][0]
        assert f"id=eq.{FAKE_SESSION_ID}" in url
        assert "select=*" in url
        assert result["status"] == "FINALIZED"

    @patch("api.db.sessions.requests.patch")
    def test_finalize_session_patch(self, mock_patch):
        """finalize_session PATCHes status and ended_at."""
        mock_patch.return_value = _ok_response()

        from api.db.sessions import finalize_session
        finalize_session(FAKE_SESSION_ID)

        url = mock_patch.call_args[0][0]
        assert f"id=eq.{FAKE_SESSION_ID}" in url

        payload = mock_patch.call_args[1]["json"]
        assert payload["status"] == "FINALIZED"
        assert "ended_at" in payload

    @patch("api.db.sessions.requests.get")
    def test_list_sessions_pagination(self, mock_get):
        """list_sessions sets Range and Prefer: count=exact headers."""
        mock_get.return_value = _ok_response(
            json_body=[{"id": "s1"}],
            headers={"Content-Range": "0-19/35"},
        )

        from api.db.sessions import list_sessions
        result = list_sessions(FAKE_ORG_ID, page=1, per_page=20)

        headers = mock_get.call_args[1]["headers"]
        assert headers["Range"] == "0-19"
        assert headers["Prefer"] == "count=exact"
        assert result["total"] == 35

    @patch("api.db.sessions.requests.get")
    def test_list_sessions_with_status_filter(self, mock_get):
        """list_sessions applies status=eq. filter."""
        mock_get.return_value = _ok_response(
            json_body=[],
            headers={"Content-Range": "*/0"},
        )

        from api.db.sessions import list_sessions
        list_sessions(FAKE_ORG_ID, status="RECORDING")

        url = mock_get.call_args[0][0]
        assert "status=eq.RECORDING" in url

    @patch("api.db.sessions.requests.delete")
    def test_delete_session(self, mock_delete):
        """delete_session sends DELETE with eq. filter."""
        mock_delete.return_value = _ok_response()

        from api.db.sessions import delete_session
        delete_session(FAKE_SESSION_ID)

        url = mock_delete.call_args[0][0]
        assert f"id=eq.{FAKE_SESSION_ID}" in url
        assert mock_delete.call_args[1].get("timeout") == 10

    @patch("api.db.sessions.requests.delete")
    def test_delete_sessions_before_uses_lt_filter(self, mock_delete):
        """delete_sessions_before uses lt. operator on ended_at."""
        mock_delete.return_value = _ok_response()

        from api.db.sessions import delete_sessions_before
        cutoff = "2025-01-01T00:00:00Z"
        delete_sessions_before(FAKE_ORG_ID, cutoff)

        url = mock_delete.call_args[0][0]
        assert f"org_id=eq.{urllib.parse.quote(FAKE_ORG_ID, safe='')}" in url
        assert "ended_at=lt." in url

    @patch("api.db.sessions.requests.post")
    def test_insert_session_chunk(self, mock_post):
        """insert_session_chunk POSTs to /rest/v1/session_chunks."""
        mock_post.return_value = _ok_response(status_code=201)

        from api.db.sessions import insert_session_chunk
        chunk = {"chunk_id": "c1", "stream": "dom", "byte_size": 1024}
        insert_session_chunk(FAKE_SESSION_ID, chunk)

        url = mock_post.call_args[0][0]
        assert "/rest/v1/session_chunks" in url

        payload = mock_post.call_args[1]["json"]
        assert payload["session_id"] == FAKE_SESSION_ID
        assert payload["chunk_id"] == "c1"


# ===================================================================
# TestFilterEncoding
# ===================================================================
class TestFilterEncoding:
    """Verify special characters and potential injection are encoded."""

    def test_spaces_are_encoded(self):
        from api.db.core import _encode_filter_value
        assert "%20" in _encode_filter_value("hello world")

    def test_semicolons_are_encoded(self):
        from api.db.core import _encode_filter_value
        encoded = _encode_filter_value("foo;DROP TABLE runs")
        assert ";" not in encoded
        assert "%3B" in encoded

    def test_ampersand_is_encoded(self):
        from api.db.core import _encode_filter_value
        encoded = _encode_filter_value("a&b=c")
        assert "&" not in encoded
        assert "%26" in encoded

    def test_parentheses_are_encoded(self):
        from api.db.core import _encode_filter_value
        encoded = _encode_filter_value("in.(evil)")
        assert "(" not in encoded
        assert ")" not in encoded

    def test_unicode_is_encoded(self):
        from api.db.core import _encode_filter_value
        encoded = _encode_filter_value("test\u00e9")
        # Should be percent-encoded
        assert "%" in encoded

    @patch("api.db.runs.requests.get")
    def test_run_id_with_specials_is_encoded_in_url(self, mock_get):
        """get_run encodes special characters in the run_id filter."""
        mock_get.return_value = _ok_response([])

        from api.db.runs import get_run
        # Attempt an ID with query manipulation chars
        get_run("abc&status=eq.PASSED")

        url = mock_get.call_args[0][0]
        # The ampersand must be encoded so it doesn't create a new query param
        assert "abc%26status%3Deq.PASSED" in url


# ===================================================================
# TestPaginationParsing
# ===================================================================
class TestPaginationParsing:
    """Verify Content-Range header parsing for various PostgREST formats."""

    def test_standard_range(self):
        from api.db.core import _parse_content_range_total
        assert _parse_content_range_total("0-9/100") == 100

    def test_large_total(self):
        from api.db.core import _parse_content_range_total
        assert _parse_content_range_total("0-99/123456") == 123456

    def test_star_range_with_total(self):
        from api.db.core import _parse_content_range_total
        assert _parse_content_range_total("*/500") == 500

    def test_star_star(self):
        from api.db.core import _parse_content_range_total
        assert _parse_content_range_total("*/*") == 0

    def test_malformed_no_slash(self):
        from api.db.core import _parse_content_range_total
        assert _parse_content_range_total("garbage") == 0

    def test_malformed_non_numeric_total(self):
        from api.db.core import _parse_content_range_total
        assert _parse_content_range_total("0-9/abc") == 0

    def test_none_input(self):
        from api.db.core import _parse_content_range_total
        assert _parse_content_range_total(None) == 0


# ===================================================================
# TestErrorHandling
# ===================================================================
class TestErrorHandling:
    """Verify error handling for various HTTP failure modes."""

    @patch("api.db.runs.requests.get")
    def test_get_run_propagates_404(self, mock_get):
        """get_run raises HTTPError on 404."""
        mock_get.return_value = _error_response(404, "Not Found")

        from api.db.runs import get_run
        with pytest.raises(requests.exceptions.HTTPError):
            get_run(FAKE_RUN_ID)

    @patch("api.db.runs.requests.post")
    def test_create_run_propagates_409_conflict(self, mock_post):
        """create_run raises HTTPError on 409 Conflict (duplicate key)."""
        mock_post.return_value = _error_response(409, "Conflict")

        from api.db.runs import create_run
        with pytest.raises(requests.exceptions.HTTPError):
            create_run(
                run_id=FAKE_RUN_ID,
                org_id=FAKE_ORG_ID,
                project_id=FAKE_PROJECT_ID,
                entry_cmd={},
                env_fingerprint={},
            )

    @patch("api.db.runs.requests.patch")
    def test_set_run_processing_propagates_500(self, mock_patch):
        """set_run_processing raises RetryableHTTPError on 500."""
        mock_patch.return_value = _error_response(500, "Internal Server Error")

        from api.db.core import RetryableHTTPError
        from api.db.runs import set_run_processing

        with pytest.raises(RetryableHTTPError):
            set_run_processing(FAKE_RUN_ID)

    @patch("api.db.sessions.requests.get")
    def test_get_session_stats_handles_server_error(self, mock_get):
        """get_session_stats surfaces 500 errors from individual status queries."""
        mock_get.return_value = _error_response(500, "Server Error")

        from api.db.core import RetryableHTTPError
        from api.db.sessions import get_session_stats

        with pytest.raises(RetryableHTTPError):
            get_session_stats(FAKE_ORG_ID)

    @patch("api.db.sessions.requests.get")
    def test_list_session_chunks_returns_ordered_data(self, mock_get):
        """list_session_chunks requests order=created_at.asc."""
        mock_get.return_value = _ok_response([
            {"chunk_id": "c1", "stream": "dom"},
            {"chunk_id": "c2", "stream": "net"},
        ])

        from api.db.sessions import list_session_chunks
        result = list_session_chunks(FAKE_SESSION_ID)

        url = mock_get.call_args[0][0]
        assert "order=created_at.asc" in url
        assert len(result) == 2

    @patch("api.db.runs.requests.get")
    def test_search_runs_builds_correct_filters(self, mock_get):
        """search_runs passes org_id, status, and since filters."""
        mock_get.return_value = _ok_response([{
            "id": "r1",
            "test_name": "test_login",
            "status": "FAILED",
            "error_type": "AssertionError",
            "error_message": "expected True",
            "error_file": "test_auth.py",
            "error_line": 42,
            "created_at": "2025-01-01T00:00:00Z",
            "duration_ms": 500,
            "determinism_score": 0.8,
        }])

        from api.db.runs import search_runs
        results = search_runs(
            org_id=FAKE_ORG_ID,
            status="failed",
            since="2025-01-01T00:00:00Z",
            limit=10,
        )

        url = mock_get.call_args[0][0]
        assert f"org_id=eq.{FAKE_ORG_ID}" in url
        assert "status=eq.FAILED" in url
        assert "created_at=gte." in url
        assert "limit=10" in url
        assert len(results) == 1
        # Verify divergence_count is computed from determinism_score
        # int((1 - 0.8) * 10) == 1 due to floating-point: 1-0.8 = 0.1999...
        assert results[0]["divergence_count"] == 1

    @patch("api.db.runs.requests.get")
    def test_get_comparable_runs_uses_neq(self, mock_get):
        """get_comparable_runs excludes the current run via neq. filter."""
        mock_get.return_value = _ok_response([
            {"id": "other_run", "status": "PASSED", "created_at": "2025-01-01", "test_name": "test_x"}
        ])

        from api.db.runs import get_comparable_runs
        results = get_comparable_runs(
            project_id=FAKE_PROJECT_ID,
            test_id="test_abc",
            exclude_run_id=FAKE_RUN_ID,
            opposite_status="FAILED",
            limit=5,
        )

        url = mock_get.call_args[0][0]
        assert f"id=neq.{FAKE_RUN_ID}" in url
        assert "status=eq.PASSED" in url
        assert "limit=5" in url
        assert len(results) == 1
