"""
Tests for GUI components.

Note: These tests are designed to work even when GUI components cannot be 
fully instantiated due to missing display or tkinter issues.
"""

import pytest
import sys
import os
import tempfile
import json


class TestGUIImports:
    """Test that GUI modules can be imported."""
    
    def test_gui_module_imports(self):
        """Test importing GUI modules."""
        try:
            from hbat.gui.main_window import MainWindow
            from hbat.gui.parameter_panel import ParameterPanel
            from hbat.gui.results_panel import ResultsPanel
            assert True, "GUI modules imported successfully"
        except ImportError as e:
            pytest.skip(f"GUI modules not available: {e}")
    
    def test_chain_visualization_import(self):
        """Test importing chain visualization module."""
        try:
            from hbat.gui.chain_visualization import ChainVisualizationWindow
            assert True, "Chain visualization module imported successfully"
        except ImportError as e:
            pytest.skip(f"Chain visualization module not available: {e}")


@pytest.mark.gui
class TestParameterPanel:
    """Test parameter panel functionality."""
    
    def setup_method(self):
        """Set up test environment."""
        try:
            import tkinter as tk
            from hbat.gui.parameter_panel import ParameterPanel
            
            # Create root window for testing
            self.root = tk.Tk()
            self.root.withdraw()  # Hide window during testing
            
            # Create parameter panel
            self.panel = ParameterPanel(self.root)
            
        except ImportError:
            pytest.skip("tkinter not available")
        except Exception as e:
            pytest.skip(f"GUI setup failed: {e}")
    
    def teardown_method(self):
        """Clean up test environment."""
        if hasattr(self, 'root'):
            try:
                self.root.destroy()
            except Exception:
                pass
    
    def test_parameter_panel_creation(self):
        """Test parameter panel creation."""
        assert self.panel is not None
        assert hasattr(self.panel, 'frame')
        assert hasattr(self.panel, 'get_parameters')
        assert hasattr(self.panel, 'set_parameters')
    
    def test_default_parameters(self):
        """Test default parameter values."""
        params = self.panel.get_parameters()
        
        assert params.hb_distance_cutoff > 0
        assert params.hb_angle_cutoff > 0
        assert params.hb_donor_acceptor_cutoff > 0
        assert params.analysis_mode in ["complete", "local"]
    
    def test_parameter_setting(self):
        """Test setting parameters programmatically."""
        from hbat.core.analysis import AnalysisParameters
        
        test_params = AnalysisParameters(
            hb_distance_cutoff=3.0,
            hb_angle_cutoff=130.0,
            analysis_mode="local"
        )
        
        self.panel.set_parameters(test_params)
        retrieved_params = self.panel.get_parameters()
        
        assert retrieved_params.hb_distance_cutoff == 3.0
        assert retrieved_params.hb_angle_cutoff == 130.0
        assert retrieved_params.analysis_mode == "local"
    
    def test_pdb_fixing_parameter_setting(self):
        """Test setting PDB fixing parameters programmatically."""
        from hbat.core.analysis import AnalysisParameters
        
        test_params = AnalysisParameters(
            fix_pdb_enabled=True,
            fix_pdb_method="pdbfixer",
            fix_pdb_add_hydrogens=True,
            fix_pdb_add_heavy_atoms=True,
            fix_pdb_replace_nonstandard=False,
            fix_pdb_remove_heterogens=True,
            fix_pdb_keep_water=False
        )
        
        self.panel.set_parameters(test_params)
        retrieved_params = self.panel.get_parameters()
        
        assert retrieved_params.fix_pdb_enabled is True
        assert retrieved_params.fix_pdb_method == "pdbfixer"
        assert retrieved_params.fix_pdb_add_hydrogens is True
        assert retrieved_params.fix_pdb_add_heavy_atoms is True
        assert retrieved_params.fix_pdb_replace_nonstandard is False
        assert retrieved_params.fix_pdb_remove_heterogens is True
        assert retrieved_params.fix_pdb_keep_water is False
    
    def test_reset_to_defaults(self):
        """Test resetting parameters to defaults."""
        from hbat.core.analysis import AnalysisParameters
        
        # Set custom parameters
        test_params = AnalysisParameters(hb_distance_cutoff=2.5)
        self.panel.set_parameters(test_params)
        
        # Reset to defaults
        self.panel.reset_to_defaults()
        
        # Check that parameters are back to defaults
        params = self.panel.get_parameters()
        default_params = AnalysisParameters()
        assert params.hb_distance_cutoff == default_params.hb_distance_cutoff
    
    def test_preset_file_operations(self):
        """Test preset file creation and validation."""
        from hbat.core.analysis import AnalysisParameters
        
        # Create test parameters
        test_params = AnalysisParameters(
            hb_distance_cutoff=3.2,
            hb_angle_cutoff=140.0,
            analysis_mode="complete"
        )
        
        # Test preset data creation
        preset_data = self.panel._create_preset_data(test_params)
        
        assert 'format_version' in preset_data
        assert 'parameters' in preset_data
        assert 'hydrogen_bonds' in preset_data['parameters']
        assert preset_data['parameters']['hydrogen_bonds']['h_a_distance_cutoff'] == 3.2
        
        # Test preset validation
        is_valid = self.panel._validate_preset_data(preset_data)
        assert is_valid, "Generated preset should be valid"
    
    def test_preset_data_validation(self):
        """Test preset data validation with various inputs."""
        # Valid preset data
        valid_preset = {
            "format_version": "1.0",
            "parameters": {
                "hydrogen_bonds": {
                    "h_a_distance_cutoff": 3.5,
                    "dha_angle_cutoff": 120.0,
                    "d_a_distance_cutoff": 4.0
                },
                "halogen_bonds": {
                    "x_a_distance_cutoff": 4.0,
                    "cxa_angle_cutoff": 120.0
                },
                "pi_interactions": {
                    "h_pi_distance_cutoff": 4.5,
                    "dh_pi_angle_cutoff": 90.0
                },
                "general": {
                    "covalent_cutoff_factor": 0.85,
                    "analysis_mode": "complete"
                },
                "pdb_fixing": {
                    "enabled": False,
                    "method": "openbabel",
                    "add_hydrogens": True,
                    "add_heavy_atoms": False,
                    "replace_nonstandard": False,
                    "remove_heterogens": False,
                    "keep_water": True
                }
            }
        }
        
        assert self.panel._validate_preset_data(valid_preset), "Valid preset should pass validation"
        
        # Invalid preset data - missing required section
        invalid_preset = {
            "format_version": "1.0",
            "parameters": {
                "hydrogen_bonds": {
                    "h_a_distance_cutoff": 3.5
                }
                # Missing other required sections
            }
        }
        
        assert not self.panel._validate_preset_data(invalid_preset), "Invalid preset should fail validation"
    
    def test_preset_file_save_load_cycle(self):
        """Test complete preset save/load cycle."""
        from hbat.core.analysis import AnalysisParameters
        
        # Create test parameters
        original_params = AnalysisParameters(
            hb_distance_cutoff=3.1,
            hb_angle_cutoff=135.0,
            xb_distance_cutoff=3.8,
            analysis_mode="local",
            fix_pdb_enabled=True,
            fix_pdb_method="openbabel",
            fix_pdb_add_hydrogens=True
        )
        
        # Create preset data
        preset_data = self.panel._create_preset_data(original_params)
        
        # Save to temporary file
        with tempfile.NamedTemporaryFile(mode='w', suffix='.hbat', delete=False) as f:
            self.panel._save_preset_file(f.name, preset_data)
            temp_path = f.name
        
        try:
            # Load from file and validate
            loaded_data = self.panel._load_preset_file(temp_path)
            
            # Apply loaded data
            self.panel._apply_preset_data(loaded_data)
            
            # Get parameters and verify they match original
            loaded_params = self.panel.get_parameters()
            
            assert loaded_params.hb_distance_cutoff == 3.1
            assert loaded_params.hb_angle_cutoff == 135.0
            assert loaded_params.xb_distance_cutoff == 3.8
            assert loaded_params.analysis_mode == "local"
            assert loaded_params.fix_pdb_enabled is True
            assert loaded_params.fix_pdb_method == "openbabel"
            assert loaded_params.fix_pdb_add_hydrogens is True
            
        finally:
            os.unlink(temp_path)


