"""
Test suite for connector configuration management
"""

import pytest
import os
import tempfile
import json
import yaml
from pathlib import Path
from connectors.config import (
    ConnectionConfig, ConfluenceConfig, JiraConfig,
    ConfigManager, get_config_manager, load_config_from_file,
    create_sample_config
)
from connectors.exceptions import ConfigurationError


class TestConnectionConfig:
    """Test base ConnectionConfig class"""
    
    def test_valid_connection_config(self):
        """Test creating valid connection config"""
        config = ConnectionConfig(
            url="https://example.com",
            timeout=30,
            max_retries=3
        )
        
        assert config.url == "https://example.com"
        assert config.timeout == 30
        assert config.max_retries == 3
        assert config.verify_ssl is True  # Default value
    
    def test_connection_config_validation(self):
        """Test connection config validation"""
        # Test missing URL
        with pytest.raises(ConfigurationError, match="URL is required"):
            config = ConnectionConfig(url="")
            config.validate()
        
        # Test invalid timeout
        with pytest.raises(ConfigurationError, match="Timeout must be positive"):
            config = ConnectionConfig(url="https://example.com", timeout=0)
            config.validate()
        
        # Test invalid max_retries
        with pytest.raises(ConfigurationError, match="Max retries must be non-negative"):
            config = ConnectionConfig(url="https://example.com", max_retries=-1)
            config.validate()


class TestConfluenceConfig:
    """Test ConfluenceConfig class"""
    
    def test_valid_confluence_config(self):
        """Test creating valid Confluence config"""
        config = ConfluenceConfig(
            url="https://confluence.example.com",
            token="test_token",
            cloud=True
        )
        
        config.validate()  # Should not raise
        assert config.url == "https://confluence.example.com"
        assert config.token == "test_token"
        assert config.cloud is True
    
    def test_confluence_config_auth_validation(self):
        """Test Confluence config authentication validation"""
        # Test missing authentication
        with pytest.raises(ConfigurationError, match="Either token or username/password"):
            config = ConfluenceConfig(url="https://confluence.example.com")
            config.validate()
        
        # Test username/password auth
        config = ConfluenceConfig(
            url="https://confluence.example.com",
            username="user",
            password="pass"
        )
        config.validate()  # Should not raise
    
    def test_confluence_config_ocr_validation(self):
        """Test OCR confidence threshold validation"""
        with pytest.raises(ConfigurationError, match="OCR confidence threshold"):
            config = ConfluenceConfig(
                url="https://confluence.example.com",
                token="token",
                ocr_confidence_threshold=150.0  # Invalid (> 100)
            )
            config.validate()


class TestJiraConfig:
    """Test JiraConfig class"""
    
    def test_valid_jira_config(self):
        """Test creating valid Jira config"""
        config = JiraConfig(
            url="https://jira.example.com",
            token="test_token"
        )
        
        config.validate()  # Should not raise
        assert config.url == "https://jira.example.com"
        assert config.token == "test_token"
    
    def test_jira_config_auth_validation(self):
        """Test Jira config authentication validation"""
        # Test missing authentication
        with pytest.raises(ConfigurationError, match="At least one authentication method"):
            config = JiraConfig(url="https://jira.example.com")
            config.validate()
        
        # Test API token auth
        config = JiraConfig(
            url="https://jira.example.com",
            api_token="api_token"
        )
        config.validate()  # Should not raise


