"""Display backend abstraction for pluggable visualization systems."""

from __future__ import annotations

import sys
from typing import Protocol, Any, TYPE_CHECKING

if TYPE_CHECKING:
    from hil_testbench.run.task_logger import TaskLogger
    from hil_testbench.config.task_config import TaskConfig


class DisplayBackend(Protocol):
    """Protocol defining the interface for display backends (Rich, Textual, etc)."""

    @property
    def logger(self) -> "TaskLogger":
        """Get reference to TaskLogger for bidirectional logging."""
        ...

    def initialize(self) -> None:
        """Initialize the display backend (start Live context, app, etc)."""
        ...

    def start_display(self) -> None:
        """Start the display (show spinner, begin rendering)."""
        ...

    def update_parameter(
        self, task_name: str, param_name: str, event: dict[str, Any], timestamp: float
    ) -> None:
        """Update a parameter value and its trendline.

        Args:
            task_name: Name of the task (e.g., "iperf", "System Health")
            param_name: Name of the parameter (e.g., "bits_per_second", "CPU%")
            event: Parsed event dict containing value and other fields
            timestamp: Unix timestamp of the event
        """
        ...

    def update_task_status(self, task_name: str, status: str) -> None:
        """Update task status (running/completed/failed).

        Args:
            task_name: Name of the task
            status: Status string ("running", "completed", "failed")
        """
        ...

    def report_task_error(self, task_name: str, error: str) -> None:
        """Report an error for a task (e.g., parser error, command failure).

        Args:
            task_name: Name of the task
            error: Error message
        """
        ...

    def add_log_line(self, message: str, level: str = "INFO") -> None:
        """Add a message to the scrollable log section.

        Args:
            message: Message to display
            level: Log level (DEBUG/INFO/WARNING/ERROR)
        """
        ...

    def shutdown(self) -> None:
        """Clean shutdown of display backend."""
        ...


def create_backend(config: "TaskConfig", logger: "TaskLogger") -> DisplayBackend | None:
    """Create appropriate display backend based on configuration and terminal capabilities.

    Auto-detection logic:
    1. Check if visualization is enabled via config.enable_viz
    2. Check terminal capabilities (isatty, color support)
    3. Apply CLI/YAML overrides for backend selection

    Args:
        config: Task configuration with display settings
        logger: TaskLogger instance for bidirectional logging

    Returns:
        DisplayBackend instance or None if visualization disabled
    """
    # Check if visualization is enabled
    if not config.enable_viz:
        return None

    # Check if running in a terminal
    if not sys.stdout.isatty():
        logger.log_warning(
            "visualization_disabled",
            reason="Not running in a TTY (stdout redirected or piped)",
        )
        return None

    # Get backend preference from config (CLI or YAML override)
    backend_name = None
    if hasattr(config, "display") and isinstance(config.display, dict):
        backend_name = config.display.get("backend")

    # Tree backend (hierarchical with command visibility)
    if backend_name == "tree":
        try:
            from hil_testbench.display.rich_tree_backend import (  # hil: allow-lazy - factory conditional import
                RichTreeBackend,
            )  # type: ignore[import]

            logger.log_info(
                "display_backend_selected", backend="tree", auto_detected=False
            )
            return RichTreeBackend(config, logger)
        except ImportError as e:
            logger.log_warning(
                "display_backend_unavailable",
                backend="tree",
                error=str(e),
                fallback="rich",
            )
            # Fall through to rich backend

    # Default to Rich scrolling backend if available
    if backend_name is None or backend_name == "rich" or backend_name == "scroll":
        try:
            from hil_testbench.display.rich_backend import (  # hil: allow-lazy - factory conditional import
                RichBackend,
            )  # type: ignore[import]

            logger.log_info(
                "display_backend_selected",
                backend=backend_name or "rich",
                auto_detected=backend_name is None,
            )
            return RichBackend(config, logger)
        except ImportError as e:
            logger.log_warning(
                "display_backend_unavailable",
                backend="rich",
                error=str(e),
                fallback="none",
            )
            return None

    # Textual backend (future implementation)
    if backend_name == "textual":
        logger.log_warning(
            "display_backend_not_implemented",
            backend="textual",
            message="Textual backend not yet implemented, falling back to Rich",
        )
        try:
            from hil_testbench.display.rich_backend import (  # hil: allow-lazy - factory conditional import
                RichBackend,
            )  # type: ignore[import]

            return RichBackend(config, logger)
        except ImportError:
            return None

    logger.log_warning("display_backend_unknown", backend=backend_name, fallback="none")
    return None