@pytest.mark.gui
class TestResultsPanel:
    """Test results panel functionality."""
    
    def setup_method(self):
        """Set up test environment."""
        try:
            import tkinter as tk
            from hbat.gui.results_panel import ResultsPanel
            
            # Create root window for testing
            self.root = tk.Tk()
            self.root.withdraw()  # Hide window during testing
            
            # Create results panel
            self.panel = ResultsPanel(self.root)
            
        except ImportError:
            pytest.skip("tkinter not available")
        except Exception as e:
            pytest.skip(f"GUI setup failed: {e}")
    
    def teardown_method(self):
        """Clean up test environment."""
        if hasattr(self, 'root'):
            try:
                self.root.destroy()
            except Exception:
                pass
    
    def test_results_panel_creation(self):
        """Test results panel creation."""
        assert self.panel is not None
        assert hasattr(self.panel, 'notebook')
    
    def test_results_display_methods(self):
        """Test methods for displaying results."""
        # Test that display methods exist
        assert hasattr(self.panel, 'update_results'), "Should have update_results method"
        assert hasattr(self.panel, 'clear_results'), "Should have clear_results method"
        
        # Test calling clear_results doesn't raise errors
        try:
            self.panel.clear_results()
        except Exception as e:
            pytest.fail(f"clear_results should not raise error: {e}")


