"""Unit tests for validation utilities."""

import pytest

from pinecone._internal.validation import (
    require_in_range,
    require_non_empty,
)


pytestmark = pytest.mark.unit


class TestRequireNonEmpty:
    """Tests for require_non_empty validation utility."""

    def test_non_empty_string_passes(self):
        """Test that non-empty string passes validation."""
        require_non_empty("model", "multilingual-e5-large")  # Should not raise

    def test_non_empty_list_passes(self):
        """Test that non-empty list passes validation."""
        require_non_empty("texts", ["Hello", "World"])  # Should not raise

    def test_empty_string_raises_error(self):
        """Test that empty string raises ValueError."""
        with pytest.raises(ValueError) as exc_info:
            require_non_empty("model", "")

        assert "model" in str(exc_info.value)
        assert "non-empty string" in str(exc_info.value)

    def test_empty_list_raises_error(self):
        """Test that empty list raises ValueError."""
        with pytest.raises(ValueError) as exc_info:
            require_non_empty("texts", [])

        assert "texts" in str(exc_info.value)
        assert "non-empty list" in str(exc_info.value)

    def test_none_raises_error(self):
        """Test that None raises ValueError."""
        with pytest.raises(ValueError) as exc_info:
            require_non_empty("query", None)

        assert "query" in str(exc_info.value)
        assert "required" in str(exc_info.value)

    def test_single_char_string_passes(self):
        """Test that single character string passes validation."""
        require_non_empty("text", "a")  # Should not raise

    def test_single_item_list_passes(self):
        """Test that single-item list passes validation."""
        require_non_empty("items", [1])  # Should not raise

    def test_whitespace_string_passes(self):
        """Test that string with only whitespace passes (not our job to trim)."""
        require_non_empty("text", "   ")  # Should not raise


class TestRequireInRange:
    """Tests for require_in_range validation utility."""

    def test_value_in_range_passes(self):
        """Test that value within range passes validation."""
        require_in_range("top_n", 5, 1, 10)  # Should not raise

    def test_value_at_min_boundary_passes(self):
        """Test that value at minimum boundary passes validation."""
        require_in_range("top_n", 1, 1, 10)  # Should not raise

    def test_value_at_max_boundary_passes(self):
        """Test that value at maximum boundary passes validation."""
        require_in_range("top_n", 10, 1, 10)  # Should not raise

    def test_value_below_min_raises_error(self):
        """Test that value below minimum raises ValueError."""
        with pytest.raises(ValueError) as exc_info:
            require_in_range("top_n", 0, 1, 10)

        assert "top_n" in str(exc_info.value)
        assert "between 1 and 10" in str(exc_info.value)
        assert "0" in str(exc_info.value)

    def test_value_above_max_raises_error(self):
        """Test that value above maximum raises ValueError."""
        with pytest.raises(ValueError) as exc_info:
            require_in_range("top_n", 11, 1, 10)

        assert "top_n" in str(exc_info.value)
        assert "between 1 and 10" in str(exc_info.value)
        assert "11" in str(exc_info.value)

    def test_none_always_passes(self):
        """Test that None always passes (for optional parameters)."""
        require_in_range("top_n", None, 1, 10)  # Should not raise

    def test_single_value_range_passes(self):
        """Test that value in single-value range passes."""
        require_in_range("exact", 5, 5, 5)  # Should not raise

    def test_negative_range_works(self):
        """Test that negative ranges work correctly."""
        require_in_range("offset", -5, -10, 0)  # Should not raise

    def test_value_below_negative_range_raises_error(self):
        """Test that value below negative range raises ValueError."""
        with pytest.raises(ValueError) as exc_info:
            require_in_range("offset", -11, -10, 0)

        assert "offset" in str(exc_info.value)
        assert "between -10 and 0" in str(exc_info.value)


class TestValidationIntegration:
    """Integration tests showing typical usage patterns."""

    def test_validate_embed_parameters(self):
        """Test validation pattern used in embed method."""
        model = "multilingual-e5-large"
        texts = ["Hello", "World"]

        # Should not raise
        require_non_empty("model", model)
        require_non_empty("texts", texts)

    def test_validate_rerank_parameters(self):
        """Test validation pattern used in rerank method."""
        model = "bge-reranker-v2-m3"
        query = "What is AI?"
        documents = ["AI is...", "ML is...", "DL is..."]
        top_n = 2

        # Should not raise
        require_non_empty("model", model)
        require_non_empty("query", query)
        require_non_empty("documents", documents)
        require_in_range("top_n", top_n, 1, len(documents))

    def test_validate_rerank_with_invalid_top_n(self):
        """Test validation catches invalid top_n in rerank."""
        documents = ["Doc 1", "Doc 2"]

        with pytest.raises(ValueError) as exc_info:
            require_in_range("top_n", 5, 1, len(documents))

        assert "top_n" in str(exc_info.value)
        assert "between 1 and 2" in str(exc_info.value)
