"""
Tests for PipelineIntrospectionSource.
"""

from engine.data_sources.pipeline_introspection import PipelineIntrospectionSource


class TestPipelineIntrospectionSource:
    """Tests for PipelineIntrospectionSource."""

    def test_basic_init(self):
        """Source initializes with defaults."""
        source = PipelineIntrospectionSource()
        assert source.name == "pipeline-inspect"
        assert source.is_dynamic is True
        assert source.frame == 0
        assert source.ready is False

    def test_init_with_params(self):
        """Source initializes with custom params."""
        source = PipelineIntrospectionSource(viewport_width=100, viewport_height=40)
        assert source.viewport_width == 100
        assert source.viewport_height == 40

    def test_inlet_outlet_types(self):
        """Source has correct inlet/outlet types."""
        source = PipelineIntrospectionSource()
        from engine.pipeline.core import DataType

        assert DataType.NONE in source.inlet_types
        assert DataType.SOURCE_ITEMS in source.outlet_types

    def test_fetch_returns_items(self):
        """fetch() returns SourceItem list."""
        source = PipelineIntrospectionSource()
        items = source.fetch()
        assert len(items) == 1
        assert items[0].source == "pipeline-inspect"

    def test_fetch_increments_frame(self):
        """fetch() increments frame counter when ready."""
        source = PipelineIntrospectionSource()
        assert source.frame == 0

        # Set pipeline first to make source ready
        class MockPipeline:
            stages = {}
            execution_order = []

            def get_metrics_summary(self):
                return {"avg_ms": 10.0, "fps": 60, "stages": {}}

            def get_frame_times(self):
                return [10.0, 12.0, 11.0]

        source.set_pipeline(MockPipeline())
        assert source.ready is True

        source.fetch()
        assert source.frame == 1
        source.fetch()
        assert source.frame == 2

    def test_get_items(self):
        """get_items() returns list of SourceItems."""
        source = PipelineIntrospectionSource()
        items = source.get_items()
        assert isinstance(items, list)
        assert len(items) > 0
        assert items[0].source == "pipeline-inspect"

    def test_set_pipeline(self):
        """set_pipeline() marks source as ready."""
        source = PipelineIntrospectionSource()
        assert source.ready is False

        class MockPipeline:
            stages = {}
            execution_order = []

            def get_metrics_summary(self):
                return {"avg_ms": 10.0, "fps": 60, "stages": {}}

            def get_frame_times(self):
                return [10.0, 12.0, 11.0]

        source.set_pipeline(MockPipeline())
        assert source.ready is True


class TestPipelineIntrospectionRender:
    """Tests for rendering methods."""

    def test_render_header_no_pipeline(self):
        """_render_header returns default when no pipeline."""
        source = PipelineIntrospectionSource()
        lines = source._render_header()
        assert len(lines) == 1
        assert "PIPELINE INTROSPECTION" in lines[0]

    def test_render_bar(self):
        """_render_bar creates correct bar."""
        source = PipelineIntrospectionSource()
        bar = source._render_bar(50, 10)
        assert len(bar) == 10
        assert bar.count("█") == 5
        assert bar.count("░") == 5

    def test_render_bar_zero(self):
        """_render_bar handles zero percentage."""
        source = PipelineIntrospectionSource()
        bar = source._render_bar(0, 10)
        assert bar == "░" * 10

    def test_render_bar_full(self):
        """_render_bar handles 100%."""
        source = PipelineIntrospectionSource()
        bar = source._render_bar(100, 10)
        assert bar == "█" * 10

    def test_render_sparkline(self):
        """_render_sparkline creates sparkline."""
        source = PipelineIntrospectionSource()
        values = [1.0, 2.0, 3.0, 4.0, 5.0]
        sparkline = source._render_sparkline(values, 10)
        assert len(sparkline) == 10

    def test_render_sparkline_empty(self):
        """_render_sparkline handles empty values."""
        source = PipelineIntrospectionSource()
        sparkline = source._render_sparkline([], 10)
        assert sparkline == " " * 10

    def test_render_footer_no_pipeline(self):
        """_render_footer shows collecting data when no pipeline."""
        source = PipelineIntrospectionSource()
        lines = source._render_footer()
        assert len(lines) >= 2


class TestPipelineIntrospectionFull:
    """Integration tests."""

    def test_render_empty(self):
        """_render works when not ready."""
        source = PipelineIntrospectionSource()
        lines = source._render()
        assert len(lines) > 0
        assert "PIPELINE INTROSPECTION" in lines[0]

    def test_render_with_mock_pipeline(self):
        """_render works with mock pipeline."""
        source = PipelineIntrospectionSource()

        class MockStage:
            category = "source"
            name = "test"

        class MockPipeline:
            stages = {"test": MockStage()}
            execution_order = ["test"]

            def get_metrics_summary(self):
                return {"stages": {"test": {"avg_ms": 1.5}}, "avg_ms": 2.0, "fps": 60}

            def get_frame_times(self):
                return [1.0, 2.0, 3.0]

        source.set_pipeline(MockPipeline())
        lines = source._render()
        assert len(lines) > 0
