"""Tests for curl debug output."""

from __future__ import annotations

import httpx
import pytest

from pinecone._internal.http.curl_debug import (
    format_curl_command,
    print_curl_debug,
    print_response_debug,
)


pytestmark = pytest.mark.unit


class TestFormatCurlCommand:
    """Test curl command formatting."""

    def test_get_request(self):
        """GET request produces valid curl with no -d flag."""
        headers = {"Api-Key": "sk-secret", "Content-Type": "application/json"}
        result = format_curl_command("GET", "https://api.pinecone.io/indexes", headers, None)

        assert result.startswith("curl -X GET 'https://api.pinecone.io/indexes'")
        assert "-d " not in result

    def test_post_request_with_body(self):
        """POST request includes -d flag with body."""
        headers = {"Api-Key": "sk-secret", "Content-Type": "application/json"}
        body = '{"name": "my-index"}'
        result = format_curl_command("POST", "https://api.pinecone.io/indexes", headers, body)

        assert "curl -X POST" in result
        assert '-d \'{"name": "my-index"}\'' in result

    def test_bytes_body_decoded(self):
        """Bytes body is decoded to utf-8 string."""
        headers = {"Content-Type": "application/json"}
        body = b'{"dimension": 1536}'
        result = format_curl_command("POST", "https://example.com", headers, body)

        assert "-d '{\"dimension\": 1536}'" in result

    def test_api_key_redacted(self):
        """Api-Key header value is replaced with $PINECONE_API_KEY."""
        headers = {"Api-Key": "my-super-secret-key", "Content-Type": "application/json"}
        result = format_curl_command("GET", "https://example.com", headers, None)

        assert "my-super-secret-key" not in result
        assert "$PINECONE_API_KEY" in result

    def test_api_key_redacted_case_insensitive(self):
        """Api-Key redaction works regardless of header case."""
        headers = {"api-key": "secret123"}
        result = format_curl_command("GET", "https://example.com", headers, None)

        assert "secret123" not in result
        assert "$PINECONE_API_KEY" in result

    def test_other_headers_preserved(self):
        """Non-sensitive headers appear with their original values."""
        headers = {
            "Content-Type": "application/json",
            "X-Custom": "my-value",
        }
        result = format_curl_command("GET", "https://example.com", headers, None)

        assert "-H 'Content-Type: application/json'" in result
        assert "-H 'X-Custom: my-value'" in result

    def test_multiline_formatting(self):
        """Command parts are joined with backslash-newline continuation."""
        headers = {"Content-Type": "application/json"}
        result = format_curl_command("GET", "https://example.com", headers, None)

        assert " \\\n" in result

    def test_delete_request_no_body(self):
        """DELETE request without body has no -d flag."""
        headers = {"Api-Key": "secret"}
        result = format_curl_command("DELETE", "https://example.com/idx", headers, None)

        assert "curl -X DELETE" in result
        assert "-d " not in result

    def test_single_quotes_escaped_in_body(self):
        """Single quotes in body are escaped for valid shell quoting."""
        headers = {"Content-Type": "application/json"}
        body = """{"name": "O'Brien"}"""
        result = format_curl_command("POST", "https://example.com", headers, body)

        assert "O'\\''Brien" in result

    def test_single_quotes_escaped_in_url(self):
        """Single quotes in URL are escaped for valid shell quoting."""
        headers = {}
        result = format_curl_command("GET", "https://example.com/q?name=O'Brien", headers, None)

        assert "O'\\''Brien" in result

    def test_single_quotes_escaped_in_header_value(self):
        """Single quotes in header values are escaped for valid shell quoting."""
        headers = {"X-Custom": "it's a test"}
        result = format_curl_command("GET", "https://example.com", headers, None)

        assert "it'\\''s a test" in result


class TestPrintCurlDebug:
    """Test curl debug printing to stderr."""

    def test_writes_to_stderr(self, capsys: pytest.CaptureFixture[str]):
        """print_curl_debug writes to stderr, not stdout."""
        headers = {"Content-Type": "application/json"}
        print_curl_debug("GET", "https://example.com", headers, None)

        captured = capsys.readouterr()
        assert captured.out == ""
        assert "curl -X GET" in captured.err

    def test_lines_prefixed_with_arrow(self, capsys: pytest.CaptureFixture[str]):
        """Each line of curl output is prefixed with '> '."""
        headers = {"Content-Type": "application/json"}
        print_curl_debug("GET", "https://example.com", headers, None)

        captured = capsys.readouterr()
        for line in captured.err.strip().splitlines():
            assert line.startswith("> ")


class TestPrintResponseDebug:
    """Test response debug printing to stderr."""

    def _make_response(
        self,
        status_code: int = 200,
        headers: dict[str, str] | None = None,
        text: str = "",
        http_version: str = "HTTP/1.1",
    ) -> httpx.Response:
        """Build an httpx.Response for testing."""
        resp = httpx.Response(
            status_code=status_code,
            headers=headers or {},
            text=text,
        )
        # Override http_version since httpx.Response doesn't accept it directly
        resp.extensions = {"http_version": http_version.encode()}
        return resp

    def test_writes_to_stderr(self, capsys: pytest.CaptureFixture[str]):
        """print_response_debug writes to stderr, not stdout."""
        resp = self._make_response(status_code=200, text='{"ok": true}')
        print_response_debug(resp)

        captured = capsys.readouterr()
        assert captured.out == ""
        assert "200" in captured.err

    def test_status_line(self, capsys: pytest.CaptureFixture[str]):
        """Status line includes protocol and status code."""
        resp = self._make_response(status_code=404, http_version="HTTP/1.1")
        print_response_debug(resp)

        captured = capsys.readouterr()
        assert "< HTTP/1.1 404" in captured.err

    def test_http2_protocol(self, capsys: pytest.CaptureFixture[str]):
        """HTTP/2 responses show HTTP/2 in status line."""
        resp = self._make_response(status_code=200, http_version="HTTP/2")
        print_response_debug(resp)

        captured = capsys.readouterr()
        assert "< HTTP/2 200" in captured.err

    def test_response_headers(self, capsys: pytest.CaptureFixture[str]):
        """Response headers are printed."""
        resp = self._make_response(
            status_code=200,
            headers={"content-type": "application/json", "x-request-id": "abc123"},
        )
        print_response_debug(resp)

        captured = capsys.readouterr()
        assert "< content-type: application/json" in captured.err
        assert "< x-request-id: abc123" in captured.err

    def test_response_body(self, capsys: pytest.CaptureFixture[str]):
        """Response body is printed."""
        resp = self._make_response(status_code=200, text='{"name": "my-index"}')
        print_response_debug(resp)

        captured = capsys.readouterr()
        assert '{"name": "my-index"}' in captured.err

    def test_empty_body(self, capsys: pytest.CaptureFixture[str]):
        """Empty response body does not print a body line."""
        resp = self._make_response(status_code=204, text="")
        print_response_debug(resp)

        captured = capsys.readouterr()
        lines = captured.err.strip().splitlines()
        # Should have status line but no body line
        assert any("204" in line for line in lines)


class TestCurlDebugEnabled:
    """Test the CURL_DEBUG_ENABLED flag."""

    def test_disabled_by_default(self):
        """CURL_DEBUG_ENABLED is False when env var is not set."""
        # The test environment should not have PINECONE_DEBUG_CURL set
        from pinecone._internal.http.curl_debug import CURL_DEBUG_ENABLED

        assert CURL_DEBUG_ENABLED is False
