"""Tests for LengthCheck."""

from __future__ import annotations

import pytest

from ai_qa.checks.length import LengthCheck
from ai_qa.core.context import Context


def test_length_check_requires_bounds():
    """Test that LengthCheck requires at least min or max length."""
    with pytest.raises(ValueError) as exc_info:
        LengthCheck()
    assert "min_length" in str(exc_info.value) or "max_length" in str(exc_info.value)


def test_length_check_min_max_order():
    """Test that min_length <= max_length."""
    with pytest.raises(ValueError) as exc_info:
        LengthCheck(min_length=10, max_length=5)
    assert "cannot be greater" in str(exc_info.value).lower()


def test_length_check_string_within_min():
    """Test LengthCheck with string length within minimum."""
    check = LengthCheck(min_length=5)
    ctx = Context(output="hello world")
    result = check.evaluate(ctx)
    assert result.passed is True
    assert result.score == 1.0


def test_length_check_string_below_min():
    """Test LengthCheck with string length below minimum."""
    check = LengthCheck(min_length=10)
    ctx = Context(output="hello")
    result = check.evaluate(ctx)
    assert result.passed is False
    assert result.score == 0.0
    assert "below minimum" in result.evidence.lower()


def test_length_check_string_within_max():
    """Test LengthCheck with string length within maximum."""
    check = LengthCheck(max_length=20)
    ctx = Context(output="hello")
    result = check.evaluate(ctx)
    assert result.passed is True


def test_length_check_string_exceeds_max():
    """Test LengthCheck with string length exceeding maximum."""
    check = LengthCheck(max_length=5)
    ctx = Context(output="hello world")
    result = check.evaluate(ctx)
    assert result.passed is False
    assert result.score == 0.0
    assert "exceeds maximum" in result.evidence.lower()


def test_length_check_string_within_range():
    """Test LengthCheck with string length within range."""
    check = LengthCheck(min_length=5, max_length=20)
    ctx = Context(output="hello world")
    result = check.evaluate(ctx)
    assert result.passed is True


def test_length_check_exact_min():
    """Test LengthCheck with string length exactly at minimum."""
    check = LengthCheck(min_length=5)
    ctx = Context(output="hello")  # Exactly 5 characters
    result = check.evaluate(ctx)
    assert result.passed is True


def test_length_check_exact_max():
    """Test LengthCheck with string length exactly at maximum."""
    check = LengthCheck(max_length=5)
    ctx = Context(output="hello")  # Exactly 5 characters
    result = check.evaluate(ctx)
    assert result.passed is True


def test_length_check_dict_length():
    """Test LengthCheck with dict (measures number of keys)."""
    check = LengthCheck(min_length=2, max_length=4)
    ctx = Context(output={"a": 1, "b": 2, "c": 3})  # 3 keys
    result = check.evaluate(ctx)
    assert result.passed is True


def test_length_check_list_length():
    """Test LengthCheck with list (measures number of items)."""
    check = LengthCheck(min_length=2, max_length=5)
    ctx = Context(output=[1, 2, 3])  # 3 items
    result = check.evaluate(ctx)
    assert result.passed is True


def test_length_check_empty_dict():
    """Test LengthCheck with empty dict."""
    check = LengthCheck(min_length=1)
    ctx = Context(output={})  # 0 keys
    result = check.evaluate(ctx)
    assert result.passed is False


def test_length_check_empty_list():
    """Test LengthCheck with empty list."""
    check = LengthCheck(min_length=1)
    ctx = Context(output=[])  # 0 items
    result = check.evaluate(ctx)
    assert result.passed is False


def test_length_check_empty_string():
    """Test LengthCheck with empty string."""
    check = LengthCheck(min_length=1)
    ctx = Context(output="")  # 0 characters
    result = check.evaluate(ctx)
    assert result.passed is False




def test_length_check_unicode_string():
    """Test LengthCheck with unicode string."""
    check = LengthCheck(min_length=3, max_length=10)
    ctx = Context(output="café")  # 4 characters including accent
    result = check.evaluate(ctx)
    assert result.passed is True


def test_length_check_evidence_includes_length():
    """Test that evidence includes the actual length."""
    check = LengthCheck(min_length=5, max_length=20)
    ctx = Context(output="hello")
    result = check.evaluate(ctx)
    assert "5" in result.evidence


def test_length_check_custom_threshold():
    """Test LengthCheck with custom threshold."""
    check = LengthCheck(min_length=1, threshold=0.8)
    assert check.threshold == 0.8


def test_length_check_version():
    """Test LengthCheck has correct version."""
    check = LengthCheck(min_length=1)
    assert check.version == "1.0.0"


def test_length_check_name():
    """Test LengthCheck has correct name."""
    check = LengthCheck(min_length=1)
    assert check.name == "length"


def test_length_check_requires_llm():
    """Test LengthCheck does not require LLM."""
    check = LengthCheck(min_length=1)
    assert check.requires_llm is False


def test_length_check_min_only():
    """Test LengthCheck with only minimum length."""
    check = LengthCheck(min_length=5)
    assert check.min_length == 5
    assert check.max_length == -1


def test_length_check_max_only():
    """Test LengthCheck with only maximum length."""
    check = LengthCheck(max_length=20)
    assert check.min_length == -1
    assert check.max_length == 20
