"""Tests for configuration management module."""

import json
from pathlib import Path

import pytest

from webdrop_bridge.config import Config, ConfigurationError
from webdrop_bridge.core.config_manager import ConfigExporter, ConfigProfile, ConfigValidator


class TestConfigValidator:
    """Test configuration validation."""

    def test_validate_valid_config(self):
        """Test validation passes for valid configuration."""
        config_dict = {
            "app_name": "WebDrop Bridge",
            "app_version": "1.0.0",
            "log_level": "INFO",
            "log_file": None,
            "allowed_roots": ["/home", "/data"],
            "allowed_urls": ["http://example.com"],
            "webapp_url": "http://localhost:8080",
            "window_width": 800,
            "window_height": 600,
            "enable_logging": True,
        }

        errors = ConfigValidator.validate(config_dict)
        assert errors == []

    def test_validate_missing_required_field(self):
        """Test validation fails for missing required fields."""
        config_dict = {
            "app_name": "WebDrop Bridge",
            "app_version": "1.0.0",
        }

        errors = ConfigValidator.validate(config_dict)
        assert len(errors) > 0
        assert any("log_level" in e for e in errors)

    def test_validate_invalid_type(self):
        """Test validation fails for invalid type."""
        config_dict = {
            "app_name": "WebDrop Bridge",
            "app_version": "1.0.0",
            "log_level": "INFO",
            "log_file": None,
            "allowed_roots": ["/home"],
            "allowed_urls": ["http://example.com"],
            "webapp_url": "http://localhost:8080",
            "window_width": "800",  # Should be int
            "window_height": 600,
            "enable_logging": True,
        }

        errors = ConfigValidator.validate(config_dict)
        assert len(errors) > 0
        assert any("window_width" in e for e in errors)

    def test_validate_invalid_log_level(self):
        """Test validation fails for invalid log level."""
        config_dict = {
            "app_name": "WebDrop Bridge",
            "app_version": "1.0.0",
            "log_level": "TRACE",  # Invalid
            "log_file": None,
            "allowed_roots": [],
            "allowed_urls": [],
            "webapp_url": "http://localhost:8080",
            "window_width": 800,
            "window_height": 600,
            "enable_logging": True,
        }

        errors = ConfigValidator.validate(config_dict)
        assert len(errors) > 0
        assert any("log_level" in e for e in errors)

    def test_validate_invalid_version_format(self):
        """Test validation fails for invalid version format."""
        config_dict = {
            "app_name": "WebDrop Bridge",
            "app_version": "1.0",  # Should be X.Y.Z
            "log_level": "INFO",
            "log_file": None,
            "allowed_roots": [],
            "allowed_urls": [],
            "webapp_url": "http://localhost:8080",
            "window_width": 800,
            "window_height": 600,
            "enable_logging": True,
        }

        errors = ConfigValidator.validate(config_dict)
        # Note: Current implementation doesn't check regex pattern
        # This test documents the expected behavior for future enhancement

    def test_validate_out_of_range_value(self):
        """Test validation fails for values outside allowed range."""
        config_dict = {
            "app_name": "WebDrop Bridge",
            "app_version": "1.0.0",
            "log_level": "INFO",
            "log_file": None,
            "allowed_roots": [],
            "allowed_urls": [],
            "webapp_url": "http://localhost:8080",
            "window_width": 100,  # Below minimum of 400
            "window_height": 600,
            "enable_logging": True,
        }

        errors = ConfigValidator.validate(config_dict)
        assert len(errors) > 0
        assert any("window_width" in e for e in errors)

    def test_validate_or_raise_valid(self):
        """Test validate_or_raise succeeds for valid config."""
        config_dict = {
            "app_name": "WebDrop Bridge",
            "app_version": "1.0.0",
            "log_level": "INFO",
            "log_file": None,
            "allowed_roots": [],
            "allowed_urls": [],
            "webapp_url": "http://localhost:8080",
            "window_width": 800,
            "window_height": 600,
            "enable_logging": True,
        }

        # Should not raise
        ConfigValidator.validate_or_raise(config_dict)

    def test_validate_or_raise_invalid(self):
        """Test validate_or_raise raises for invalid config."""
        config_dict = {
            "app_name": "WebDrop Bridge",
            "app_version": "1.0.0",
        }

        with pytest.raises(ConfigurationError) as exc_info:
            ConfigValidator.validate_or_raise(config_dict)

        assert "Configuration validation failed" in str(exc_info.value)


