"""
Base presenter interface for MiniMax CLI output.

Defines the abstract interface that all presenter implementations must follow,
providing a consistent API for different UI modes (console, rich, textual).
"""

from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional, Union, Callable, AsyncGenerator, Generator
from pathlib import Path


# Type aliases for convenience
ContentGenerator = Union[
    Callable[[], str],
    Callable[[], Generator[str, None, None]],
    Callable[[], AsyncGenerator[str, None]],
    Generator[str, None, None],
    AsyncGenerator[str, None]
]


class BasePresenter(ABC):
    """Abstract base class for all presenter implementations.
    
    This interface defines the contract that all presenters must implement,
    ensuring consistent behavior across different UI modes while allowing
    each implementation to provide mode-specific enhancements.
    """
    
    def __init__(self, **kwargs):
        """Initialize the presenter with optional configuration."""
        self.config = kwargs
    
    # Status message methods
    @abstractmethod
    def show_info(self, message: str, **kwargs) -> None:
        """Display an informational message.
        
        Args:
            message: The information message to display
            **kwargs: Additional formatting options (title, icon, etc.)
        """
        pass
    
    @abstractmethod
    def show_error(self, message: str, **kwargs) -> None:
        """Display an error message.
        
        Args:
            message: The error message to display
            **kwargs: Additional formatting options (title, icon, etc.)
        """
        pass
    
    @abstractmethod
    def show_success(self, message: str, **kwargs) -> None:
        """Display a success message.
        
        Args:
            message: The success message to display
            **kwargs: Additional formatting options (title, icon, etc.)
        """
        pass
    
    @abstractmethod
    def show_warning(self, message: str, **kwargs) -> None:
        """Display a warning message.
        
        Args:
            message: The warning message to display
            **kwargs: Additional formatting options (title, icon, etc.)
        """
        pass
    
    # Formatting methods
    @abstractmethod
    def show_header(self, title: str, **kwargs) -> None:
        """Display a section header.
        
        Args:
            title: The header title
            **kwargs: Additional formatting options (subtitle, style, etc.)
        """
        pass
    
    @abstractmethod
    def show_separator(self, **kwargs) -> None:
        """Display a visual separator.
        
        Args:
            **kwargs: Additional formatting options (style, character, etc.)
        """
        pass
    
    # Content display methods
    @abstractmethod
    def show_text(self, content: str, **kwargs) -> None:
        """Display plain text content.
        
        Args:
            content: The text content to display
            **kwargs: Additional formatting options (wrap, indent, etc.)
        """
        pass
    
    @abstractmethod
    def show_code(self, code: str, language: Optional[str] = None, **kwargs) -> None:
        """Display code with syntax highlighting.
        
        Args:
            code: The code content to display
            language: Programming language for syntax highlighting
            **kwargs: Additional formatting options (line_numbers, theme, etc.)
        """
        pass
    
    @abstractmethod
    def show_tree(self, tree_data: Union[Dict, List, str], **kwargs) -> None:
        """Display hierarchical tree structure.
        
        Args:
            tree_data: Tree structure data (dict, list, or formatted string)
            **kwargs: Additional formatting options (expand_all, icons, etc.)
        """
        pass
    
    @abstractmethod
    def show_table(self, data: List[Dict[str, Any]], **kwargs) -> None:
        """Display tabular data with headers and formatting.
        
        Args:
            data: List of dictionaries representing table rows
            **kwargs: Additional formatting options (title, show_header, alignment, etc.)
        """
        pass
    
    @abstractmethod
    def show_markdown(self, content: str, **kwargs) -> None:
        """Display markdown content with proper formatting.
        
        Args:
            content: Markdown content to display
            **kwargs: Additional formatting options (theme, width, etc.)
        """
        pass
    
    @abstractmethod
    def show_notification(self, message: str, level: str = 'info', **kwargs) -> None:
        """Display a transient notification message.
        
        Args:
            message: The notification message
            level: Notification level ('info', 'warning', 'error', 'success')
            **kwargs: Additional options (duration, title, etc.)
        """
        pass
    
    # Interactive methods
    @abstractmethod
    def stream_content(self, content_generator: ContentGenerator, **kwargs) -> None:
        """Display streaming content in real-time.
        
        Args:
            content_generator: Generator or callable that yields content chunks
            **kwargs: Additional formatting options (prefix, suffix, etc.)
        """
        pass
    
    @abstractmethod
    def confirm_action(self, message: str, **kwargs) -> bool:
        """Prompt user for confirmation.
        
        Args:
            message: The confirmation prompt message
            **kwargs: Additional options (default, choices, etc.)
            
        Returns:
            True if user confirmed, False otherwise
        """
        pass
    
    @abstractmethod
    def show_progress(self, 
                     task_name: str,
                     total: Optional[int] = None,
                     **kwargs) -> 'ProgressContext':
        """Display progress indicator for long operations.
        
        Args:
            task_name: Name/description of the task
            total: Total number of steps (None for indeterminate progress)
            **kwargs: Additional options (show_percentage, show_eta, etc.)
            
        Returns:
            Progress context manager for updating progress
        """
        pass
    
    # Utility methods with default implementations
    def clear_screen(self) -> None:
        """Clear the screen/display area.
        
        Default implementation does nothing. Subclasses can override
        to provide mode-specific clearing behavior.
        """
        pass
    
    def set_title(self, title: str) -> None:
        """Set the application/window title.
        
        Args:
            title: The title to set
            
        Default implementation does nothing. Subclasses can override
        to provide mode-specific title setting.
        """
        pass
    
    def flush(self) -> None:
        """Flush any pending output.
        
        Default implementation does nothing. Subclasses can override
        to ensure all output is displayed immediately.
        """
        pass


