"""
Tests for wosecopy.analysis module.
"""
import pytest
import pandas as pd
import numpy as np
from unittest.mock import Mock, patch
from wosecopy.analysis import (
    group_by_rating,
    filter_by_prompt,
    calculate_rating_statistics,
    create_metrics_matrix,
)


class TestGroupByRating:
    """Test grouping concepts by rating."""

    def test_group_by_rating_basic(self):
        """Test basic rating grouping."""
        df = pd.DataFrame({
            'rating': [1, 2, 1, 3, 2],
            'woseco_concepts': [['a'], ['b'], ['c'], ['d'], ['e']]
        })

        grouped = group_by_rating(df, 'rating')

        assert 1 in grouped
        assert 2 in grouped
        assert 3 in grouped
        assert len(grouped[1]) == 2  # Two stories with rating 1
        assert len(grouped[2]) == 2
        assert len(grouped[3]) == 1

    def test_group_by_rating_custom_column(self):
        """Test grouping with custom column names."""
        df = pd.DataFrame({
            'my_rating': [5, 4, 5],
            'concepts': [['x'], ['y'], ['z']]
        })

        grouped = group_by_rating(df, 'my_rating', 'concepts')

        assert 4 in grouped
        assert 5 in grouped
        assert len(grouped[5]) == 2


class TestFilterByPrompt:
    """Test prompt filtering."""

    def test_filter_by_prompt(self):
        """Test filtering by prompt value."""
        df = pd.DataFrame({
            'prompt': ['belief-faith', 'gloom-payment', 'belief-faith'],
            'story': ['Story 1', 'Story 2', 'Story 3']
        })

        filtered = filter_by_prompt(df, 'belief-faith')

        assert len(filtered) == 2
        assert all(filtered['prompt'] == 'belief-faith')

    def test_filter_by_prompt_no_matches(self):
        """Test filtering with no matches."""
        df = pd.DataFrame({
            'prompt': ['a', 'b', 'c'],
        })

        filtered = filter_by_prompt(df, 'nonexistent')

        assert len(filtered) == 0


class TestCalculateRatingStatistics:
    """Test rating statistics calculation."""

    def test_calculate_rating_statistics(self):
        """Test basic statistics calculation."""
        df = pd.DataFrame({
            'rating_h': [4, 5, 3],
            'rating_j': [5, 4, 3],
            'rating_k': [4, 5, 4]
        })

        result = calculate_rating_statistics(df, ['rating_h', 'rating_j', 'rating_k'])

        assert 'rating_mean' in result.columns
        assert 'rating_std' in result.columns
        assert 'rating_min' in result.columns
        assert 'rating_max' in result.columns

        assert result['rating_mean'][0] == pytest.approx(4.33, abs=0.1)
        assert result['rating_min'][0] == 4
        assert result['rating_max'][0] == 5


class TestCreateMetricsMatrix:
    """Test metrics matrix creation."""

    def test_create_metrics_matrix(self):
        """Test creating matrix from grouped metrics."""
        grouped_metrics = {
            1: {'aspl': [1.0, 2.0], 'mlcc': [0.5, 0.6]},
            2: {'aspl': [3.0, 4.0], 'mlcc': [0.7, 0.8]},
        }

        matrix = create_metrics_matrix(grouped_metrics, metric_names=['aspl', 'mlcc'])

        assert matrix.shape == (2, 2)  # 2 groups, 2 metrics
        assert matrix[0, 0] == 1.5  # Mean of [1.0, 2.0]
        assert matrix[1, 1] == 0.75  # Mean of [0.7, 0.8]

    def test_create_metrics_matrix_empty(self):
        """Test creating matrix from empty dict."""
        grouped_metrics = {}

        matrix = create_metrics_matrix(grouped_metrics)

        assert matrix.shape == (0,)


class TestPCAAnalysis:
    """Test PCA analysis."""

    def test_pca_analysis(self):
        """Test PCA dimensionality reduction."""
        from wosecopy.analysis import pca_analysis

        # Create test data matrix
        data = np.array([
            [1.0, 2.0, 3.0],
            [2.0, 3.0, 4.0],
            [3.0, 4.0, 5.0],
            [4.0, 5.0, 6.0]
        ])

        result = pca_analysis(data, n_components=2)

        assert 'transformed' in result
        assert 'explained_variance' in result
        assert 'components' in result

        assert result['transformed'].shape == (4, 2)
        assert len(result['explained_variance']) == 2


class TestCompareRaters:
    """Test rater comparison functionality."""

    def test_compare_raters(self):
        """Test comparing multiple raters."""
        from wosecopy.analysis import compare_raters

        df = pd.DataFrame({
            'rating_h': [1, 2, 3],
            'rating_j': [2, 2, 3],
            'woseco_concepts': [['a', 'b'], ['c', 'd'], ['e', 'f']]
        })

        with patch('wosecopy.analysis.stats') as mock_stats:
            mock_stats.return_value = {
                'aspl': [1.0, 2.0],
                'mlcc': [0.5, 0.6]
            }

            result = compare_raters(df, ['rating_h', 'rating_j'])

            assert 'h' in result
            assert 'j' in result


class TestAnalyzePromptGroups:
    """Test prompt group analysis."""

    def test_analyze_prompt_groups(self):
        """Test analyzing different prompt groups."""
        from wosecopy.analysis import analyze_prompt_groups

        df = pd.DataFrame({
            'prompt': ['prompt1', 'prompt1', 'prompt2'],
            'woseco_concepts': [['a', 'b'], ['c', 'd'], ['e', 'f']]
        })

        with patch('wosecopy.analysis.stats') as mock_stats:
            mock_stats.return_value = {
                'aspl': [1.0, 2.0],
                'mlcc': [0.5, 0.6]
            }

            result = analyze_prompt_groups(df)

            assert 'prompt1' in result
            assert 'prompt2' in result