class TestConfigProfile:
    """Test configuration profile management."""

    @pytest.fixture
    def profile_manager(self, tmp_path, monkeypatch):
        """Create profile manager with temporary directory."""
        monkeypatch.setattr(ConfigProfile, "PROFILES_DIR", tmp_path / "profiles")
        return ConfigProfile()

    @pytest.fixture
    def sample_config(self):
        """Create sample configuration."""
        return Config(
            app_name="WebDrop Bridge",
            app_version="1.0.0",
            log_level="INFO",
            log_file=None,
            allowed_roots=[Path("/home"), Path("/data")],
            allowed_urls=["http://example.com"],
            webapp_url="http://localhost:8080",
            window_width=800,
            window_height=600,
            enable_logging=True,
        )

    def test_save_profile(self, profile_manager, sample_config):
        """Test saving a profile."""
        profile_path = profile_manager.save_profile("work", sample_config)

        assert profile_path.exists()
        assert profile_path.name == "work.json"

    def test_load_profile(self, profile_manager, sample_config):
        """Test loading a profile."""
        profile_manager.save_profile("work", sample_config)
        loaded = profile_manager.load_profile("work")

        assert loaded["app_name"] == "WebDrop Bridge"
        assert loaded["log_level"] == "INFO"
        assert loaded["window_width"] == 800

    def test_load_nonexistent_profile(self, profile_manager):
        """Test loading nonexistent profile raises error."""
        with pytest.raises(ConfigurationError) as exc_info:
            profile_manager.load_profile("nonexistent")

        assert "Profile not found" in str(exc_info.value)

    def test_list_profiles(self, profile_manager, sample_config):
        """Test listing profiles."""
        profile_manager.save_profile("work", sample_config)
        profile_manager.save_profile("personal", sample_config)

        profiles = profile_manager.list_profiles()

        assert "work" in profiles
        assert "personal" in profiles
        assert len(profiles) == 2

    def test_delete_profile(self, profile_manager, sample_config):
        """Test deleting a profile."""
        profile_manager.save_profile("work", sample_config)
        assert profile_manager.list_profiles() == ["work"]

        profile_manager.delete_profile("work")
        assert profile_manager.list_profiles() == []

    def test_delete_nonexistent_profile(self, profile_manager):
        """Test deleting nonexistent profile raises error."""
        with pytest.raises(ConfigurationError) as exc_info:
            profile_manager.delete_profile("nonexistent")

        assert "Profile not found" in str(exc_info.value)

    def test_invalid_profile_name(self, profile_manager, sample_config):
        """Test invalid profile names are rejected."""
        with pytest.raises(ConfigurationError) as exc_info:
            profile_manager.save_profile("work/personal", sample_config)

        assert "Invalid profile name" in str(exc_info.value)


class TestConfigExporter:
    """Test configuration export/import."""

    @pytest.fixture
    def sample_config(self):
        """Create sample configuration."""
        return Config(
            app_name="WebDrop Bridge",
            app_version="1.0.0",
            log_level="INFO",
            log_file=None,
            allowed_roots=[Path("/home"), Path("/data")],
            allowed_urls=["http://example.com"],
            webapp_url="http://localhost:8080",
            window_width=800,
            window_height=600,
            window_title="WebDrop Bridge v1.0.0",
            enable_logging=True,
        )

    def test_export_to_json(self, tmp_path, sample_config):
        """Test exporting configuration to JSON."""
        output_file = tmp_path / "config.json"

        ConfigExporter.export_to_json(sample_config, output_file)

        assert output_file.exists()

        data = json.loads(output_file.read_text())
        assert data["app_name"] == "WebDrop Bridge"
        assert data["log_level"] == "INFO"

    def test_import_from_json(self, tmp_path, sample_config):
        """Test importing configuration from JSON."""
        # Export first
        output_file = tmp_path / "config.json"
        ConfigExporter.export_to_json(sample_config, output_file)

        # Import
        imported = ConfigExporter.import_from_json(output_file)

        assert imported["app_name"] == "WebDrop Bridge"
        assert imported["log_level"] == "INFO"
        assert imported["window_width"] == 800

    def test_import_nonexistent_file(self):
        """Test importing nonexistent file raises error."""
        with pytest.raises(ConfigurationError) as exc_info:
            ConfigExporter.import_from_json(Path("/nonexistent/file.json"))

        assert "File not found" in str(exc_info.value)

    def test_import_invalid_json(self, tmp_path):
        """Test importing invalid JSON raises error."""
        invalid_file = tmp_path / "invalid.json"
        invalid_file.write_text("{ invalid json }")

        with pytest.raises(ConfigurationError) as exc_info:
            ConfigExporter.import_from_json(invalid_file)

        assert "Invalid JSON" in str(exc_info.value)

    def test_import_invalid_config(self, tmp_path):
        """Test importing JSON with invalid config raises error."""
        invalid_file = tmp_path / "invalid_config.json"
        invalid_file.write_text('{"app_name": "test"}')  # Missing required fields

        with pytest.raises(ConfigurationError) as exc_info:
            ConfigExporter.import_from_json(invalid_file)

        assert "Configuration validation failed" in str(exc_info.value)
