"""
Tests for HealthChecker initialization options.
"""

import pytest
import tempfile
import json
import os
from unittest.mock import patch, MagicMock

from openHealth import HealthChecker, load_config, validate_config
from openHealth.core.config import ConfigValidationError


class TestHealthCheckerInitialization:
    """Test cases for HealthChecker initialization options."""
    
    def setup_method(self):
        """Setup test fixtures."""
        self.test_config = {
            "services": [
                {
                    "name": "Test Service",
                    "url": "https://example.com",
                    "health_endpoint": "/health",
                    "interval": 60,
                    "timeout": 10,
                    "max_retries": 3,
                    "expected_status_code": 200
                }
            ]
        }
        
        # Create temporary config file
        self.temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False)
        json.dump(self.test_config, self.temp_file)
        self.temp_file.close()
    
    def teardown_method(self):
        """Cleanup after tests."""
        if os.path.exists(self.temp_file.name):
            os.unlink(self.temp_file.name)
    
    def test_init_with_config_path(self):
        """Test HealthChecker initialization with config_path (original behavior)."""
        with patch('openHealth.client.setup_logging'):
            checker = HealthChecker(config_path=self.temp_file.name)
            
            assert checker.config_path == self.temp_file.name
            assert checker.config is not None
            assert len(checker.services) == 1
            assert checker.services[0]['name'] == "Test Service"
    
    def test_init_with_config_dict(self):
        """Test HealthChecker initialization with config dict (new behavior)."""
        with patch('openHealth.client.setup_logging'):
            checker = HealthChecker(config=self.test_config)
            
            assert checker.config_path is None
            assert checker.config is not None
            assert len(checker.services) == 1
            assert checker.services[0]['name'] == "Test Service"
    
    def test_init_with_both_parameters_raises_error(self):
        """Test that providing both config_path and config raises ValueError."""
        with patch('openHealth.client.setup_logging'):
            with pytest.raises(ValueError) as exc_info:
                HealthChecker(config_path=self.temp_file.name, config=self.test_config)
            
            assert "Cannot provide both" in str(exc_info.value)
    
    def test_init_with_neither_parameter_uses_default(self):
        """Test that providing neither parameter uses default config_path."""
        with patch('openHealth.client.setup_logging') as mock_setup:
            # This should try to load from "config.json" and fail, but we can patch it
            with patch.object(HealthChecker, 'load_config'):
                checker = HealthChecker()
                assert checker.config_path == "config.json"
                assert checker.config is None  # Will be set by load_config
    
    def test_init_with_invalid_config_dict_raises_error(self):
        """Test that invalid config dict raises ConfigValidationError."""
        invalid_config = {"invalid": "config"}
        
        with patch('openHealth.client.setup_logging'):
            with pytest.raises(ConfigValidationError):
                HealthChecker(config=invalid_config)
    
    def test_init_with_invalid_config_path_raises_error(self):
        """Test that invalid config path raises ConfigValidationError."""
        with patch('openHealth.client.setup_logging'):
            with pytest.raises(ConfigValidationError):
                HealthChecker(config_path="nonexistent_file.json")
    
    def test_init_log_level_and_log_file_parameters(self):
        """Test that log_level and log_file parameters work correctly."""
        with patch('openHealth.client.setup_logging') as mock_setup:
            HealthChecker(config=self.test_config, log_level="DEBUG", log_file="test.log")
            
            mock_setup.assert_called_once_with(level="DEBUG", log_file="test.log")
    
    def test_component_initialization_with_config_dict(self):
        """Test that components are properly initialized when using config dict."""
        with patch('openHealth.client.setup_logging'):
            checker = HealthChecker(config=self.test_config)
            
            # Components should be initialized
            assert checker.config_validator is not None
            assert checker.executor is not None
            assert hasattr(checker, 'email_notifiers')
            assert hasattr(checker, 'slack_notifiers')
    
    def test_component_initialization_with_config_path(self):
        """Test that components are properly initialized when using config path."""
        with patch('openHealth.client.setup_logging'):
            checker = HealthChecker(config_path=self.temp_file.name)
            
            # Components should be initialized
            assert checker.config_validator is not None
            assert checker.executor is not None
            assert hasattr(checker, 'email_notifiers')
            assert hasattr(checker, 'slack_notifiers')


