"""Tests for extraction pipeline."""
import pytest
from unittest.mock import MagicMock
from greymatter_core.extraction import ExtractionPipeline


class TestClassify:
    def test_classify_decision(self):
        assert ExtractionPipeline._classify("We decided to use PostgreSQL for this.") == "decision"
        assert ExtractionPipeline._classify("Let's go with the Redis approach.") == "decision"

    def test_classify_correction(self):
        assert ExtractionPipeline._classify("Actually, it should be using async instead.") == "correction"
        assert ExtractionPipeline._classify("Fixed the bug in the login handler.") == "correction"

    def test_classify_pattern(self):
        assert ExtractionPipeline._classify("We always run tests before committing code.") == "pattern"
        assert ExtractionPipeline._classify("Remember to check error handling in all endpoints.") == "pattern"

    def test_classify_insight(self):
        assert ExtractionPipeline._classify("I realized the timeout was causing the failures.") == "insight"
        assert ExtractionPipeline._classify("The root cause was a race condition in the queue.") == "insight"

    def test_classify_none(self):
        assert ExtractionPipeline._classify("The weather is nice today.") is None
        assert ExtractionPipeline._classify("Hello world.") is None


class TestSplitSentences:
    def test_splits_on_period(self):
        text = "First sentence is long enough to pass. Second sentence is also long enough."
        result = ExtractionPipeline._split_sentences(text)
        assert len(result) == 2

    def test_filters_short_segments(self):
        text = "Short. This is a much longer sentence that should be included."
        result = ExtractionPipeline._split_sentences(text)
        assert len(result) == 1

    def test_splits_on_newlines(self):
        text = "First line is long enough to pass\nSecond line is also long enough here"
        result = ExtractionPipeline._split_sentences(text)
        assert len(result) == 2


class TestGenerateTitle:
    def test_short_text(self):
        title = ExtractionPipeline._generate_title("Short text here.", "decision")
        assert title.startswith("[decision]")

    def test_truncation(self):
        long_text = "A" * 200
        title = ExtractionPipeline._generate_title(long_text, "insight")
        assert len(title) < 200
        assert title.endswith("...")


class TestExtractHeuristic:
    def test_extract_multiple(self):
        text = """We decided to use SQLite for the local database.
I realized the previous approach was causing memory issues.
Remember to always validate input before processing it."""
        results = ExtractionPipeline.extract_heuristic(text, session_id="test-123")
        assert len(results) >= 2
        categories = {r["category"] for r in results}
        assert "decision" in categories

    def test_extract_with_session(self):
        text = "We decided to go with the microservice architecture for better scaling."
        results = ExtractionPipeline.extract_heuristic(text, session_id="sess-abc", trigger="pre_compact")
        assert len(results) == 1
        assert results[0]["session_id"] == "sess-abc"
        assert results[0]["trigger"] == "pre_compact"
        assert results[0]["confidence"] == 0.4

    def test_extract_nothing_from_generic(self):
        text = "The quick brown fox jumps over the lazy dog."
        results = ExtractionPipeline.extract_heuristic(text)
        assert len(results) == 0


# ---- LLM extraction with domains ----


class TestLLMExtractionDomains:
    """Verify LLM extraction returns domains."""

    def test_extract_llm_includes_domains(self):
        mock_llm = MagicMock()
        mock_llm.generate_json.return_value = [
            {
                "category": "decision",
                "title": "Use PostgreSQL for analytics",
                "content": "Chose PostgreSQL over SQLite for the analytics pipeline.",
                "confidence": 0.9,
                "domains": ["database", "analytics"],
            }
        ]
        results = ExtractionPipeline.extract_llm(
            "We decided to use PostgreSQL for analytics.",
            llm=mock_llm,
            session_id="test",
        )
        assert len(results) == 1
        assert results[0]["domains"] == "database,analytics"

    def test_extract_llm_missing_domains_defaults_empty(self):
        mock_llm = MagicMock()
        mock_llm.generate_json.return_value = [
            {
                "category": "insight",
                "title": "Caching helps",
                "content": "Caching reduces load.",
                "confidence": 0.7,
            }
        ]
        results = ExtractionPipeline.extract_llm(
            "Caching reduces load.",
            llm=mock_llm,
            session_id="test",
        )
        assert len(results) == 1
        assert results[0]["domains"] == ""


# ---- Improved heuristic patterns ----


class TestImprovedHeuristic:
    """Verify heuristic catches more patterns."""

    def test_catches_i_want(self):
        results = ExtractionPipeline.extract_heuristic(
            "I want to use Ollama for local inference on every machine."
        )
        assert len(results) >= 1

    def test_catches_trade_off(self):
        results = ExtractionPipeline.extract_heuristic(
            "The trade-off is speed versus accuracy for embedding models."
        )
        assert len(results) >= 1

    def test_catches_pricing(self):
        results = ExtractionPipeline.extract_heuristic(
            "The pricing model is free tier 500 observations, Pro unlimited."
        )
        assert len(results) >= 1
