"""
Tests for Docker integration with Claude Desktop MCP
"""

import json
import os
import tempfile
from pathlib import Path

import pytest


class TestDockerClaudeDesktopIntegration:
    """Test Docker integration with Claude Desktop"""

    @pytest.fixture(autouse=True)
    def setup(self):
        """Setup for each test"""
        self.project_root = Path(__file__).parent.parent

    def test_mcp_config_docker_run_format(self):
        """Test MCP configuration for direct docker run"""
        config = {
            "mcpServers": {
                "pal-mcp": {
                    "command": "docker",
                    "args": [
                        "run",
                        "--rm",
                        "-i",
                        "--env-file",
                        "/path/to/.env",
                        "-v",
                        "/path/to/logs:/app/logs",
                        "pal-mcp-server:latest",
                    ],
                }
            }
        }

        # Validate configuration structure
        assert "mcpServers" in config
        assert "pal-mcp" in config["mcpServers"]
        assert config["mcpServers"]["pal-mcp"]["command"] == "docker"

        args = config["mcpServers"]["pal-mcp"]["args"]
        assert "run" in args
        assert "--rm" in args
        assert "-i" in args
        assert "--env-file" in args

    def test_mcp_config_docker_compose_format(self):
        """Test MCP configuration for docker-compose run"""
        config = {
            "mcpServers": {
                "pal-mcp": {
                    "command": "docker-compose",
                    "args": ["-f", "/path/to/docker-compose.yml", "run", "--rm", "pal-mcp"],
                }
            }
        }

        # Validate configuration structure
        assert config["mcpServers"]["pal-mcp"]["command"] == "docker-compose"

        args = config["mcpServers"]["pal-mcp"]["args"]
        assert "-f" in args
        assert "run" in args
        assert "--rm" in args
        assert "pal-mcp" in args

    def test_mcp_config_environment_variables(self):
        """Test MCP configuration with inline environment variables"""
        config = {
            "mcpServers": {
                "pal-mcp": {
                    "command": "docker",
                    "args": [
                        "run",
                        "--rm",
                        "-i",
                        "-e",
                        "GEMINI_API_KEY=test_key",
                        "-e",
                        "LOG_LEVEL=INFO",
                        "pal-mcp-server:latest",
                    ],
                }
            }
        }

        args = config["mcpServers"]["pal-mcp"]["args"]

        # Check that environment variables are properly formatted
        env_args = [arg for arg in args if arg.startswith("-e")]
        assert len(env_args) > 0, "Environment variables should be present"

        # Check for API key environment variable
        api_key_present = any("GEMINI_API_KEY=" in args[i + 1] for i, arg in enumerate(args[:-1]) if arg == "-e")
        assert api_key_present, "API key environment variable should be set"

    def test_windows_path_format(self):
        """Test Windows-specific path formatting"""
        windows_config = {
            "mcpServers": {
                "pal-mcp": {
                    "command": "docker",
                    "args": [
                        "run",
                        "--rm",
                        "-i",
                        "--env-file",
                        "C:/Users/User/pal-mcp-server/.env",
                        "-v",
                        "C:/Users/User/pal-mcp-server/logs:/app/logs",
                        "pal-mcp-server:latest",
                    ],
                }
            }
        }

        args = windows_config["mcpServers"]["pal-mcp"]["args"]

        # Check Windows path format
        windows_paths = [arg for arg in args if arg.startswith("C:/")]
        assert len(windows_paths) > 0, "Windows paths should use forward slashes"

        for path in windows_paths:
            assert "\\" not in path, "Windows paths should use forward slashes"

    def test_mcp_config_validation(self):
        """Test validation of MCP configuration"""
        # Valid configuration
        valid_config = {
            "mcpServers": {"pal-mcp": {"command": "docker", "args": ["run", "--rm", "-i", "pal-mcp-server:latest"]}}
        }

        # Validate JSON serialization
        config_json = json.dumps(valid_config)
        loaded_config = json.loads(config_json)
        assert loaded_config == valid_config

    def test_mcp_stdio_communication(self):
        """Test that MCP configuration supports stdio communication"""
        config = {
            "mcpServers": {
                "pal-mcp": {
                    "command": "docker",
                    "args": [
                        "run",
                        "--rm",
                        "-i",  # Interactive mode for stdio
                        "pal-mcp-server:latest",
                    ],
                }
            }
        }

        args = config["mcpServers"]["pal-mcp"]["args"]

        # Check for interactive mode
        assert "-i" in args, "Interactive mode required for stdio communication"

        # Should not expose network ports for stdio communication
        port_args = [arg for arg in args if arg.startswith("-p")]
        assert len(port_args) == 0, "No ports should be exposed for stdio mode"

    def test_docker_image_reference(self):
        """Test that Docker image is properly referenced"""
        configs = [
            {"image": "pal-mcp-server:latest"},
            {"image": "pal-mcp-server:v1.0.0"},
            {"image": "registry/pal-mcp-server:latest"},
        ]

        for config in configs:
            image = config["image"]

            # Basic image format validation
            assert ":" in image, "Image should have a tag"
            assert len(image.split(":")) == 2, "Image should have exactly one tag"

    @pytest.fixture
    def temp_mcp_config(self):
        """Create temporary MCP configuration file"""
        config = {
            "mcpServers": {
                "pal-mcp": {
                    "command": "docker",
                    "args": ["run", "--rm", "-i", "--env-file", "/tmp/.env", "pal-mcp-server:latest"],
                }
            }
        }

        with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False, encoding="utf-8") as f:
            json.dump(config, f, indent=2)
            temp_file_path = f.name

        yield temp_file_path
        os.unlink(temp_file_path)

    def test_mcp_config_file_parsing(self, temp_mcp_config):
        """Test parsing of MCP configuration file"""
        # Read and parse the temporary config file
        with open(temp_mcp_config, encoding="utf-8") as f:
            config = json.load(f)

        assert "mcpServers" in config
        assert "pal-mcp" in config["mcpServers"]

    def test_environment_file_integration(self):
        """Test integration with .env file"""
        # Test .env file format expected by Docker
        env_content = """GEMINI_API_KEY=test_key
OPENAI_API_KEY=test_key_2
LOG_LEVEL=INFO
DEFAULT_MODEL=auto
"""

        # Parse environment content
        env_vars = {}
        for line in env_content.strip().split("\n"):
            if "=" in line and not line.startswith("#"):
                key, value = line.split("=", 1)
                env_vars[key] = value

        # Validate required environment variables
        assert "GEMINI_API_KEY" in env_vars
        assert len(env_vars["GEMINI_API_KEY"]) > 0

    def test_docker_volume_mount_paths(self):
        """Test Docker volume mount path configurations"""
        mount_configs = [
            {"host": "./logs", "container": "/app/logs"},
            {"host": "/absolute/path/logs", "container": "/app/logs"},
            {"host": "C:/Windows/path/logs", "container": "/app/logs"},
        ]

        for config in mount_configs:
            mount_arg = f"{config['host']}:{config['container']}"

            # Validate mount format
            assert ":" in mount_arg
            parts = mount_arg.split(":")
            assert len(parts) >= 2
            assert parts[-1].startswith("/"), "Container path should be absolute"


