"""
Tests for wosecopy.core module.
"""
import pytest
import pandas as pd
from unittest.mock import Mock, patch
from wosecopy.core import WosecoExtractor


class TestWosecoExtractor:
    """Test cases for WosecoExtractor class."""

    @pytest.fixture
    def extractor(self):
        """Create a WosecoExtractor instance for testing."""
        with patch('wosecopy.core.spacy.load') as mock_load:
            mock_nlp = Mock()
            mock_load.return_value = mock_nlp
            return WosecoExtractor(language='en', model_size='sm')

    def test_initialization(self, extractor):
        """Test extractor initialization."""
        assert extractor.language == 'en'
        assert extractor.model_size == 'sm'
        assert extractor.nlp is not None

    def test_extract_nouns(self, extractor):
        """Test noun extraction from text."""
        # Mock spacy doc
        mock_token1 = Mock()
        mock_token1.pos_ = "NOUN"
        mock_token1.lemma_ = "dog"

        mock_token2 = Mock()
        mock_token2.pos_ = "VERB"
        mock_token2.lemma_ = "run"

        mock_token3 = Mock()
        mock_token3.pos_ = "NOUN"
        mock_token3.lemma_ = "park"

        mock_doc = [mock_token1, mock_token2, mock_token3]
        extractor.nlp.return_value = mock_doc

        nouns = extractor.extract_nouns("The dog runs in the park")
        assert nouns == ["dog", "park"]

    def test_get_concept_matches_empty_list(self, extractor):
        """Test concept matching with empty list."""
        result = extractor.get_concept_matches([])
        assert result == []

    def test_get_concept_matches_single_sentence(self, extractor):
        """Test concept matching with single sentence."""
        concepts = [['dog', 'park']]
        result = extractor.get_concept_matches(concepts)
        # Should return first concept when only one sentence
        assert len(result) > 0

    def test_get_woseco_empty_dataframe(self, extractor):
        """Test Woseco extraction on empty DataFrame."""
        df = pd.DataFrame({'Story': []})
        result = extractor.get_woseco(df, show_progress=False)
        assert result == []

    def test_get_woseco_basic(self, extractor):
        """Test basic Woseco extraction."""
        # Mock the extract_nouns method
        extractor.extract_nouns = Mock(side_effect=[
            ['belief', 'village'],
            ['faith', 'people']
        ])

        # Mock similarity calculation
        mock_doc1 = Mock()
        mock_doc1.similarity = Mock(return_value=0.8)
        extractor.nlp.return_value = mock_doc1

        df = pd.DataFrame({
            'Story': ['There was a belief in the village. The faith helped people.']
        })

        result = extractor.get_woseco(df, show_progress=False)
        assert len(result) == 1
        assert isinstance(result[0], list)

    def test_process_csv(self, extractor, tmp_path):
        """Test CSV processing."""
        # Create test CSV
        test_csv = tmp_path / "test.csv"
        df = pd.DataFrame({
            'Story': ['Test story one.', 'Test story two.']
        })
        df.to_csv(test_csv, index=False)

        # Mock get_woseco
        extractor.get_woseco = Mock(return_value=[['concept1'], ['concept2']])

        output_csv = tmp_path / "output.csv"
        result_df = extractor.process_csv(
            str(test_csv),
            output_path=str(output_csv)
        )

        assert 'woseco_concepts' in result_df.columns
        assert len(result_df) == 2
        assert output_csv.exists()


class TestConceptMatching:
    """Test concept matching functionality."""

    @pytest.fixture
    def extractor(self):
        """Create extractor with mocked NLP."""
        with patch('wosecopy.core.spacy.load') as mock_load:
            mock_nlp = Mock()
            mock_load.return_value = mock_nlp
            return WosecoExtractor(language='en', model_size='sm')

    def test_similarity_threshold(self, extractor):
        """Test concept matching with similarity threshold."""
        concept_list = [['dog'], ['cat']]

        # Mock similarity below threshold
        mock_doc = Mock()
        mock_doc.similarity = Mock(return_value=0.3)
        extractor.nlp.return_value = mock_doc

        result = extractor.get_concept_matches(concept_list, similarity_threshold=0.5)
        # With low similarity, should still add first and last
        assert len(result) >= 1

    def test_high_similarity_match(self, extractor):
        """Test concept matching with high similarity."""
        concept_list = [['belief'], ['faith']]

        # Mock high similarity
        mock_doc = Mock()
        mock_doc.similarity = Mock(return_value=0.9)
        extractor.nlp.return_value = mock_doc

        result = extractor.get_concept_matches(concept_list)
        assert len(result) >= 2


def test_module_imports():
    """Test that core module imports work."""
    from wosecopy.core import WosecoExtractor
    assert WosecoExtractor is not None
