"""
Storm Logger Console Safety Module
Safe console wrappers with fallback mechanisms
"""

import sys
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Any, Literal, TextIO, Union

# Abstract interfaces for better testability


class ConsoleChecker(ABC):
    """Abstract interface for checking console capabilities."""

    @abstractmethod
    def check_rich_availability(self) -> bool:
        """Check if Rich is available and functioning."""
        pass


class OutputWriter(ABC):
    """Abstract interface for output operations."""

    @abstractmethod
    def write(self, message: str, file: TextIO | None = None) -> None:
        """Write message to output."""
        pass

    @abstractmethod
    def write_line(self, message: str, file: TextIO | None = None) -> None:
        """Write message with newline to output."""
        pass


class RichImporter(ABC):
    """Abstract interface for importing Rich components."""

    @abstractmethod
    def import_console(self) -> Any:
        """Import Rich Console class."""
        pass

    @abstractmethod
    def import_panel(self) -> Any:
        """Import Rich Panel class."""
        pass

    @abstractmethod
    def import_table(self) -> Any:
        """Import Rich Table class."""
        pass

    @abstractmethod
    def import_progress(self) -> Any:
        """Import Rich Progress class."""
        pass


# Concrete implementations


class RealConsoleChecker(ConsoleChecker):
    """Real implementation for checking console capabilities."""

    def check_rich_availability(self) -> bool:
        """Check if Rich is available and functioning."""
        try:
            from rich.console import Console

            test_console = Console()
            test_console.print("", end="")  # Test basic functionality
        except (ImportError, OSError, UnicodeError):
            return False
        else:
            return True


class RealOutputWriter(OutputWriter):
    """Real implementation for output operations."""

    def write(self, message: str, file: TextIO | None = None) -> None:
        """Write message to output."""
        output_file = file or sys.stdout
        output_file.write(message)
        output_file.flush()

    def write_line(self, message: str, file: TextIO | None = None) -> None:
        """Write message with newline to output."""
        output_file = file or sys.stdout
        print(message, file=output_file)


class RealRichImporter(RichImporter):
    """Real implementation for importing Rich components."""

    def import_console(self) -> Any:
        """Import Rich Console class."""
        from rich.console import Console

        return Console

    def import_panel(self) -> Any:
        """Import Rich Panel class."""
        from rich.panel import Panel

        return Panel

    def import_table(self) -> Any:
        """Import Rich Table class."""
        from rich.table import Table

        return Table

    def import_progress(self) -> Any:
        """Import Rich Progress class."""
        from rich.progress import Progress

        return Progress


@dataclass
class SafeConsoleConfig:
    """Configuration for SafeConsoleWrapper."""

    fallback_to_print: bool = True
    check_on_init: bool = True
    console_checker: ConsoleChecker | None = None
    output_writer: OutputWriter | None = None
    rich_importer: RichImporter | None = None


