"""Tests for data/validator.py — validate_and_stats + extended_stats."""

from soup_cli.data.validator import (
    _percentile,
    extended_stats,
    validate_and_stats,
)

# --- validate_and_stats ---

def test_validate_empty_data():
    """Empty dataset should return zero stats with an issue."""
    stats = validate_and_stats([])
    assert stats["total"] == 0
    assert stats["avg_length"] == 0
    assert "empty" in stats["issues"][0].lower()


def test_validate_basic_stats():
    """Basic stats should be computed correctly."""
    data = [
        {"instruction": "What is Python?", "output": "A programming language."},
        {"instruction": "What is AI?", "output": "Artificial Intelligence."},
    ]
    stats = validate_and_stats(data)
    assert stats["total"] == 2
    assert stats["avg_length"] > 0
    assert stats["min_length"] > 0
    assert stats["max_length"] >= stats["min_length"]
    assert "instruction" in stats["columns"]
    assert "output" in stats["columns"]


def test_validate_detects_duplicates():
    """Duplicated rows should be counted."""
    row = {"instruction": "Hello", "output": "Hi"}
    data = [row, row, {"instruction": "Bye", "output": "See ya"}]
    stats = validate_and_stats(data)
    assert stats["duplicates"] == 1
    assert any("duplicate" in issue.lower() for issue in stats["issues"])


def test_validate_detects_empty_fields():
    """None fields should be counted as empty."""
    data = [
        {"instruction": "Test", "output": None},
        {"instruction": "Test2", "output": "Ok"},
    ]
    stats = validate_and_stats(data)
    assert stats["empty_fields"] == 1
    assert any("empty" in issue.lower() for issue in stats["issues"])


def test_validate_format_alpaca_valid():
    """Valid alpaca data should have no format issues."""
    data = [
        {"instruction": "Q", "input": "", "output": "A"},
        {"instruction": "Q2", "input": "", "output": "A2"},
    ]
    stats = validate_and_stats(data, expected_format="alpaca")
    assert stats["valid_rows"] == 2
    # No format-related issues (may have short-sample issues)
    format_issues = [iss for iss in stats["issues"] if "missing required keys" in iss]
    assert len(format_issues) == 0


def test_validate_format_alpaca_invalid():
    """Rows missing required alpaca keys should be flagged."""
    data = [
        {"instruction": "Q", "output": "A"},
        {"wrong_key": "Q2", "output": "A2"},  # missing 'instruction'
    ]
    stats = validate_and_stats(data, expected_format="alpaca")
    assert stats["valid_rows"] == 1
    assert any("missing required keys" in iss for iss in stats["issues"])


def test_validate_short_samples():
    """Very short samples (<10 chars) should be flagged."""
    data = [
        {"text": "Hi"},
        {"text": "This is a longer sentence that should not trigger the warning."},
    ]
    stats = validate_and_stats(data)
    assert any("short" in iss.lower() for iss in stats["issues"])


# --- extended_stats ---

def test_extended_stats_empty():
    """Extended stats on empty data should return defaults."""
    stats = extended_stats([])
    assert stats["total"] == 0
    assert stats["avg_tokens"] == 0
    assert stats["lengths"] == []


def test_extended_stats_basic():
    """Extended stats should compute percentiles and token counts."""
    data = [
        {"text": "Short text"},
        {"text": "A medium length piece of example text for testing"},
        {"text": "An even longer sentence that should be significantly more characters than rest"},
    ]
    stats = extended_stats(data)
    assert stats["total"] == 3
    assert len(stats["lengths"]) == 3
    assert len(stats["token_counts"]) == 3
    assert stats["avg_tokens"] > 0
    assert stats["min_tokens"] >= 1
    assert stats["max_tokens"] >= stats["min_tokens"]
    assert stats["length_p50"] > 0


def test_extended_stats_percentiles():
    """Percentiles should be ordered correctly."""
    data = [{"text": "x" * i} for i in range(10, 110, 10)]
    stats = extended_stats(data)
    assert stats["length_p10"] <= stats["length_p25"]
    assert stats["length_p25"] <= stats["length_p50"]
    assert stats["length_p50"] <= stats["length_p75"]
    assert stats["length_p75"] <= stats["length_p90"]


# --- _percentile ---

def test_percentile_empty():
    assert _percentile([], 50) == 0


def test_percentile_single():
    assert _percentile([42], 50) == 42


def test_percentile_sorted():
    vals = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
    assert _percentile(vals, 50) == 60  # index 5
    assert _percentile(vals, 0) == 10   # index 0
    assert _percentile(vals, 100) == 100  # last element
