"""
Comprehensive unit tests for Storm Console.
Tests all functionality to achieve 100% coverage.
"""

import pytest
from unittest.mock import Mock, MagicMock, patch, call
from typing import Any, Dict, List, Optional

from storm_logger.console.storm_console import (
    StormConsole, get_storm_console, _storm_console
)
from storm_logger.console.console_interfaces import (
    ConsoleFactory, SyntaxFactory, ProgressFactory,
    RichComponentFactory, ThemeProvider, ConfigProvider,
    SafetyProvider
)
from storm_logger.config import StormLoggerConfig, StormTheme


# Mock implementations for testing

class MockConsoleFactory(ConsoleFactory):
    """Mock console factory for testing."""
    
    def __init__(self):
        self.console_mock = Mock()
        self.create_console_calls = []
    
    def create_console(self, theme: Any, force_terminal: bool, 
                      legacy_windows: bool, safe_box: bool, 
                      stderr: bool) -> Any:
        self.create_console_calls.append({
            'theme': theme,
            'force_terminal': force_terminal,
            'legacy_windows': legacy_windows,
            'safe_box': safe_box,
            'stderr': stderr
        })
        return self.console_mock


class MockSyntaxFactory(SyntaxFactory):
    """Mock syntax factory for testing."""
    
    def __init__(self):
        self.syntax_mock = Mock()
        self.create_syntax_calls = []
    
    def create_syntax(self, code: str, language: str, theme: str) -> Any:
        self.create_syntax_calls.append({
            'code': code,
            'language': language,
            'theme': theme
        })
        return self.syntax_mock


class MockProgressFactory(ProgressFactory):
    """Mock progress factory for testing."""
    
    def __init__(self):
        self.progress_mock = Mock()
        self.spinner_mock = Mock()
        self.text_mock = Mock()
        self.bar_mock = Mock()
        self.create_progress_calls = []
    
    def create_progress(self, *columns, console: Any = None, 
                       refresh_per_second: float = 10) -> Any:
        self.create_progress_calls.append({
            'columns': columns,
            'console': console,
            'refresh_per_second': refresh_per_second
        })
        return self.progress_mock
    
    def create_spinner_column(self) -> Any:
        return self.spinner_mock
    
    def create_text_column(self, text_format: str) -> Any:
        return Mock(text_format=text_format)
    
    def create_bar_column(self) -> Any:
        return self.bar_mock


class MockComponentFactory(RichComponentFactory):
    """Mock component factory for testing."""
    
    def __init__(self):
        self.table_mock = Mock()
        self.panel_mock = Mock()
        self.text_mock = Mock()
        self.columns_mock = Mock()
        self.layout_mock = Mock()
        self.live_mock = Mock()
        self.created_tables = []
        self.created_panels = []
    
    def create_table(self, title: Optional[str] = None, 
                    show_header: bool = True, 
                    header_style: Optional[str] = None) -> Any:
        self.created_tables.append({
            'title': title,
            'show_header': show_header,
            'header_style': header_style
        })
        # Return a mock with add_column and add_row methods
        table = Mock()
        table.add_column = Mock()
        table.add_row = Mock()
        return table
    
    def create_panel(self, content: Any, title: Optional[str] = None,
                    style: Optional[str] = None, padding: tuple = (0, 1)) -> Any:
        self.created_panels.append({
            'content': content,
            'title': title,
            'style': style,
            'padding': padding
        })
        return self.panel_mock
    
    def create_text(self, text: str, style: Optional[str] = None) -> Any:
        return self.text_mock
    
    def create_columns(self, renderables: List[Any]) -> Any:
        return self.columns_mock
    
    def create_layout(self) -> Any:
        return self.layout_mock
    
    def create_live(self, renderable: Any, console: Any, 
                   refresh_per_second: float = 4) -> Any:
        return self.live_mock


class MockThemeProvider(ThemeProvider):
    """Mock theme provider for testing."""
    
    def __init__(self):
        self.theme_mock = Mock()
        self.get_theme_calls = []
    
    def get_theme(self, theme_name: str) -> Any:
        self.get_theme_calls.append(theme_name)
        return self.theme_mock


class MockConfigProvider(ConfigProvider):
    """Mock config provider for testing."""
    
    def __init__(self, config: Optional[StormLoggerConfig] = None):
        self.config = config or StormLoggerConfig()
    
    def get_config(self) -> Any:
        return self.config