class TestStandaloneFunctions:
    """Test cases for standalone configuration functions."""
    
    def setup_method(self):
        """Setup test fixtures."""
        self.test_config = {
            "services": [
                {
                    "name": "Test Service",
                    "url": "https://example.com",
                    "health_endpoint": "/health"
                }
            ]
        }
        
        # Create temporary config file
        self.temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False)
        json.dump(self.test_config, self.temp_file)
        self.temp_file.close()
    
    def teardown_method(self):
        """Cleanup after tests."""
        if os.path.exists(self.temp_file.name):
            os.unlink(self.temp_file.name)
    
    def test_load_config_function(self):
        """Test standalone load_config function."""
        config = load_config(self.temp_file.name)
        
        assert config == self.test_config
        assert len(config['services']) == 1
    
    def test_load_config_function_with_invalid_file(self):
        """Test load_config function with invalid file."""
        with pytest.raises(ConfigValidationError):
            load_config("nonexistent_file.json")
    
    def test_validate_config_function(self):
        """Test standalone validate_config function."""
        # Should not raise exception for valid config
        validate_config(self.test_config)
    
    def test_validate_config_function_with_invalid_config(self):
        """Test validate_config function with invalid config."""
        invalid_config = {"invalid": "config"}
        
        with pytest.raises(ConfigValidationError):
            validate_config(invalid_config)
    
    def test_validate_config_function_with_missing_required_fields(self):
        """Test validate_config function with missing required fields."""
        invalid_config = {"services": []}
        
        with pytest.raises(ConfigValidationError):
            validate_config(invalid_config)


class TestInitializationIntegration:
    """Integration tests for HealthChecker initialization."""
    
    def setup_method(self):
        """Setup test fixtures."""
        self.test_config = {
            "services": [
                {
                    "name": "Test Service 1",
                    "url": "https://service1.example.com",
                    "health_endpoint": "/health",
                    "interval": 30
                },
                {
                    "name": "Test Service 2", 
                    "url": "https://service2.example.com",
                    "health_endpoint": "/status",
                    "interval": 60
                }
            ]
        }
        
        # Create temporary config file
        self.temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False)
        json.dump(self.test_config, self.temp_file)
        self.temp_file.close()
    
    def teardown_method(self):
        """Cleanup after tests."""
        if os.path.exists(self.temp_file.name):
            os.unlink(self.temp_file.name)
    
    def test_file_based_initialization_integration(self):
        """Test complete integration with file-based initialization."""
        with patch('openHealth.client.setup_logging'):
            # Load config using standalone function
            config = load_config(self.temp_file.name)
            
            # Initialize HealthChecker with pre-loaded config
            checker = HealthChecker(config=config)
            
            # Verify services are loaded correctly
            assert len(checker.services) == 2
            service_names = [s['name'] for s in checker.services]
            assert "Test Service 1" in service_names
            assert "Test Service 2" in service_names
    
    def test_both_initialization_methods_produce_same_result(self):
        """Test that both initialization methods produce the same result."""
        with patch('openHealth.client.setup_logging'):
            # Method 1: File-based
            checker1 = HealthChecker(config_path=self.temp_file.name)
            
            # Method 2: Direct config
            config = load_config(self.temp_file.name)
            checker2 = HealthChecker(config=config)
            
            # Both should have the same services
            assert len(checker1.services) == len(checker2.services)
            assert checker1.services[0]['name'] == checker2.services[0]['name']
            assert checker1.services[1]['name'] == checker2.services[1]['name']
    
    def test_initialization_with_notifications(self):
        """Test initialization with notification configurations."""
        config_with_notifications = {
            "services": [
                {
                    "name": "Test Service",
                    "url": "https://example.com",
                    "health_endpoint": "/health",
                    "slack_integration": {
                        "enabled": True,
                        "channel": "alerts",
                        "webhook_url": "https://hooks.slack.com/test"
                    }
                }
            ]
        }
        
        with patch('openHealth.client.setup_logging'):
            checker = HealthChecker(config=config_with_notifications)
            
            # Should have slack notifier initialized
            assert len(checker.slack_notifiers) == 1
            assert "Test Service" in checker.slack_notifiers