@pytest.mark.gui
class TestChainVisualization:
    """Test chain visualization functionality."""
    
    def test_chain_visualization_import(self):
        """Test importing chain visualization components."""
        try:
            from hbat.gui.chain_visualization import ChainVisualizationWindow
            assert ChainVisualizationWindow is not None
        except ImportError:
            pytest.skip("Chain visualization module not available")
    
    def test_ellipse_node_functionality(self):
        """Test ellipse node drawing functionality."""
        try:
            import tkinter as tk
            from hbat.gui.chain_visualization import ChainVisualizationWindow, VISUALIZATION_AVAILABLE
            
            # Skip if visualization dependencies are not available
            if not VISUALIZATION_AVAILABLE:
                pytest.skip("Visualization dependencies (networkx, matplotlib) not available")
            
            # Create root window for testing
            root = tk.Tk()
            root.withdraw()
            
            try:
                # Create a mock chain object for testing
                from unittest.mock import Mock
                mock_chain = Mock()
                mock_chain.interactions = []
                mock_chain.chain_length = 0
                mock_chain.chain_type = "mock"
                
                # Test that we can create the visualization window with proper parameters
                viz_window = ChainVisualizationWindow(root, mock_chain, "test_chain")
                assert viz_window is not None
                assert hasattr(viz_window, 'viz_window')
                assert hasattr(viz_window, 'G')  # NetworkX graph
                
                # Clean up the visualization window
                if viz_window.viz_window:
                    viz_window.viz_window.destroy()
                
            finally:
                root.destroy()
                
        except ImportError as e:
            pytest.skip(f"Dependencies not available for chain visualization: {e}")
        except Exception as e:
            pytest.skip(f"Chain visualization test failed: {e}")


@pytest.mark.gui
class TestMainWindow:
    """Test main window functionality."""
    
    def test_main_window_import(self):
        """Test importing main window."""
        try:
            from hbat.gui.main_window import MainWindow
            assert MainWindow is not None
        except ImportError:
            pytest.skip("Main window module not available")
    
    def test_main_window_components(self):
        """Test main window has required components."""
        try:
            from hbat.gui.main_window import MainWindow
            
            try:
                # Create main window (MainWindow creates its own root)
                main_window = MainWindow()
                main_window.root.withdraw()  # Hide window during testing
                
                # Test that main window has essential attributes
                assert hasattr(main_window, 'parameter_panel'), "Should have parameter panel"
                assert hasattr(main_window, 'results_panel'), "Should have results panel"
                assert hasattr(main_window, 'root'), "Should have root window"
                assert hasattr(main_window, 'analyzer'), "Should have analyzer attribute"
                
                # Clean up
                main_window.root.destroy()
                
            except Exception as e:
                pytest.skip(f"Main window test failed: {e}")
                
        except ImportError:
            pytest.skip("GUI dependencies not available")


class TestGUIPresetIntegration:
    """Test GUI preset integration without requiring full GUI."""
    
    def test_preset_directory_access(self):
        """Test GUI can access preset directory."""
        try:
            from hbat.gui.parameter_panel import ParameterPanel
            
            # Create mock parameter panel
            panel = ParameterPanel.__new__(ParameterPanel)
            
            # Test directory access methods
            example_dir = panel._get_example_presets_directory()
            user_dir = panel._get_presets_directory()
            
            assert isinstance(example_dir, str), "Example presets directory should be string"
            assert isinstance(user_dir, str), "User presets directory should be string"
            
            # User directory should be created if it doesn't exist
            assert os.path.exists(user_dir), "User presets directory should be created"
            
        except ImportError:
            pytest.skip("GUI modules not available")
    
    def test_preset_file_format_compatibility(self):
        """Test GUI preset file format compatibility."""
        try:
            from hbat.gui.parameter_panel import ParameterPanel
            from hbat.cli.main import load_preset_file
            
            # Create a preset using GUI format
            panel = ParameterPanel.__new__(ParameterPanel)
            
            from hbat.core.analysis import AnalysisParameters
            test_params = AnalysisParameters(
                hb_distance_cutoff=3.3,
                hb_angle_cutoff=125.0,
                fix_pdb_enabled=True,
                fix_pdb_method="pdbfixer",
                fix_pdb_add_hydrogens=True,
                fix_pdb_add_heavy_atoms=False
            )
            
            gui_preset_data = panel._create_preset_data(test_params)
            
            # Save to temporary file
            with tempfile.NamedTemporaryFile(mode='w', suffix='.hbat', delete=False) as f:
                json.dump(gui_preset_data, f)
                temp_path = f.name
            
            try:
                # Test that CLI can load GUI-created preset
                cli_params = load_preset_file(temp_path)
                
                assert cli_params.hb_distance_cutoff == 3.3
                assert cli_params.hb_angle_cutoff == 125.0
                assert cli_params.fix_pdb_enabled is True
                assert cli_params.fix_pdb_method == "pdbfixer"
                assert cli_params.fix_pdb_add_hydrogens is True
                
            except SystemExit:
                # Acceptable if CLI loading fails in test environment
                pass
            finally:
                os.unlink(temp_path)
                
        except ImportError:
            pytest.skip("GUI or CLI modules not available")