"""Comprehensive tests for fact extractor — multi-scenario."""

from mnemosynth.engine.extractor import FactExtractor
from mnemosynth.core.types import MemoryType


class TestFactExtractor:
    def setup_method(self):
        self.extractor = FactExtractor()

    # ── Basic extraction ──────────────────────────────────────

    def test_extract_single_fact(self):
        facts = self.extractor.extract("User prefers dark mode.")
        assert len(facts) >= 1
        assert any("dark mode" in f.content for f in facts)

    def test_extract_multiple_facts(self):
        text = "User likes Python. The project uses React. Team meets on Monday."
        facts = self.extractor.extract(text)
        assert len(facts) >= 2

    def test_extract_empty_text(self):
        facts = self.extractor.extract("")
        assert len(facts) == 0

    def test_extract_short_fragments_skipped(self):
        facts = self.extractor.extract("Hi. Ok. Yes.")
        # Very short fragments should be skipped
        assert len(facts) == 0

    # ── Classification accuracy ───────────────────────────────

    def test_semantic_fact_classified(self):
        facts = self.extractor.extract("The API uses REST architecture with JSON responses.")
        assert len(facts) >= 1
        assert facts[0].memory_type == MemoryType.SEMANTIC

    def test_procedural_classified(self):
        facts = self.extractor.extract("To install the package, run pip install mnemosynth.")
        assert len(facts) >= 1
        assert any(f.memory_type == MemoryType.PROCEDURAL for f in facts)

    def test_episodic_classified(self):
        facts = self.extractor.extract("Yesterday we discussed the authentication module bugs.")
        assert len(facts) >= 1
        assert any(f.memory_type == MemoryType.EPISODIC for f in facts)

    # ── Confidence estimation ─────────────────────────────────

    def test_high_confidence_words(self):
        facts = self.extractor.extract("The user always uses TypeScript for all projects.")
        assert len(facts) >= 1
        assert facts[0].confidence >= 0.85

    def test_low_confidence_words(self):
        facts = self.extractor.extract("The user might sometimes prefer JavaScript.")
        assert len(facts) >= 1
        assert facts[0].confidence <= 0.70

    def test_medium_confidence_words(self):
        facts = self.extractor.extract("The user usually prefers morning meetings.")
        assert len(facts) >= 1
        assert 0.6 <= facts[0].confidence <= 0.9

    # ── Conversation extraction ───────────────────────────────

    def test_conversation_extraction(self):
        facts = self.extractor.extract_from_conversation(
            user_message="I prefer Python and dark mode for my projects",
            assistant_response="I'll remember that you prefer Python and dark mode",
        )
        assert len(facts) >= 1

    def test_user_statements_higher_confidence(self):
        facts = self.extractor.extract_from_conversation(
            user_message="I always use TypeScript",
            assistant_response="I note that you always use TypeScript",
        )
        user_facts = [f for f in facts if "TypeScript" in f.content]
        if len(user_facts) >= 2:
            # User statement should have higher confidence boost
            assert user_facts[0].confidence >= user_facts[1].confidence * 0.9

    # ── Deduplication ─────────────────────────────────────────

    def test_deduplication(self):
        facts = self.extractor.extract_from_conversation(
            user_message="User prefers dark mode",
            assistant_response="User prefers dark mode",
        )
        contents = [f.content.lower().strip() for f in facts]
        # Should have deduplicated
        assert len(set(contents)) == len(contents)

    # ── Edge cases ────────────────────────────────────────────

    def test_multiline_text(self):
        text = "First fact on line one.\nSecond fact on line two.\nThird on line three."
        facts = self.extractor.extract(text)
        assert len(facts) >= 2

    def test_code_block_text(self):
        text = "```python\ndef hello():\n    print('hi')\n```"
        facts = self.extractor.extract(text)
        # Should classify as procedural
        if facts:
            assert any(f.memory_type == MemoryType.PROCEDURAL for f in facts)

    def test_mixed_content(self):
        text = (
            "Yesterday we had a meeting about the new API. "
            "The API uses REST with JSON. "
            "To deploy, run docker compose up."
        )
        facts = self.extractor.extract(text)
        types = {f.memory_type for f in facts}
        # Should have at least 2 different types
        assert len(types) >= 2
