"""Adapter wrapping EffectPlugin as a Stage."""

from typing import Any

from sideline.pipeline.core import PipelineContext, Stage


class EffectPluginStage(Stage):
    """Adapter wrapping EffectPlugin as a Stage.

    Supports capability-based dependencies through the dependencies parameter.
    """

    def __init__(
        self,
        effect_plugin,
        name: str = "effect",
        dependencies: set[str] | None = None,
    ):
        self._effect = effect_plugin
        self.name = name
        self.category = "effect"
        self.optional = False
        self._dependencies = dependencies or set()

    @property
    def stage_type(self) -> str:
        """Return stage_type based on effect name.

        Overlay effects have stage_type "overlay".
        """
        if self.is_overlay:
            return "overlay"
        return self.category

    @property
    def render_order(self) -> int:
        """Return render_order based on effect type.

        Overlay effects have high render_order to appear on top.
        """
        if self.is_overlay:
            return 100  # High order for overlays
        return 0

    @property
    def is_overlay(self) -> bool:
        """Return True for overlay effects.

        Overlay effects compose on top of the buffer
        rather than transforming it for the next stage.
        """
        # Check if the effect has an is_overlay attribute that is explicitly True
        # (not just any truthy value from a mock object)
        if hasattr(self._effect, "is_overlay"):
            effect_overlay = self._effect.is_overlay
            # Only return True if it's explicitly set to True
            if effect_overlay is True:
                return True
        return self.name == "hud"

    @property
    def capabilities(self) -> set[str]:
        return {f"effect.{self.name}"}

    @property
    def dependencies(self) -> set[str]:
        return self._dependencies

    @property
    def inlet_types(self) -> set:
        from sideline.pipeline.core import DataType

        return {DataType.TEXT_BUFFER}

    @property
    def outlet_types(self) -> set:
        from sideline.pipeline.core import DataType

        return {DataType.TEXT_BUFFER}

    def process(self, data: Any, ctx: PipelineContext) -> Any:
        """Process data through the effect."""
        if data is None:
            return None
        from sideline.effects.types import EffectContext, apply_param_bindings

        w = ctx.params.viewport_width if ctx.params else 80
        h = ctx.params.viewport_height if ctx.params else 24
        frame = ctx.params.frame_number if ctx.params else 0

        effect_ctx = EffectContext(
            terminal_width=w,
            terminal_height=h,
            scroll_cam=0,
            ticker_height=h,
            camera_x=0,
            mic_excess=0.0,
            grad_offset=(frame * 0.01) % 1.0,
            frame_number=frame,
            has_message=False,
            items=ctx.get("items", []),
        )

        # Copy sensor state from PipelineContext to EffectContext
        for key, value in ctx.state.items():
            if key.startswith("sensor."):
                effect_ctx.set_state(key, value)

        # Copy metrics from PipelineContext to EffectContext
        if "metrics" in ctx.state:
            effect_ctx.set_state("metrics", ctx.state["metrics"])

        # Copy pipeline_order from PipelineContext services to EffectContext state
        pipeline_order = ctx.get("pipeline_order")
        if pipeline_order:
            effect_ctx.set_state("pipeline_order", pipeline_order)

        # Apply sensor param bindings if effect has them
        if hasattr(self._effect, "param_bindings") and self._effect.param_bindings:
            bound_config = apply_param_bindings(self._effect, effect_ctx)
            self._effect.configure(bound_config)

        return self._effect.process(data, effect_ctx)