class TestDockerMCPErrorHandling:
    """Test error handling for Docker MCP integration"""

    def test_missing_docker_image_handling(self):
        """Test handling of missing Docker image"""
        # This would test what happens when the image doesn't exist
        # In practice, Claude Desktop would show an error
        nonexistent_config = {
            "mcpServers": {"pal-mcp": {"command": "docker", "args": ["run", "--rm", "-i", "nonexistent:latest"]}}
        }

        # Configuration should be valid even if image doesn't exist
        assert "pal-mcp" in nonexistent_config["mcpServers"]

    def test_invalid_env_file_path(self):
        """Test handling of invalid .env file path"""
        config_with_invalid_env = {
            "mcpServers": {
                "pal-mcp": {
                    "command": "docker",
                    "args": ["run", "--rm", "-i", "--env-file", "/nonexistent/.env", "pal-mcp-server:latest"],
                }
            }
        }

        # Configuration structure should still be valid
        args = config_with_invalid_env["mcpServers"]["pal-mcp"]["args"]
        assert "--env-file" in args

    def test_docker_permission_issues(self):
        """Test configuration for potential Docker permission issues"""
        # On some systems, Docker requires specific permissions
        # The configuration should work with both cases

        configs = [
            # Regular Docker command
            {"command": "docker"},
            # Sudo Docker command (if needed)
            {"command": "sudo", "extra_args": ["docker"]},
        ]

        for config in configs:
            assert len(config["command"]) > 0

    def test_resource_limit_configurations(self):
        """Test Docker resource limit configurations"""
        config_with_limits = {
            "mcpServers": {
                "pal-mcp": {
                    "command": "docker",
                    "args": ["run", "--rm", "-i", "--memory=512m", "--cpus=1.0", "pal-mcp-server:latest"],
                }
            }
        }

        args = config_with_limits["mcpServers"]["pal-mcp"]["args"]

        # Check for resource limits
        memory_limit = any("--memory" in arg for arg in args)
        cpu_limit = any("--cpus" in arg for arg in args)

        assert memory_limit or cpu_limit, "Resource limits should be configurable"