class MockSafetyProvider(SafetyProvider):
    """Mock safety provider for testing."""
    
    def __init__(self, safety_wrapper=None):
        self.safety_wrapper = safety_wrapper or Mock(_rich_available=True, is_rich_available=Mock(return_value=True))
    
    def get_safety_wrapper(self) -> Any:
        return self.safety_wrapper


class TestStormConsole:
    """Test StormConsole class."""
    
    def test_init_with_injected_dependencies(self):
        """Test initialization with dependency injection."""
        # Create mocks
        config = StormLoggerConfig(storm_theme=StormTheme.PROFESSIONAL)
        console_factory = MockConsoleFactory()
        syntax_factory = MockSyntaxFactory()
        progress_factory = MockProgressFactory()
        component_factory = MockComponentFactory()
        theme_provider = MockThemeProvider()
        config_provider = MockConfigProvider(config)
        safety_provider = MockSafetyProvider()
        
        # Create console
        storm_console = StormConsole(
            config=config,
            console_factory=console_factory,
            syntax_factory=syntax_factory,
            progress_factory=progress_factory,
            component_factory=component_factory,
            theme_provider=theme_provider,
            config_provider=config_provider,
            safety_provider=safety_provider
        )
        
        # Verify dependencies were set
        assert storm_console._console_factory is console_factory
        assert storm_console._syntax_factory is syntax_factory
        assert storm_console._progress_factory is progress_factory
        assert storm_console._component_factory is component_factory
        assert storm_console._theme_provider is theme_provider
        assert storm_console._config_provider is config_provider
        assert storm_console._safety_provider is safety_provider
        assert storm_console.config is config
        
        # Verify theme was fetched
        assert theme_provider.get_theme_calls == ['professional']
    
    def test_init_with_config_provider_no_config(self):
        """Test initialization using config provider when no config is provided."""
        config_provider = MockConfigProvider()
        theme_provider = MockThemeProvider()
        safety_provider = MockSafetyProvider()
        
        storm_console = StormConsole(
            config_provider=config_provider,
            theme_provider=theme_provider,
            safety_provider=safety_provider
        )
        
        assert storm_console.config == config_provider.config
    
    def test_init_with_backward_compatibility(self):
        """Test initialization with backward compatibility (no dependencies)."""
        with patch('storm_logger.config.get_config') as mock_get_config:
            with patch('storm_logger.console.themes.get_theme') as mock_get_theme:
                mock_config = Mock(storm_theme=Mock(value='default'))
                mock_get_config.return_value = mock_config
                mock_theme = Mock()
                mock_get_theme.return_value = mock_theme
                
                storm_console = StormConsole()
                
                assert storm_console.config == mock_config
                assert storm_console.theme == mock_theme
                mock_get_config.assert_called_once()
                mock_get_theme.assert_called_once_with('default')
    
    def test_get_console_with_factory(self):
        """Test get_console using console factory."""
        console_factory = MockConsoleFactory()
        config = StormLoggerConfig(console_colors=True)
        theme = Mock()
        
        storm_console = StormConsole(
            config=config,
            console_factory=console_factory,
            theme_provider=MockThemeProvider()
        )
        storm_console.theme = theme
        
        # Get console
        console = storm_console.get_console()
        
        # Verify factory was called correctly
        assert console is console_factory.console_mock
        assert len(console_factory.create_console_calls) == 1
        call_args = console_factory.create_console_calls[0]
        assert call_args['theme'] == theme
        assert call_args['force_terminal'] is True
        assert call_args['legacy_windows'] is False
        assert call_args['safe_box'] is True
        assert call_args['stderr'] is False
        
        # Verify console is cached
        console2 = storm_console.get_console()
        assert console2 is console
        assert len(console_factory.create_console_calls) == 1  # Still only one call
    
    def test_get_console_backward_compatibility(self):
        """Test get_console with backward compatibility."""
        with patch('rich.console.Console') as mock_console_class:
            mock_console = Mock()
            mock_console_class.return_value = mock_console
            
            # Use a fresh StormConsole instance to avoid test interference
            with patch('storm_logger.config.get_config') as mock_get_config:
                with patch('storm_logger.console.themes.get_theme') as mock_get_theme:
                    mock_config = Mock(storm_theme=Mock(value='default'), console_colors=True)
                    mock_get_config.return_value = mock_config
                    mock_theme = Mock()
                    mock_get_theme.return_value = mock_theme
                    
                    storm_console = StormConsole()
                    console = storm_console.get_console()
                    
                    assert console is mock_console
                    # Find the call with our expected arguments
                    found_call = False
                    for call in mock_console_class.call_args_list:
                        if (call[1].get('theme') == mock_theme and
                            call[1].get('force_terminal') is True and
                            call[1].get('legacy_windows') is False and
                            call[1].get('safe_box') is True and
                            call[1].get('stderr') is False):
                            found_call = True
                            break
                    assert found_call, f"Expected call not found in {mock_console_class.call_args_list}"
    
    def test_print(self):
        """Test print method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        # Test print
        storm_console.print("test message", style="bold")
        
        # Verify safe_print was called
        safety_wrapper.safe_print.assert_called_once_with(
            console_factory.console_mock,
            "test message",
            style="bold"
        )
    
    def test_print_header(self):
        """Test print_header method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        # Test with title only
        storm_console.print_header("Main Title")
        
        safety_wrapper.safe_panel.assert_called_once()
        call_args = safety_wrapper.safe_panel.call_args
        assert "[storm.header] Main Title [/storm.header]" in call_args[0][1]
        assert call_args[1]['style'] == "storm-royal-blue"
        assert call_args[1]['padding'] == (1, 2)
        
        # Test with subtitle
        safety_wrapper.reset_mock()
        storm_console.print_header("Main Title", "Subtitle")
        
        call_args = safety_wrapper.safe_panel.call_args
        content = call_args[0][1]
        assert "[storm.header] Main Title [/storm.header]" in content
        assert "[storm.subheader]Subtitle[/storm.subheader]" in content
    
    def test_print_business_context(self):
        """Test print_business_context method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        # Test different technologies
        test_cases = [
            ("django", "storm.django"),
            ("midas", "storm.midas"),
            ("animation", "storm.animation"),
            ("business", "storm.business"),
            ("unknown", "storm.info")  # Default case
        ]
        
        for tech, expected_style in test_cases:
            safety_wrapper.reset_mock()
            storm_console.print_business_context("Test context", tech)
            
            call_args = safety_wrapper.safe_print.call_args
            message = call_args[0][1]
            assert f"[{expected_style}]🎯 Business Context: Test context[/{expected_style}]" == message
    
    def test_print_analysis(self):
        """Test print_analysis method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        storm_console.print_analysis("Performance Analysis", "Details here")
        
        call_args = safety_wrapper.safe_panel.call_args
        content = call_args[0][1]
        assert "[storm.info]📊 Performance Analysis[/storm.info]" in content
        assert "Details here" in content
        assert call_args[1]['style'] == "storm-cyan"
        assert call_args[1]['title'] == "Analysis"
    
    def test_print_error(self):
        """Test print_error method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        # Without guidance
        storm_console.print_error("Database Error", "Connection failed")
        
        call_args = safety_wrapper.safe_panel.call_args
        content = call_args[0][1]
        assert "[storm.error]❌ Database Error[/storm.error]" in content
        assert "Connection failed" in content
        assert "Guidance" not in content
        assert call_args[1]['style'] == "storm-error"
        assert call_args[1]['title'] == "Error Analysis"
        
        # With guidance
        safety_wrapper.reset_mock()
        storm_console.print_error("Database Error", "Connection failed", "Check connection string")
        
        content = safety_wrapper.safe_panel.call_args[0][1]
        assert "[storm.warning]💡 Guidance:[/storm.warning]" in content
        assert "Check connection string" in content
    
    def test_print_success(self):
        """Test print_success method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        storm_console.print_success("Operation Complete", "All tests passed")
        
        call_args = safety_wrapper.safe_panel.call_args
        content = call_args[0][1]
        assert "[storm.success]✅ Operation Complete[/storm.success]" in content
        assert "All tests passed" in content
        assert call_args[1]['style'] == "storm-success"
        assert call_args[1]['title'] == "Success"
    
    def test_print_warning(self):
        """Test print_warning method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        storm_console.print_warning("Deprecation", "This feature will be removed")
        
        call_args = safety_wrapper.safe_panel.call_args
        content = call_args[0][1]
        assert "[storm.warning]⚠️ Deprecation[/storm.warning]" in content
        assert "This feature will be removed" in content
        assert call_args[1]['style'] == "storm-warning"
        assert call_args[1]['title'] == "Warning"
    
    def test_print_info(self):
        """Test print_info method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        storm_console.print_info("Information", "Here is some info")
        
        call_args = safety_wrapper.safe_panel.call_args
        content = call_args[0][1]
        assert "[storm.info]ℹ️ Information[/storm.info]" in content
        assert "Here is some info" in content
        assert call_args[1]['style'] == "storm-info"
        assert call_args[1]['title'] == "Info"
    
    def test_print_panel(self):
        """Test print_panel method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        storm_console.print_panel("Panel Title", "Panel content", style="custom.style")
        
        safety_wrapper.safe_panel.assert_called_once_with(
            console_factory.console_mock,
            "Panel content",
            style="custom.style",
            title="Panel Title"
        )
    
    def test_print_business_metric(self):
        """Test print_business_metric method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        # Test without threshold
        storm_console.print_business_metric("Revenue", 1000000)
        
        call_args = safety_wrapper.safe_print.call_args
        message = call_args[0][1]
        assert "[storm.metric]📈 Revenue:[/storm.metric] 1000000" == message
        
        # Test with numeric threshold (exceeds)
        safety_wrapper.reset_mock()
        storm_console.print_business_metric("Error Rate", 5.5, threshold=5.0)
        
        message = safety_wrapper.safe_print.call_args[0][1]
        assert "[storm.metric]📈 Error Rate:[/storm.metric] 5.5" in message
        assert "[storm.error](exceeds threshold: 5.0)[/storm.error]" in message
        
        # Test with numeric threshold (within)
        safety_wrapper.reset_mock()
        storm_console.print_business_metric("Error Rate", 4.5, threshold=5.0)
        
        message = safety_wrapper.safe_print.call_args[0][1]
        assert "[storm.success](within threshold: 5.0)[/storm.success]" in message
        
        # Test with non-numeric threshold
        safety_wrapper.reset_mock()
        storm_console.print_business_metric("Status", "Active", threshold="Expected")
        
        message = safety_wrapper.safe_print.call_args[0][1]
        assert "[storm.info](threshold: Expected)[/storm.info]" in message
    
    def test_print_test_progress(self):
        """Test print_test_progress method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        # Test different statuses
        test_cases = [
            ("passed", "storm.success", "✅"),
            ("failed", "storm.error", "❌"),
            ("running", "storm.info", "🏃"),
            ("skipped", "storm.warning", "⏭️"),
            ("unknown", "storm.info", "•")  # Default case
        ]
        
        for status, expected_style, expected_icon in test_cases:
            safety_wrapper.reset_mock()
            storm_console.print_test_progress("test_example", status)
            
            message = safety_wrapper.safe_print.call_args[0][1]
            assert f"[{expected_style}]{expected_icon} test_example: {status.upper()}[/{expected_style}]" == message
        
        # Test with duration
        safety_wrapper.reset_mock()
        storm_console.print_test_progress("test_example", "passed", duration=1.234)
        
        message = safety_wrapper.safe_print.call_args[0][1]
        assert "[storm.debug](1.23s)[/storm.debug]" in message
    
    def test_print_session_summary(self):
        """Test print_session_summary method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        storm_console.print_session_summary(tests_run=100, passed=95, failed=5, duration=12.5)
        
        call_args = safety_wrapper.safe_panel.call_args
        content = call_args[0][1]
        
        assert "[storm.metric]Tests Run:[/storm.metric] 100" in content
        assert "[storm.success]Passed:[/storm.success] 95" in content
        assert "[storm.error]Failed:[/storm.error] 5" in content
        assert "[storm.kpi]Success Rate:[/storm.kpi] 95.0%" in content
        assert "[storm.info]Duration:[/storm.info] 12.50s" in content
        assert call_args[1]['style'] == "storm-royal-blue"
        assert call_args[1]['title'] == "Test Session Summary"
        
        # Test with zero tests
        safety_wrapper.reset_mock()
        storm_console.print_session_summary(tests_run=0, passed=0, failed=0, duration=0.0)
        
        content = safety_wrapper.safe_panel.call_args[0][1]
        assert "[storm.kpi]Success Rate:[/storm.kpi] 0.0%" in content
    
    def test_print_business_recommendation(self):
        """Test print_business_recommendation method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        recommendations = ["Increase cache size", "Add more workers", "Optimize queries"]
        storm_console.print_business_recommendation("Performance Improvements", recommendations)
        
        call_args = safety_wrapper.safe_panel.call_args
        content = call_args[0][1]
        
        assert "[storm.business]Performance Improvements[/storm.business]" in content
        assert "[storm.highlight]1.[/storm.highlight] Increase cache size" in content
        assert "[storm.highlight]2.[/storm.highlight] Add more workers" in content
        assert "[storm.highlight]3.[/storm.highlight] Optimize queries" in content
        assert call_args[1]['style'] == "storm-pine"
        assert call_args[1]['title'] == "Business Recommendations"
    
    def test_print_table(self):
        """Test print_table method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        columns = ["Name", "Age"]
        rows = [["Alice", 30], ["Bob", 25]]
        
        storm_console.print_table("User Data", columns, rows)
        
        safety_wrapper.safe_table.assert_called_once_with(
            console_factory.console_mock,
            columns,
            rows,
            title="User Data"
        )
    
    def test_print_code_with_syntax_factory(self):
        """Test print_code method with syntax factory."""
        console_factory = MockConsoleFactory()
        syntax_factory = MockSyntaxFactory()
        safety_wrapper = Mock(_rich_available=True, is_rich_available=Mock(return_value=True))
        
        storm_console = StormConsole(
            console_factory=console_factory,
            syntax_factory=syntax_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        code = "def hello():\n    print('Hello')"
        storm_console.print_code(code, language="python", theme="monokai")
        
        # Verify syntax factory was called
        assert len(syntax_factory.create_syntax_calls) == 1
        call_args = syntax_factory.create_syntax_calls[0]
        assert call_args['code'] == code
        assert call_args['language'] == "python"
        assert call_args['theme'] == "monokai"
        
        # Verify console.print was called with syntax
        console_factory.console_mock.print.assert_called_once_with(syntax_factory.syntax_mock)
    
    def test_print_code_backward_compatibility(self):
        """Test print_code with backward compatibility."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock(_rich_available=True, is_rich_available=Mock(return_value=True))
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        with patch('rich.syntax.Syntax') as mock_syntax_class:
            mock_syntax = Mock()
            mock_syntax_class.return_value = mock_syntax
            
            code = "print('test')"
            storm_console.print_code(code)
            
            mock_syntax_class.assert_called_once_with(code, "python", theme="monokai")
            console_factory.console_mock.print.assert_called_once_with(mock_syntax)
    
    def test_print_code_fallback(self):
        """Test print_code fallback when Rich is not available."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock(_rich_available=False, is_rich_available=Mock(return_value=False))
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        code = "print('test')"
        storm_console.print_code(code, language="python")
        
        expected_output = "```\npython\nprint('test')\n"  # Note: closing ``` is on the next line due to multiline string
        safety_wrapper.safe_print.assert_called_once_with(
            console_factory.console_mock,
            expected_output
        )
    
    def test_print_code_exception_fallback(self):
        """Test print_code fallback when exception occurs."""
        console_factory = MockConsoleFactory()
        syntax_factory = MockSyntaxFactory()
        syntax_factory.create_syntax = Mock(side_effect=Exception("Syntax error"))
        safety_wrapper = Mock(_rich_available=True, is_rich_available=Mock(return_value=True))
        
        storm_console = StormConsole(
            console_factory=console_factory,
            syntax_factory=syntax_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        code = "invalid code"
        storm_console.print_code(code)
        
        # Should fall back to plain output
        expected_output = "```\npython\ninvalid code\n"  # Note: closing ``` is on the next line due to multiline string
        safety_wrapper.safe_print.assert_called_once_with(
            console_factory.console_mock,
            expected_output
        )
    
    def test_create_progress_with_factory(self):
        """Test create_progress method with progress factory."""
        console_factory = MockConsoleFactory()
        progress_factory = MockProgressFactory()
        safety_wrapper = Mock(_rich_available=True)
        
        storm_console = StormConsole(
            console_factory=console_factory,
            progress_factory=progress_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        result = storm_console.create_progress("Processing...")
        
        # Verify factory methods were called
        assert result is progress_factory.progress_mock
        assert len(progress_factory.create_progress_calls) == 1
        
        # Verify columns were created
        call_args = progress_factory.create_progress_calls[0]
        assert len(call_args['columns']) == 4  # spinner, text, bar, percent
        assert call_args['console'] is console_factory.console_mock
    
    def test_create_progress_backward_compatibility(self):
        """Test create_progress with backward compatibility."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock(_rich_available=True)
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        with patch('rich.progress.Progress') as mock_progress_class:
            with patch('rich.progress.SpinnerColumn') as mock_spinner:
                with patch('rich.progress.TextColumn') as mock_text:
                    with patch('rich.progress.BarColumn') as mock_bar:
                        mock_progress = Mock()
                        mock_progress_class.return_value = mock_progress
                        
                        result = storm_console.create_progress()
                        
                        assert result is mock_progress
                        mock_progress_class.assert_called_once()
    
    def test_create_progress_fallback(self):
        """Test create_progress fallback when Rich is not available."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock(_rich_available=False)
        mock_simple_progress = Mock()
        safety_wrapper.safe_progress.return_value = mock_simple_progress
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        result = storm_console.create_progress("Processing...")
        
        assert result is mock_simple_progress
        safety_wrapper.safe_progress.assert_called_once_with(
            console_factory.console_mock,
            ["Processing..."]
        )
    
    def test_print_separator(self):
        """Test print_separator method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        # Without title
        storm_console.print_separator()
        
        call_args = safety_wrapper.safe_print.call_args
        message = call_args[0][1]
        assert message == "[storm.debug]" + "=" * 60 + "[/storm.debug]"
        
        # With title
        safety_wrapper.reset_mock()
        storm_console.print_separator("Section")
        
        message = safety_wrapper.safe_print.call_args[0][1]
        assert "[storm.debug]" + "=" * 20 + " Section " + "=" * 20 + "[/storm.debug]" == message
    
    def test_print_debug(self):
        """Test print_debug method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        # Test with debug mode enabled
        config = StormLoggerConfig(debug_mode=True)
        storm_console = StormConsole(
            config=config,
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        storm_console.print_debug("Debug message")
        
        call_args = safety_wrapper.safe_print.call_args
        message = call_args[0][1]
        assert message == "[storm.debug]🔍 DEBUG: Debug message[/storm.debug]"
        
        # Test with debug mode disabled
        safety_wrapper.reset_mock()
        config.debug_mode = False
        storm_console.print_debug("Debug message")
        
        safety_wrapper.safe_print.assert_not_called()
    
    def test_print_metrics_with_factory(self):
        """Test print_metrics method with component factory."""
        console_factory = MockConsoleFactory()
        component_factory = MockComponentFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            component_factory=component_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        metrics = {
            "Revenue": 1000000,
            "Error Rate": 0,
            "Status": "error detected",
            "Users": "1000"
        }
        
        storm_console.print_metrics(metrics)
        
        # Verify table was created
        assert len(component_factory.created_tables) == 1
        table_args = component_factory.created_tables[0]
        assert table_args['title'] == "📈 Business Metrics"
        assert table_args['show_header'] is True
        assert table_args['header_style'] == "storm.header"
        
        # Verify safe_print was called with the table
        assert safety_wrapper.safe_print.called
    
    def test_print_metrics_empty(self):
        """Test print_metrics with empty metrics."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        storm_console.print_metrics({})
        
        call_args = safety_wrapper.safe_print.call_args
        message = call_args[0][1]
        assert message == "[storm.warning]📊 No metrics available[/storm.warning]"
    
    def test_print_metrics_backward_compatibility(self):
        """Test print_metrics with backward compatibility."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        with patch('rich.table.Table') as mock_table_class:
            mock_table = Mock()
            mock_table_class.return_value = mock_table
            
            storm_console.print_metrics({"Test": 123})
            
            mock_table_class.assert_called_once()
            mock_table.add_column.assert_called()
            mock_table.add_row.assert_called()
    
    def test_print_solution(self):
        """Test print_solution method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        # Without subtitle
        storm_console.print_solution("Use caching to improve performance")
        
        call_args = safety_wrapper.safe_panel.call_args
        content = call_args[0][1]
        assert "[storm.success]💡 Solution:[/storm.success]" in content
        assert "Use caching to improve performance" in content
        assert "[storm.info]" not in content
        assert call_args[1]['style'] == "storm-success"
        assert call_args[1]['title'] == "💡 Solution Found"
        
        # With subtitle
        safety_wrapper.reset_mock()
        storm_console.print_solution("Use caching", subtitle="Performance Optimization")
        
        content = safety_wrapper.safe_panel.call_args[0][1]
        assert "[storm.info]Performance Optimization[/storm.info]" in content
        assert "[storm.success]💡 Solution:[/storm.success]" in content
    
    def test_print_django_spellbook_tip(self):
        """Test print_django_spellbook_tip method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        storm_console.print_django_spellbook_tip("Use select_related for foreign keys")
        
        call_args = safety_wrapper.safe_panel.call_args
        content = call_args[0][1]
        assert "[storm.django]🔮 Django Spellbook Tip:[/storm.django]" in content
        assert "Use select_related for foreign keys" in content
        assert call_args[1]['style'] == "storm-django"
        assert call_args[1]['title'] == "🔮 Django Spellbook"
    
    def test_print_midas_optimization(self):
        """Test print_midas_optimization method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        storm_console.print_midas_optimization("Compile hot paths to WebAssembly")
        
        call_args = safety_wrapper.safe_panel.call_args
        content = call_args[0][1]
        assert "[storm.midas]⚡ MIDAS Optimization:[/storm.midas]" in content
        assert "Compile hot paths to WebAssembly" in content
        assert call_args[1]['style'] == "storm-midas"
        assert call_args[1]['title'] == "⚡ MIDAS WebAssembly Optimization"
    
    def test_print_storm_animation_insight(self):
        """Test print_storm_animation_insight method."""
        console_factory = MockConsoleFactory()
        safety_wrapper = Mock()
        
        storm_console = StormConsole(
            console_factory=console_factory,
            safety_provider=MockSafetyProvider(safety_wrapper)
        )
        
        storm_console.print_storm_animation_insight("Use requestAnimationFrame for smooth animations")
        
        call_args = safety_wrapper.safe_panel.call_args
        content = call_args[0][1]
        assert "[storm.animation]🎬 Storm Animation Insight:[/storm.animation]" in content
        assert "Use requestAnimationFrame for smooth animations" in content
        assert call_args[1]['style'] == "storm-animation"
        assert call_args[1]['title'] == "🎬 60fps Storm Animation System"


class TestGlobalFunctions:
    """Test global functions and instance management."""
    
    def test_get_storm_console_creates_instance(self):
        """Test get_storm_console creates new instance."""
        # The module storm_console is already created during import, 
        # so we test with a custom config to force a new instance
        config = StormLoggerConfig(debug_mode=True)
        console = get_storm_console(config=config)
        
        assert isinstance(console, StormConsole)
        assert console.config is config
        
        # Verify that calling get_storm_console again without config returns the same instance
        console2 = get_storm_console()
        assert console2 is console
    
    def test_get_storm_console_returns_existing_instance(self):
        """Test get_storm_console returns existing instance."""
        import storm_logger.console.storm_console
        
        # Create first instance
        console1 = get_storm_console()
        
        # Get again - should return same instance
        console2 = get_storm_console()
        assert console1 is console2
    
    def test_get_storm_console_with_config_creates_new(self):
        """Test get_storm_console with config creates new instance."""
        import storm_logger.console.storm_console
        
        # Get default instance
        console1 = get_storm_console()
        
        # Get with config - should create new
        config = StormLoggerConfig(debug_mode=True)
        console2 = get_storm_console(config=config)
        
        assert console2 is not console1
        assert console2.config is config
    
    def test_get_storm_console_with_dependencies(self):
        """Test get_storm_console with injected dependencies."""
        # Force a new instance creation with config
        config = StormLoggerConfig()
        console_factory = MockConsoleFactory()
        syntax_factory = MockSyntaxFactory()
        
        console = get_storm_console(
            config=config,  # This forces a new instance
            console_factory=console_factory,
            syntax_factory=syntax_factory
        )
        
        assert console._console_factory is console_factory
        assert console._syntax_factory is syntax_factory
    
    def test_module_level_storm_console_instance(self):
        """Test module-level storm_console instance."""
        from storm_logger.console.storm_console import storm_console
        
        assert isinstance(storm_console, StormConsole)


if __name__ == "__main__":
    pytest.main([__file__, "-v"])