import pytest

from engine.effects.plugins.tint import TintEffect
from engine.effects.types import EffectConfig


@pytest.fixture
def effect():
    return TintEffect()


@pytest.fixture
def effect_with_params(r=255, g=128, b=64, a=0.5):
    e = TintEffect()
    config = EffectConfig(
        enabled=True,
        intensity=1.0,
        params={"r": r, "g": g, "b": b, "a": a},
    )
    e.configure(config)
    return e


@pytest.fixture
def mock_context():
    class MockContext:
        terminal_width = 80
        terminal_height = 24

        def get_state(self, key):
            return None

    return MockContext()


class TestTintEffect:
    def test_name(self, effect):
        assert effect.name == "tint"

    def test_enabled_by_default(self, effect):
        assert effect.config.enabled is True

    def test_returns_input_when_empty(self, effect, mock_context):
        result = effect.process([], mock_context)
        assert result == []

    def test_returns_input_when_transparency_zero(
        self, effect_with_params, mock_context
    ):
        effect_with_params.config.params["a"] = 0.0
        buf = ["hello world"]
        result = effect_with_params.process(buf, mock_context)
        assert result == buf

    def test_applies_tint_to_plain_text(self, effect_with_params, mock_context):
        buf = ["hello world"]
        result = effect_with_params.process(buf, mock_context)
        assert len(result) == 1
        assert "\033[" in result[0]  # Has ANSI codes
        assert "hello world" in result[0]

    def test_tint_preserves_content(self, effect_with_params, mock_context):
        buf = ["hello world", "test line"]
        result = effect_with_params.process(buf, mock_context)
        assert "hello world" in result[0]
        assert "test line" in result[1]

    def test_rgb_to_ansi256_black(self, effect):
        assert effect._rgb_to_ansi256(0, 0, 0) == 16

    def test_rgb_to_ansi256_white(self, effect):
        assert effect._rgb_to_ansi256(255, 255, 255) == 231

    def test_rgb_to_ansi256_red(self, effect):
        color = effect._rgb_to_ansi256(255, 0, 0)
        assert 196 <= color <= 197  # Red in 256 color

    def test_rgb_to_ansi256_green(self, effect):
        color = effect._rgb_to_ansi256(0, 255, 0)
        assert 34 <= color <= 46

    def test_rgb_to_ansi256_blue(self, effect):
        color = effect._rgb_to_ansi256(0, 0, 255)
        assert 20 <= color <= 33

    def test_configure_updates_params(self, effect):
        config = EffectConfig(
            enabled=True,
            intensity=1.0,
            params={"r": 100, "g": 150, "b": 200, "a": 0.8},
        )
        effect.configure(config)
        assert effect.config.params["r"] == 100
        assert effect.config.params["g"] == 150
        assert effect.config.params["b"] == 200
        assert effect.config.params["a"] == 0.8

    def test_clamp_rgb_values(self, effect_with_params, mock_context):
        effect_with_params.config.params["r"] = 300
        effect_with_params.config.params["g"] = -10
        effect_with_params.config.params["b"] = 1.5
        buf = ["test"]
        result = effect_with_params.process(buf, mock_context)
        assert "\033[" in result[0]

    def test_clamp_alpha_above_one(self, effect_with_params, mock_context):
        effect_with_params.config.params["a"] = 1.5
        buf = ["test"]
        result = effect_with_params.process(buf, mock_context)
        assert "\033[" in result[0]

    def test_preserves_empty_lines(self, effect_with_params, mock_context):
        buf = ["hello", "", "world"]
        result = effect_with_params.process(buf, mock_context)
        assert result[1] == ""

    def test_inlet_types_includes_text_buffer(self, effect):
        from engine.pipeline.core import DataType

        assert DataType.TEXT_BUFFER in effect.inlet_types

    def test_outlet_types_includes_text_buffer(self, effect):
        from engine.pipeline.core import DataType

        assert DataType.TEXT_BUFFER in effect.outlet_types
