"""Enhanced tests for LSC Optimizer GUI functionality."""

from __future__ import annotations

import pytest

# Check if PySide2 is available
try:
    from PySide2.QtCore import Qt

    GUI_AVAILABLE = True
except ImportError:
    GUI_AVAILABLE = False

# Check if pytest-qt is available
try:
    from importlib.util import find_spec

    find_spec("pytestqt")
    PYTEST_QT_AVAILABLE = True
except (ImportError, ValueError, AttributeError):
    PYTEST_QT_AVAILABLE = False

# Import GUI components conditionally
if GUI_AVAILABLE:
    try:
        from ..lscopt_gui import ConfigManager, LSCOptimizerGUI
    except ImportError:
        try:
            from ..lscopt_gui import ConfigManager, LSCOptimizerGUI
        except ImportError:
            GUI_AVAILABLE = False


@pytest.mark.skipif(not (GUI_AVAILABLE and PYTEST_QT_AVAILABLE), reason="PySide2 or pytest-qt not available")
class TestEnhancedLSCOptimizerGUI:
    """Enhanced tests for LSC Optimizer GUI functionality."""

    def test_parameter_validation(self, qtbot):
        """Test parameter input validation."""
        window = LSCOptimizerGUI()
        qtbot.addWidget(window)

        # Test that parameter widgets have proper ranges
        m_widget = window.param_widgets["m"]
        assert m_widget.spinbox.minimum() == -5.0
        assert m_widget.spinbox.maximum() == 0.0
        assert m_widget.spinbox.singleStep() == 0.05

        h_widget = window.param_widgets["H"]
        assert h_widget.spinbox.minimum() == 0.0
        assert h_widget.spinbox.maximum() == 5.0
        assert h_widget.spinbox.singleStep() == 0.1

    def test_parameter_interaction(self, qtbot):
        """Test parameter widget interaction."""
        window = LSCOptimizerGUI()
        qtbot.addWidget(window)

        # Change a parameter value
        m_widget = window.param_widgets["m"]
        original_value = m_widget.get_value()

        # Simulate user input
        m_widget.spinbox.setValue(-2.0)
        assert m_widget.get_value() == -2.0
        assert m_widget.get_value() != original_value

    def test_calculation_workflow(self, qtbot):
        """Test complete calculation workflow."""
        window = LSCOptimizerGUI()
        qtbot.addWidget(window)

        # Set some parameters
        window.param_widgets["m"].set_value(-1.5)
        window.param_widgets["H"].set_value(0.8)

        # Trigger calculation
        qtbot.mouseClick(window.calculate_button, Qt.LeftButton)

        # Check that results were updated (give some time for computation)
        qtbot.wait(100)  # Wait 100ms for calculation

        # Results should be displayed in status bar
        status_text = window.calc_status_label.text()
        assert "计算完成" in status_text or "Error" in status_text or "✓" in status_text

    def test_reset_functionality(self, qtbot):
        """Test reset to default values functionality."""
        window = LSCOptimizerGUI()
        qtbot.addWidget(window)

        # Change some parameters
        m_widget = window.param_widgets["m"]
        original_default = m_widget.default_value
        m_widget.set_value(-3.0)

        # Reset to defaults
        qtbot.mouseClick(window.reset_button, Qt.LeftButton)

        # Check that parameters were reset and status is ready
        assert m_widget.get_value() == original_default
        assert "准备计算" in window.calc_status_label.text() or "Ready" in window.calc_status_label.text()

    def test_window_state_persistence(self, qtbot):
        """Test that window state is properly managed."""
        window1 = LSCOptimizerGUI()
        qtbot.addWidget(window1)

        # Change window size and position (respecting minimum size constraints)
        # Note: Window has minimum width of 1200px, so requesting 1100px will result in 1200px
        window1.resize(1300, 750)  # Use size larger than minimum to test persistence
        window1.move(150, 150)

        # Force the window to process events to ensure resize is applied
        qtbot.wait(50)  # Wait for UI events to process

        # Close window (triggers save)
        window1.close()

        # Create new window and check if settings persisted
        window2 = LSCOptimizerGUI()
        qtbot.addWidget(window2)

        # Check that configuration was loaded
        config = window2.config_manager.get_config()
        assert config.window_width == 1300
        assert config.window_height == 750


@pytest.mark.skipif(not (GUI_AVAILABLE and PYTEST_QT_AVAILABLE), reason="PySide2 or pytest-qt not available")
class TestConfigPersistence:
    """Tests for configuration persistence functionality."""

    def test_config_save_load(self, tmp_path):
        """Test configuration save and load functionality."""
        # Create temporary config file
        config_file = tmp_path / "test_config.json"
        config_manager = ConfigManager(config_file)

        # Modify some settings
        config_manager.update_config(m=-2.0, H=1.0, window_width=1100)
        config_manager.save_config()

        # Create new manager with same file
        new_manager = ConfigManager(config_file)
        config = new_manager.get_config()

        # Check that settings were preserved
        assert config.m == -2.0
        assert config.H == 1.0
        assert config.window_width == 1100

    def test_config_defaults_fallback(self, tmp_path):
        """Test that defaults are used when config file is corrupted."""
        # Create corrupted config file
        config_file = tmp_path / "corrupted_config.json"
        config_file.write_text("invalid json content")

        # Should fall back to defaults
        config_manager = ConfigManager(config_file)
        config = config_manager.get_config()

        # Check that we got default values
        default_config = ConfigManager.DEFAULT_CONFIG
        assert config.m == default_config.m
        assert config.H == default_config.H


@pytest.mark.skipif(not GUI_AVAILABLE, reason="PySide2 not available")
def test_cli_entry_point():
    """Test that CLI entry point works."""
    from ..lscopt_gui import main

    # We can't actually run the GUI in tests, but we can verify the function exists
    assert callable(main)


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