"""Tests for the SyntheticDataGenerator."""

from __future__ import annotations

import pytest

from llmhosts.training.curator import TrainingExample
from llmhosts.training.synthetic import (
    COMPLEXITY_LABELS,
    DOMAIN_LABELS,
    PRIVACY_LABELS,
    QUALITY_LABELS,
    SyntheticDataGenerator,
)


@pytest.fixture()
def gen() -> SyntheticDataGenerator:
    return SyntheticDataGenerator()


class TestSyntheticDataGenerator:
    def test_generate_exact_count(self, gen: SyntheticDataGenerator) -> None:
        """generate(n_samples=100) must produce exactly 100 examples."""
        examples = gen.generate(n_samples=100)
        assert len(examples) == 100

    def test_generate_returns_training_examples(self, gen: SyntheticDataGenerator) -> None:
        """Each returned item must be a TrainingExample dataclass."""
        examples = gen.generate(n_samples=10)
        for ex in examples:
            assert isinstance(ex, TrainingExample)

    def test_all_labels_valid_complexity(self, gen: SyntheticDataGenerator) -> None:
        """Every example must have a valid complexity_label."""
        examples = gen.generate(n_samples=500)
        for ex in examples:
            assert ex.complexity_label in COMPLEXITY_LABELS, f"Invalid complexity_label: {ex.complexity_label!r}"

    def test_all_labels_valid_domain(self, gen: SyntheticDataGenerator) -> None:
        """Every example must have a valid domain_label."""
        examples = gen.generate(n_samples=500)
        for ex in examples:
            assert ex.domain_label in DOMAIN_LABELS, f"Invalid domain_label: {ex.domain_label!r}"

    def test_all_labels_valid_quality(self, gen: SyntheticDataGenerator) -> None:
        """Every example must have a valid quality_label."""
        examples = gen.generate(n_samples=500)
        for ex in examples:
            assert ex.quality_label in QUALITY_LABELS, f"Invalid quality_label: {ex.quality_label!r}"

    def test_all_labels_valid_privacy(self, gen: SyntheticDataGenerator) -> None:
        """Every example must have a valid privacy_label."""
        examples = gen.generate(n_samples=500)
        for ex in examples:
            assert ex.privacy_label in PRIVACY_LABELS, f"Invalid privacy_label: {ex.privacy_label!r}"

    def test_reproducibility_same_seed(self, gen: SyntheticDataGenerator) -> None:
        """Same seed must produce identical first examples."""
        a = gen.generate(n_samples=50, seed=42)
        b = gen.generate(n_samples=50, seed=42)
        assert a[0].text == b[0].text
        assert a[0].complexity_label == b[0].complexity_label

    def test_different_seeds_produce_different_results(self, gen: SyntheticDataGenerator) -> None:
        """Different seeds should (very likely) produce different first examples."""
        a = gen.generate(n_samples=100, seed=1)
        b = gen.generate(n_samples=100, seed=2)
        # It's overwhelmingly unlikely that both sets are identical
        texts_a = [ex.text for ex in a]
        texts_b = [ex.text for ex in b]
        assert texts_a != texts_b

    def test_all_complexity_levels_present_in_large_batch(self, gen: SyntheticDataGenerator) -> None:
        """All 5 complexity levels should appear in a 1000-sample generation."""
        examples = gen.generate(n_samples=1000, seed=42)
        found = {ex.complexity_label for ex in examples}
        assert found == set(COMPLEXITY_LABELS), f"Missing complexity levels: {set(COMPLEXITY_LABELS) - found}"

    def test_all_domain_levels_present_in_large_batch(self, gen: SyntheticDataGenerator) -> None:
        """All 7 domain labels should appear in a 1000-sample generation."""
        examples = gen.generate(n_samples=1000, seed=42)
        found = {ex.domain_label for ex in examples}
        assert found == set(DOMAIN_LABELS), f"Missing domain labels: {set(DOMAIN_LABELS) - found}"

    def test_text_is_non_empty_string(self, gen: SyntheticDataGenerator) -> None:
        """Every example must have a non-empty text field."""
        examples = gen.generate(n_samples=100)
        for ex in examples:
            assert isinstance(ex.text, str)
            assert len(ex.text.strip()) > 0, "Found empty text in generated example"

    def test_generate_zero_samples(self, gen: SyntheticDataGenerator) -> None:
        """Generating 0 samples should return an empty list."""
        examples = gen.generate(n_samples=0)
        assert examples == []

    def test_generate_large_batch(self, gen: SyntheticDataGenerator) -> None:
        """Generating 10_000 samples should complete without error."""
        examples = gen.generate(n_samples=10_000, seed=99)
        assert len(examples) == 10_000

    def test_slot_filling_lang_replaced(self, gen: SyntheticDataGenerator) -> None:
        """Generated texts should not contain the raw {LANG} placeholder."""
        examples = gen.generate(n_samples=500, seed=7)
        for ex in examples:
            assert "{LANG}" not in ex.text, f"Unfilled {{LANG}} slot in: {ex.text!r}"

    def test_slot_filling_format_replaced(self, gen: SyntheticDataGenerator) -> None:
        """Generated texts should not contain the raw {FORMAT} placeholder."""
        examples = gen.generate(n_samples=500, seed=13)
        for ex in examples:
            assert "{FORMAT}" not in ex.text, f"Unfilled {{FORMAT}} slot in: {ex.text!r}"