class TestConfigManager:
    """Test ConfigManager class"""
    
    def setup_method(self):
        """Setup test environment"""
        self.temp_dir = tempfile.mkdtemp()
        self.config_file = os.path.join(self.temp_dir, "test_config.yaml")
        
        # Clear any existing environment variables
        self.original_env = {}
        for key in list(os.environ.keys()):
            if key.startswith(('CONNECTORS_', 'CONFLUENCE_', 'JIRA_')):
                self.original_env[key] = os.environ.pop(key)
    
    def teardown_method(self):
        """Cleanup test environment"""
        import shutil
        shutil.rmtree(self.temp_dir)
        
        # Restore original environment variables
        for key, value in self.original_env.items():
            os.environ[key] = value
    
    def test_config_manager_with_yaml_file(self):
        """Test loading config from YAML file"""
        config_data = {
            'log_level': 'DEBUG',
            'timeout': 60,
            'confluence': {
                'url': 'https://confluence.test.com',
                'token': 'yaml_token'
            },
            'jira': {
                'url': 'https://jira.test.com',
                'token': 'jira_yaml_token'
            }
        }
        
        with open(self.config_file, 'w') as f:
            yaml.dump(config_data, f)
        
        manager = ConfigManager(self.config_file)
        
        confluence_config = manager.get_confluence_config()
        assert confluence_config.url == 'https://confluence.test.com'
        assert confluence_config.token == 'yaml_token'
        assert confluence_config.timeout == 60  # Inherited from common
        
        jira_config = manager.get_jira_config()
        assert jira_config.url == 'https://jira.test.com'
        assert jira_config.token == 'jira_yaml_token'
    
    def test_config_manager_with_json_file(self):
        """Test loading config from JSON file"""
        config_data = {
            'log_level': 'INFO',
            'confluence': {
                'url': 'https://confluence.json.com',
                'token': 'json_token'
            }
        }
        
        json_file = os.path.join(self.temp_dir, "test_config.json")
        with open(json_file, 'w') as f:
            json.dump(config_data, f)
        
        manager = ConfigManager(json_file)
        
        confluence_config = manager.get_confluence_config()
        assert confluence_config.url == 'https://confluence.json.com'
        assert confluence_config.token == 'json_token'
    
    def test_config_manager_environment_override(self):
        """Test environment variable overrides"""
        # Create basic config file
        config_data = {
            'confluence': {
                'url': 'https://confluence.file.com',
                'token': 'file_token'
            }
        }
        
        with open(self.config_file, 'w') as f:
            yaml.dump(config_data, f)
        
        # Set environment variables
        os.environ['CONFLUENCE_TOKEN'] = 'env_token'
        os.environ['CONNECTORS_TIMEOUT'] = '45'
        
        manager = ConfigManager(self.config_file)
        
        confluence_config = manager.get_confluence_config()
        assert confluence_config.url == 'https://confluence.file.com'  # From file
        assert confluence_config.token == 'env_token'  # From environment
        assert confluence_config.timeout == 45  # From environment
    
    def test_config_manager_missing_file(self):
        """Test handling of missing config file"""
        manager = ConfigManager('/nonexistent/config.yaml')
        
        # Should work with defaults and environment variables
        os.environ['CONFLUENCE_URL'] = 'https://confluence.env.com'
        os.environ['CONFLUENCE_TOKEN'] = 'env_token'
        
        confluence_config = manager.get_confluence_config()
        assert confluence_config.url == 'https://confluence.env.com'
        assert confluence_config.token == 'env_token'
    
    def test_config_manager_invalid_file_format(self):
        """Test handling of invalid file format"""
        invalid_file = os.path.join(self.temp_dir, "invalid.txt")
        with open(invalid_file, 'w') as f:
            f.write("invalid config")
        
        with pytest.raises(ConfigurationError, match="Unsupported config file format"):
            ConfigManager(invalid_file)
    
    def test_config_manager_invalid_yaml(self):
        """Test handling of invalid YAML"""
        invalid_yaml_file = os.path.join(self.temp_dir, "invalid.yaml")
        with open(invalid_yaml_file, 'w') as f:
            f.write("invalid: yaml: content: [")
        
        with pytest.raises(ConfigurationError, match="Failed to load config file"):
            ConfigManager(invalid_yaml_file)
    
    def test_config_manager_reload(self):
        """Test config reloading"""
        # Create initial config
        config_data = {'confluence': {'url': 'https://initial.com'}}
        with open(self.config_file, 'w') as f:
            yaml.dump(config_data, f)
        
        manager = ConfigManager(self.config_file)
        initial_config = manager.get_confluence_config()
        assert initial_config.url == 'https://initial.com'
        
        # Update config file
        config_data = {'confluence': {'url': 'https://updated.com'}}
        with open(self.config_file, 'w') as f:
            yaml.dump(config_data, f)
        
        manager.reload()
        updated_config = manager.get_confluence_config()
        assert updated_config.url == 'https://updated.com'