class ProgressContext(ABC):
    """Abstract context manager for progress operations.
    
    Provides a consistent interface for updating progress across
    different presenter implementations.
    """
    
    def __init__(self, presenter: BasePresenter, task_name: str, total: Optional[int] = None):
        """Initialize progress context.
        
        Args:
            presenter: The presenter instance
            task_name: Name/description of the task
            total: Total number of steps
        """
        self.presenter = presenter
        self.task_name = task_name
        self.total = total
        self.current = 0
        self.completed = False
    
    def __enter__(self) -> 'ProgressContext':
        """Enter the progress context."""
        self.start()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        """Exit the progress context."""
        self.finish()
    
    @abstractmethod
    def start(self) -> None:
        """Start the progress indicator."""
        pass
    
    @abstractmethod
    def update(self, advance: int = 1, description: Optional[str] = None) -> None:
        """Update progress.
        
        Args:
            advance: Number of steps to advance
            description: Optional description update
        """
        pass
    
    @abstractmethod
    def finish(self) -> None:
        """Finish and hide the progress indicator."""
        pass
    
    def set_total(self, total: int) -> None:
        """Update the total number of steps.
        
        Args:
            total: New total number of steps
        """
        self.total = total
    
    def set_description(self, description: str) -> None:
        """Update the task description.
        
        Args:
            description: New task description
        """
        self.task_name = description


class TreeNode:
    """Represents a node in a tree structure for display purposes."""
    
    def __init__(self, 
                 name: str, 
                 children: Optional[List['TreeNode']] = None,
                 metadata: Optional[Dict[str, Any]] = None):
        """Initialize a tree node.
        
        Args:
            name: Display name of the node
            children: List of child nodes
            metadata: Additional metadata (size, type, path, icon, etc.)
        """
        self.name = name
        self.children = children or []
        self.metadata = metadata or {}
        
        # Ensure metadata has common fields with defaults
        self.metadata.setdefault('type', 'unknown')
        self.metadata.setdefault('size', None)
        self.metadata.setdefault('modified', None)
        self.metadata.setdefault('icon', None)
    
    def add_child(self, child: 'TreeNode') -> None:
        """Add a child node.
        
        Args:
            child: Child node to add
        """
        self.children.append(child)
    
    def is_leaf(self) -> bool:
        """Check if this is a leaf node (no children).
        
        Returns:
            True if leaf node, False otherwise
        """
        return len(self.children) == 0
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert tree to dictionary representation.
        
        Returns:
            Dictionary representation of the tree
        """
        result = {
            'name': self.name,
            'metadata': self.metadata
        }
        if self.children:
            result['children'] = [child.to_dict() for child in self.children]
        return result
    
    @classmethod
    def from_path(cls, path: Path, max_depth: int = 3) -> 'TreeNode':
        """Create a tree node from a filesystem path.
        
        Args:
            path: Filesystem path to convert
            max_depth: Maximum depth to traverse
            
        Returns:
            TreeNode representing the filesystem structure
        """
        node = cls(
            name=path.name or str(path),
            metadata={
                'type': 'directory' if path.is_dir() else 'file',
                'path': str(path)
            }
        )
        
        if path.is_dir() and max_depth > 0:
            try:
                for child_path in sorted(path.iterdir()):
                    if not child_path.name.startswith('.'):  # Skip hidden files
                        child_node = cls.from_path(child_path, max_depth - 1)
                        node.add_child(child_node)
            except PermissionError:
                # Add a placeholder for inaccessible directories
                node.add_child(cls(
                    name="[Permission Denied]",
                    metadata={'type': 'error'}
                ))
        
        return node


# TreeData type alias (defined after TreeNode class)
TreeData = Union[Dict[str, Any], List[Any], TreeNode, str]
