"""Tests for decomposition forest."""

import pytest
from bex.decompose import (
    decompose_sequence,
    decompose_all,
    decompose_with_coverage,
    get_decomposition_stats,
)


class TestDecomposeSequence:
    """Test sequence decomposition."""

    def test_short_sequence(self):
        seq = ["if", "return"]
        result = decompose_sequence(seq, max_length=5)
        # Short sequences returned as-is
        assert result == [seq]

    def test_empty_sequence(self):
        result = decompose_sequence([], max_length=5)
        assert result == []

    def test_long_sequence(self):
        seq = ["if", "return", "if", "return", "if", "return"]
        result = decompose_sequence(seq, max_length=3)
        
        # Should have prefixes, suffixes, and windows
        assert len(result) > 0
        
        # All fragments should be <= max_length
        for frag in result:
            assert len(frag) <= 3

    def test_prefixes(self):
        seq = ["a", "b", "c", "d"]
        result = decompose_sequence(seq, max_length=2)
        
        # Should include prefixes: [a], [a,b]
        assert ["a"] in result
        assert ["a", "b"] in result

    def test_suffixes(self):
        seq = ["a", "b", "c", "d"]
        result = decompose_sequence(seq, max_length=2)
        
        # Should include suffixes: [d], [c,d]
        assert ["d"] in result
        assert ["c", "d"] in result

    def test_windows(self):
        seq = ["a", "b", "c", "d", "e"]
        result = decompose_sequence(seq, max_length=3)
        
        # Should include windows: [a,b,c], [b,c,d], [c,d,e]
        assert ["a", "b", "c"] in result
        assert ["b", "c", "d"] in result
        assert ["c", "d", "e"] in result


class TestDecomposeAll:
    """Test decomposing multiple sequences."""

    def test_basic(self):
        seqs = [
            ["if", "return", "if"],
            ["while", "return"],
        ]
        result = decompose_all(seqs, max_length=2)
        
        # Should have fragments from both sequences
        assert len(result) > len(seqs)

    def test_empty(self):
        result = decompose_all([], max_length=5)
        assert result == []


class TestDecomposeWithCoverage:
    """Test decomposition with coverage filtering."""

    def test_filter_rare(self):
        seqs = [
            ["if", "return", "if", "return"],
            ["if", "return", "if", "return"],
            ["if", "return", "if", "return"],
            ["rare", "other", "rare", "other"],  # Only 1/4 have "rare"
        ]
        result = decompose_with_coverage(seqs, max_length=2, min_coverage=0.5)
        
        # "rare" fragments should be filtered out
        result_strs = [str(f) for f in result]
        assert not any("rare" in s for s in result_strs)

    def test_keep_common(self):
        seqs = [
            ["if", "return", "if"],
            ["if", "return", "if"],
            ["if", "return", "if"],
        ]
        result = decompose_with_coverage(seqs, max_length=2, min_coverage=0.5)
        
        # "if" and "return" fragments should be kept
        result_strs = [str(f) for f in result]
        assert any("if" in s for s in result_strs)
        assert any("return" in s for s in result_strs)


class TestDecompositionStats:
    """Test decomposition statistics."""

    def test_basic(self):
        seqs = [
            ["if", "return", "if", "return"],
            ["while", "return"],
        ]
        stats = get_decomposition_stats(seqs, max_length=2)
        
        assert stats['n_original'] == 2
        assert stats['n_fragments'] > 2
        assert stats['expansion_ratio'] > 1

    def test_empty(self):
        stats = get_decomposition_stats([], max_length=5)
        assert stats['n_original'] == 0
        assert stats['n_fragments'] == 0