class SafeConsoleWrapper:
    """
    Safety wrapper for Rich console operations.

    Provides graceful fallback mechanisms when Rich features fail,
    ensuring logging always works even in constrained environments.
    """

    def __init__(self, config: SafeConsoleConfig | None = None) -> None:
        if config is None:
            config = SafeConsoleConfig()

        self.fallback_to_print = config.fallback_to_print
        self._console_checker = config.console_checker or RealConsoleChecker()
        self._output_writer = config.output_writer or RealOutputWriter()
        self._rich_importer = config.rich_importer or RealRichImporter()

        # Check Rich availability if requested
        if config.check_on_init:
            self._rich_available = self._console_checker.check_rich_availability()
        else:
            self._rich_available = True  # Assume available, check on first use

    def safe_print(
        self, console: Any, message: str, style: str | None = None, **kwargs: Any
    ) -> None:
        """
        Safely print a message with optional Rich styling.

        Args:
            console: Rich Console instance
            message: Message to print
            style: Optional Rich style
            **kwargs: Additional Rich print arguments
        """
        if self._rich_available:
            try:
                if style:
                    console.print(message, style=style, **kwargs)
                else:
                    console.print(message, **kwargs)
            except (OSError, UnicodeError, AttributeError):
                # Rich failed, fall back to plain print
                self._rich_available = False
            else:
                return

        # Fallback to standard print
        if self.fallback_to_print:
            output_file = kwargs.get("file", sys.stdout)
            self._output_writer.write_line(message, file=output_file)

    def safe_panel(
        self,
        console: Any,
        content: str,
        title: str | None = None,
        style: str | None = None,
        **kwargs: Any,
    ) -> None:
        """
        Safely print a panel with fallback to simple formatting.

        Args:
            console: Rich Console instance
            content: Panel content
            title: Optional panel title
            style: Optional Rich style
            **kwargs: Additional Rich panel arguments
        """
        if self._rich_available:
            try:
                Panel = self._rich_importer.import_panel()
                panel = Panel(content, title=title, style=style, **kwargs)
                console.print(panel)
            except (ImportError, OSError, UnicodeError, AttributeError):
                # Rich failed, fall back to simple formatting
                self._rich_available = False
            else:
                return

        # Fallback to simple text formatting
        if self.fallback_to_print:
            if title:
                self._output_writer.write_line(f"=== {title} ===")
            self._output_writer.write_line(content)
            if title:
                self._output_writer.write_line("=" * (len(title) + 8))

    def safe_table(
        self,
        console: Any,
        headers: list[str],
        rows: list[list[Any]],
        title: str | None = None,
        **kwargs: Any,
    ) -> None:
        """
        Safely print a table with fallback to simple formatting.

        Args:
            console: Rich Console instance
            headers: Table headers
            rows: Table rows
            title: Optional table title
            **kwargs: Additional Rich table arguments
        """
        if self._rich_available:
            try:
                Table = self._rich_importer.import_table()
                table = Table(title=title, **kwargs)

                # Add headers
                for header in headers:
                    table.add_column(header)

                # Add rows
                for row in rows:
                    table.add_row(*[str(cell) for cell in row])

                console.print(table)
            except (ImportError, OSError, UnicodeError, AttributeError):
                # Rich failed, fall back to simple formatting
                self._rich_available = False
            else:
                return

        # Fallback to simple text table
        if self.fallback_to_print:
            if title:
                self._output_writer.write_line(f"=== {title} ===")

            # Print headers
            header_line = " | ".join(headers)
            self._output_writer.write_line(header_line)
            self._output_writer.write_line("-" * len(header_line))

            # Print rows
            for row in rows:
                self._output_writer.write_line(" | ".join(str(cell) for cell in row))

    def safe_progress(
        self, console: Any, tasks: list[str], **kwargs: Any
    ) -> Union[Any, "SimpleProgress"]:
        """
        Safely create a progress bar with fallback.

        Args:
            console: Rich Console instance
            tasks: List of tasks to track
            **kwargs: Additional Rich progress arguments
        """
        if self._rich_available:
            try:
                Progress = self._rich_importer.import_progress()
                return Progress(console=console, **kwargs)
            except (ImportError, OSError, UnicodeError, AttributeError):
                # Rich failed, fall back to simple progress
                self._rich_available = False

        # Fallback to simple progress indication
        return SimpleProgress(tasks, output_writer=self._output_writer)

    def is_rich_available(self) -> bool:
        """Check if Rich is available."""
        return self._rich_available

    def set_rich_availability(self, available: bool) -> None:
        """Set Rich availability (for testing)."""
        self._rich_available = available


class SimpleProgress:
    """
    Simple progress tracker for fallback scenarios.
    """

    def __init__(self, tasks: list[str], output_writer: OutputWriter | None = None) -> None:
        self.tasks = tasks
        self.current_task = 0
        self.total_tasks = len(tasks)
        self._output_writer = output_writer or RealOutputWriter()
        self._completed_tasks: dict[int, int] = {}

    def __enter__(self) -> Any:
        self._output_writer.write_line(f"Starting {self.total_tasks} tasks...")
        return self

    def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> Literal[False]:
        if exc_type is None:
            self._output_writer.write_line("All tasks completed!")
        else:
            self._output_writer.write_line(f"Task failed: {exc_val}")
        return False

    def add_task(self, description: str, _total: int = 100) -> int:
        """Add a task to track."""
        task_id = self.current_task
        self.current_task += 1
        self._completed_tasks[task_id] = 0
        self._output_writer.write_line(f"Task {task_id + 1}/{self.total_tasks}: {description}")
        return task_id

    def update(self, task_id: int, completed: int = 0, description: str | None = None) -> None:
        """Update task progress."""
        if description:
            self._output_writer.write_line(f"  {description}")

        if completed > 0:
            self._completed_tasks[task_id] = completed
            self._output_writer.write_line(f"  Progress: {completed}%")

    def advance(self, task_id: int, advance: int = 1) -> None:
        """Advance task progress."""
        current = self._completed_tasks.get(task_id, 0)
        new_progress = min(current + advance, 100)
        self._completed_tasks[task_id] = new_progress
        if advance > 0:
            self._output_writer.write_line(f"  Advanced to: {new_progress}%")

    def get_progress(self, task_id: int) -> int:
        """Get current progress for a task."""
        return self._completed_tasks.get(task_id, 0)


# Global safety wrapper instance with default configuration
_safety_wrapper = SafeConsoleWrapper()


def get_safety_wrapper() -> SafeConsoleWrapper:
    """Get the global safety wrapper instance."""
    return _safety_wrapper


def set_safety_wrapper(wrapper: SafeConsoleWrapper) -> None:
    """Set the global safety wrapper instance (for testing)."""
    global _safety_wrapper  # noqa: PLW0603
    _safety_wrapper = wrapper


def reset_safety_wrapper() -> None:
    """Reset the global safety wrapper to default (for testing)."""
    global _safety_wrapper  # noqa: PLW0603
    _safety_wrapper = SafeConsoleWrapper()
