"""
Final tests to hit 60% coverage.
"""

import sys

import pytest

sys.path.insert(0, "src")

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt

import boofun as bf
from boofun.visualization import BooleanFunctionVisualizer


@pytest.fixture(autouse=True)
def cleanup_plots():
    yield
    plt.close("all")


class TestVisualizerAllMethods:
    """Test all visualizer methods."""

    def test_all_plot_methods(self):
        """Test all available plot methods."""
        f = bf.majority(3)
        viz = BooleanFunctionVisualizer(f)

        # Get all plot methods
        for name in dir(viz):
            if name.startswith("plot_") or name.startswith("create_"):
                method = getattr(viz, name)
                if callable(method):
                    try:
                        fig = method(show=False)
                        assert fig is not None
                    except (TypeError, ValueError):
                        pass

    def test_compare_all(self):
        """Test comparison with all functions."""
        f1 = bf.AND(3)
        viz = BooleanFunctionVisualizer(f1)

        funcs = [bf.OR(3), bf.majority(3), bf.parity(3)]

        if hasattr(viz, "compare_functions"):
            try:
                fig = viz.compare_functions(funcs, show=False)
            except (TypeError, ValueError):
                pass

    @pytest.mark.parametrize("n", [2, 3, 4, 5, 6])
    def test_different_sizes(self, n):
        """Test with different function sizes."""
        f = bf.majority(n) if n % 2 == 1 else bf.AND(n)
        viz = BooleanFunctionVisualizer(f)

        fig = viz.plot_influences(show=False)
        assert fig is not None


class TestVisualizationAnalyzer:
    """Test visualizer's analyzer integration."""

    def test_analyzer_attribute(self):
        """Visualizer should have analyzer."""
        f = bf.majority(5)
        viz = BooleanFunctionVisualizer(f)

        assert hasattr(viz, "analyzer")

    def test_analyzer_methods_via_viz(self):
        """Test accessing analyzer methods through visualizer."""
        f = bf.majority(5)
        viz = BooleanFunctionVisualizer(f)

        influences = viz.analyzer.influences()
        assert len(influences) == 5


class TestVisualizationWithCustomFunctions:
    """Test visualization with custom functions."""

    def test_custom_truth_table(self):
        """Test with custom truth table."""
        # XOR function
        f = bf.create([0, 1, 1, 0])
        viz = BooleanFunctionVisualizer(f)

        fig = viz.plot_influences(show=False)
        assert fig is not None

    def test_threshold_function(self):
        """Test threshold function visualization."""
        # Create threshold-2 on 4 variables
        tt = []
        for x in range(16):
            count = bin(x).count("1")
            tt.append(1 if count >= 2 else 0)

        f = bf.create(tt)
        viz = BooleanFunctionVisualizer(f)

        fig = viz.plot_influences(show=False)
        assert fig is not None


class TestVisualizationProperties:
    """Test visualization of function properties."""

    def test_balanced_vs_unbalanced(self):
        """Compare balanced vs unbalanced visualization."""
        balanced = bf.majority(3)
        unbalanced = bf.AND(3)

        viz_b = BooleanFunctionVisualizer(balanced)
        viz_u = BooleanFunctionVisualizer(unbalanced)

        fig_b = viz_b.plot_influences(show=False)
        fig_u = viz_u.plot_influences(show=False)

        assert fig_b is not None
        assert fig_u is not None

    def test_symmetric_functions(self):
        """Test symmetric function visualization."""
        for func in [bf.AND(3), bf.OR(3), bf.majority(5)]:
            viz = BooleanFunctionVisualizer(func)
            fig = viz.plot_influences(show=False)
            assert fig is not None


class TestAllBuiltinFunctions:
    """Test visualization with all built-in functions."""

    @pytest.mark.parametrize(
        "func_factory,n",
        [
            (bf.AND, 2),
            (bf.AND, 3),
            (bf.AND, 4),
            (bf.OR, 2),
            (bf.OR, 3),
            (bf.OR, 4),
            (bf.parity, 2),
            (bf.parity, 3),
            (bf.parity, 4),
            (bf.majority, 3),
            (bf.majority, 5),
            (bf.majority, 7),
        ],
    )
    def test_all_builtins(self, func_factory, n):
        """Test all built-in functions."""
        f = func_factory(n)
        viz = BooleanFunctionVisualizer(f)

        fig = viz.plot_influences(show=False)
        assert fig is not None

        fig = viz.plot_fourier_spectrum(show=False)
        assert fig is not None


class TestVisualizationOutput:
    """Test visualization output options."""

    def test_different_figsizes(self):
        """Test different figure sizes."""
        f = bf.majority(3)
        viz = BooleanFunctionVisualizer(f)

        for size in [(6, 4), (8, 6), (10, 8), (12, 10), (14, 10)]:
            fig = viz.plot_influences(figsize=size, show=False)
            assert fig is not None
            plt.close("all")

    def test_save_multiple_formats(self, tmp_path):
        """Test saving in multiple formats."""
        f = bf.majority(3)
        viz = BooleanFunctionVisualizer(f)

        for ext in ["png", "pdf", "svg"]:
            save_file = tmp_path / f"test.{ext}"
            try:
                fig = viz.plot_influences(save_path=str(save_file), show=False)
                assert fig is not None
            except Exception:
                pass  # Some formats may not be supported
            plt.close("all")


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