class TestConfigUtilities:
    """Test configuration utility functions"""
    
    def setup_method(self):
        """Setup test environment"""
        self.temp_dir = tempfile.mkdtemp()
    
    def teardown_method(self):
        """Cleanup test environment"""
        import shutil
        shutil.rmtree(self.temp_dir)
    
    def test_load_config_from_file_yaml(self):
        """Test loading config from YAML file"""
        config_data = {'test': 'value'}
        config_file = os.path.join(self.temp_dir, "config.yaml")
        
        with open(config_file, 'w') as f:
            yaml.dump(config_data, f)
        
        result = load_config_from_file(config_file)
        assert result == config_data
    
    def test_load_config_from_file_json(self):
        """Test loading config from JSON file"""
        config_data = {'test': 'value'}
        config_file = os.path.join(self.temp_dir, "config.json")
        
        with open(config_file, 'w') as f:
            json.dump(config_data, f)
        
        result = load_config_from_file(config_file)
        assert result == config_data
    
    def test_load_config_from_file_not_found(self):
        """Test loading non-existent config file"""
        with pytest.raises(ConfigurationError, match="Config file not found"):
            load_config_from_file('/nonexistent/config.yaml')
    
    def test_create_sample_config_yaml(self):
        """Test creating sample YAML config"""
        config_file = os.path.join(self.temp_dir, "sample.yaml")
        create_sample_config(config_file, "yaml")
        
        assert Path(config_file).exists()
        
        with open(config_file, 'r') as f:
            config = yaml.safe_load(f)
        
        assert 'confluence' in config
        assert 'jira' in config
        assert config['confluence']['url'] == 'https://your-confluence.atlassian.net'
        assert config['jira']['url'] == 'https://your-jira.atlassian.net'
    
    def test_create_sample_config_json(self):
        """Test creating sample JSON config"""
        config_file = os.path.join(self.temp_dir, "sample.json")
        create_sample_config(config_file, "json")
        
        assert Path(config_file).exists()
        
        with open(config_file, 'r') as f:
            config = json.load(f)
        
        assert 'confluence' in config
        assert 'jira' in config
    
    def test_create_sample_config_invalid_format(self):
        """Test creating sample config with invalid format"""
        config_file = os.path.join(self.temp_dir, "sample.txt")
        
        with pytest.raises(ConfigurationError, match="Unsupported format"):
            create_sample_config(config_file, "txt")


class TestGlobalConfigManager:
    """Test global configuration manager"""
    
    def setup_method(self):
        """Setup test environment"""
        # Clear global config manager
        import connectors.config
        connectors.config._config_manager = None
    
    def test_get_config_manager_singleton(self):
        """Test that get_config_manager returns singleton"""
        manager1 = get_config_manager()
        manager2 = get_config_manager()
        
        assert manager1 is manager2
    
    def test_get_config_manager_with_file(self):
        """Test getting config manager with specific file"""
        temp_dir = tempfile.mkdtemp()
        config_file = os.path.join(temp_dir, "test_config.yaml")
        
        with open(config_file, 'w') as f:
            yaml.dump({'test': 'value'}, f)
        
        try:
            manager = get_config_manager(config_file)
            assert isinstance(manager, ConfigManager)
        finally:
            import shutil
            shutil.rmtree(temp_dir)
