"""
Tests for configuration validation module.
"""

import pytest
import json
import tempfile
import os
from pathlib import Path

from openHealth.core.config import ConfigValidator, ConfigValidationError


class TestConfigValidator:
    """Test cases for ConfigValidator class."""
    
    def setup_method(self):
        """Setup test fixtures."""
        self.validator = ConfigValidator()
    
    def test_validate_url_valid(self):
        """Test URL validation with valid URLs."""
        valid_urls = [
            "https://example.com",
            "http://localhost:8080",
            "https://api.example.com/v1",
            "http://192.168.1.1:3000"
        ]
        
        for url in valid_urls:
            assert self.validator.validate_url(url), f"URL {url} should be valid"
    
    def test_validate_url_invalid(self):
        """Test URL validation with invalid URLs."""
        invalid_urls = [
            "not-a-url",
            "ftp://example.com",
            "example.com",
            "",
            "javascript:alert('xss')"
        ]
        
        for url in invalid_urls:
            assert not self.validator.validate_url(url), f"URL {url} should be invalid"
    
    def test_validate_config_valid(self):
        """Test configuration validation with valid config."""
        valid_config = {
            "services": [
                {
                    "name": "Test Service",
                    "url": "https://example.com",
                    "health_endpoint": "/health",
                    "interval": 60,
                    "timeout": 10,
                    "max_retries": 3,
                    "expected_status_code": 200,
                    "web_interface": {
                        "enabled": False
                    },
                    "slack_integration": {
                        "enabled": False,
                        "channel": "alerts",
                        "api_key": "test-key",
                        "message_template": "Service {name} is down"
                    },
                    "email_alert": {
                        "enabled": False,
                        "recipients": ["test@example.com"],
                        "smtp_server": "smtp.gmail.com",
                        "smtp_port": 587,
                        "username": "test@gmail.com",
                        "app_password": "test-password"
                    }
                }
            ]
        }
        
        # Should not raise exception
        self.validator.validate_config(valid_config)
    
    def test_validate_config_missing_required_fields(self):
        """Test configuration validation with missing required fields."""
        invalid_configs = [
            # Missing services
            {},
            # Empty services array
            {"services": []},
            # Missing required service fields
            {
                "services": [
                    {
                        "url": "https://example.com",
                        "health_endpoint": "/health"
                        # Missing name
                    }
                ]
            },
            {
                "services": [
                    {
                        "name": "Test Service",
                        "health_endpoint": "/health"
                        # Missing url
                    }
                ]
            },
            {
                "services": [
                    {
                        "name": "Test Service",
                        "url": "https://example.com"
                        # Missing health_endpoint
                    }
                ]
            }
        ]
        
        for config in invalid_configs:
            with pytest.raises(ConfigValidationError):
                self.validator.validate_config(config)
    
    def test_validate_config_invalid_url(self):
        """Test configuration validation with invalid URL."""
        invalid_config = {
            "services": [
                {
                    "name": "Test Service",
                    "url": "invalid-url",
                    "health_endpoint": "/health"
                }
            ]
        }
        
        with pytest.raises(ConfigValidationError):
            self.validator.validate_config(invalid_config)
    
    def test_validate_config_invalid_health_endpoint(self):
        """Test configuration validation with invalid health endpoint."""
        invalid_config = {
            "services": [
                {
                    "name": "Test Service",
                    "url": "https://example.com",
                    "health_endpoint": "health"  # Should start with /
                }
            ]
        }
        
        with pytest.raises(ConfigValidationError):
            self.validator.validate_config(invalid_config)
    
    def test_validate_config_enabled_notification_missing_fields(self):
        """Test configuration validation with enabled notifications but missing fields."""
        # Missing Slack fields when enabled
        invalid_config = {
            "services": [
                {
                    "name": "Test Service",
                    "url": "https://example.com",
                    "health_endpoint": "/health",
                    "slack_integration": {
                        "enabled": True,
                        "channel": "alerts"
                        # Missing api_key
                    }
                }
            ]
        }
        
        with pytest.raises(ConfigValidationError) as exc_info:
            self.validator.validate_config(invalid_config)
        assert "api_key" in str(exc_info.value)
    
    def test_validate_config_enabled_email_missing_fields(self):
        """Test configuration validation with enabled email but missing fields."""
        invalid_config = {
            "services": [
                {
                    "name": "Test Service",
                    "url": "https://example.com",
                    "health_endpoint": "/health",
                    "email_alert": {
                        "enabled": True,
                        "recipients": ["test@example.com"]
                        # Missing other required fields
                    }
                }
            ]
        }
        
        with pytest.raises(ConfigValidationError) as exc_info:
            self.validator.validate_config(invalid_config)
        assert any(field in str(exc_info.value) for field in ["smtp_server", "smtp_port", "username", "app_password"])
    
    def test_load_config_file_exists(self):
        """Test loading configuration from existing file."""
        config_data = {
            "services": [
                {
                    "name": "Test Service",
                    "url": "https://example.com",
                    "health_endpoint": "/health"
                }
            ]
        }
        
        with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
            json.dump(config_data, f)
            temp_path = f.name
        
        try:
            loaded_config = self.validator.load_config(temp_path)
            assert loaded_config == config_data
        finally:
            os.unlink(temp_path)
    
    def test_load_config_file_not_found(self):
        """Test loading configuration from non-existent file."""
        with pytest.raises(ConfigValidationError) as exc_info:
            self.validator.load_config("nonexistent_file.json")
        assert "not found" in str(exc_info.value)
    
    def test_load_config_invalid_json(self):
        """Test loading configuration from invalid JSON file."""
        with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
            f.write('{"invalid": json}')
            temp_path = f.name
        
        try:
            with pytest.raises(ConfigValidationError) as exc_info:
                self.validator.load_config(temp_path)
            assert "Invalid JSON" in str(exc_info.value)
        finally:
            os.unlink(temp_path)
    
    def test_get_default_config(self):
        """Test getting default configuration."""
        default_config = self.validator.get_default_config()
        
        assert "services" in default_config
        assert len(default_config["services"]) > 0
        
        service = default_config["services"][0]
        required_fields = ["name", "url", "health_endpoint"]
        for field in required_fields:
            assert field in service
        
        # Check that all notifications are disabled by default
        assert not service["web_interface"]["enabled"]
        assert not service["slack_integration"]["enabled"]
        assert not service["email_alert"]["enabled"]
    
    def test_validate_config_with_valid_emails(self):
        """Test configuration validation with valid email addresses."""
        valid_config = {
            "services": [
                {
                    "name": "Test Service",
                    "url": "https://example.com",
                    "health_endpoint": "/health",
                    "email_alert": {
                        "enabled": True,
                        "recipients": [
                            "test@example.com",
                            "user.name+tag@domain.co.uk",
                            "user123@test-domain.org"
                        ],
                        "smtp_server": "smtp.gmail.com",
                        "smtp_port": 587,
                        "username": "test@gmail.com",
                        "app_password": "test-password"
                    }
                }
            ]
        }
        
        # Should not raise exception
        self.validator.validate_config(valid_config)
    
    def test_validate_config_with_invalid_emails(self):
        """Test configuration validation with invalid email addresses."""
        invalid_config = {
            "services": [
                {
                    "name": "Test Service",
                    "url": "https://example.com",
                    "health_endpoint": "/health",
                    "email_alert": {
                        "enabled": True,
                        "recipients": [
                            "invalid-email",
                            "@example.com",
                            "test@"
                        ],
                        "smtp_server": "smtp.gmail.com",
                        "smtp_port": 587,
                        "username": "test@gmail.com",
                        "app_password": "test-password"
                    }
                }
            ]
        }
        
        with pytest.raises(ConfigValidationError) as exc_info:
            self.validator.validate_config(invalid_config)
        assert "Invalid email format" in str(exc_info.value)
    
    def test_validate_config_edge_cases(self):
        """Test configuration validation with edge cases."""
        # Valid config with minimum required fields
        minimal_config = {
            "services": [
                {
                    "name": "Test",
                    "url": "http://localhost",
                    "health_endpoint": "/"
                }
            ]
        }
        
        # Should not raise exception
        self.validator.validate_config(minimal_config)
        
        # Valid config with all optional fields
        maximal_config = {
            "services": [
                {
                    "name": "Test Service",
                    "url": "https://example.com",
                    "health_endpoint": "/health/check",
                    "interval": 1,
                    "timeout": 1,
                    "max_retries": 1,
                    "expected_status_code": 201,
                    "web_interface": {"enabled": True},
                    "slack_integration": {
                        "enabled": True,
                        "channel": "alerts",
                        "api_key": "xoxb-test-key",
                        "message_template": "Custom template {name}"
                    },
                    "email_alert": {
                        "enabled": True,
                        "recipients": ["test@example.com"],
                        "smtp_server": "smtp.example.com",
                        "smtp_port": 465,
                        "username": "user@example.com",
                        "app_password": "password"
                    }
                }
            ]
        }
        
        # Should not raise exception
        self.validator.validate_config(maximal_config)