"""Feature translation between runtimes.

This module provides the FeatureTranslator class which analyzes container
configurations and translates features between different runtimes.
"""

from __future__ import annotations

from gaol.migration.models import (
    FeatureWarning,
    FeatureWarningSeverity,
    RuntimeCapabilities,
)
from gaol.models.container import ContainerConfig, NetworkMode


# Runtime capabilities definitions
RUNTIME_CAPABILITIES: dict[str, RuntimeCapabilities] = {
    "docker": RuntimeCapabilities(
        name="docker",
        supports_pause=True,
        supports_snapshots=True,
        supports_copy=True,
        supports_cpu_shares=True,
        supports_cpu_count=True,
        supports_memory_limit=True,
        supports_privileged=True,
        supports_capabilities=True,
        supports_read_only=True,
        memory_granularity_mb=1,
        filesystem_type="overlay",
        requires_root_export=False,
        requires_root_import=False,
    ),
    "nspawn": RuntimeCapabilities(
        name="nspawn",
        supports_pause=False,
        supports_snapshots=True,
        supports_copy=True,
        supports_cpu_shares=True,
        supports_cpu_count=True,
        supports_memory_limit=True,
        supports_privileged=True,
        supports_capabilities=True,
        supports_read_only=False,  # nspawn doesn't support read-only root
        memory_granularity_mb=1,
        filesystem_type="directory",
        requires_root_export=True,
        requires_root_import=True,
    ),
    "libvirt": RuntimeCapabilities(
        name="libvirt",
        supports_pause=True,  # suspend/resume
        supports_snapshots=True,
        supports_copy=True,  # SCP-based
        supports_cpu_shares=False,  # Uses vCPU count instead
        supports_cpu_count=True,
        supports_memory_limit=True,
        supports_privileged=False,  # VMs are isolated differently
        supports_capabilities=False,  # Not applicable to VMs
        supports_read_only=False,  # Not typically supported
        memory_granularity_mb=4,  # QEMU rounds to 4MB
        filesystem_type="disk",
        requires_root_export=True,
        requires_root_import=True,
    ),
}


def get_runtime_capabilities(runtime: str) -> RuntimeCapabilities:
    """Get capabilities for a runtime.

    Args:
        runtime: Runtime name.

    Returns:
        RuntimeCapabilities for the runtime.

    Raises:
        ValueError: If runtime is unknown.
    """
    if runtime not in RUNTIME_CAPABILITIES:
        raise ValueError(f"Unknown runtime: {runtime}")
    return RUNTIME_CAPABILITIES[runtime]


class FeatureTranslator:
    """Translates container features between runtimes.

    Analyzes a container configuration and determines which features
    can be migrated to a target runtime, generating warnings for
    features that cannot be perfectly translated.
    """

    def __init__(self):
        """Initialize translator."""
        pass

    def analyze_migration(
        self,
        config: ContainerConfig,
        source_runtime: str,
        target_runtime: str,
    ) -> tuple[ContainerConfig, list[FeatureWarning]]:
        """Analyze and translate config for target runtime.

        Args:
            config: Container configuration to translate.
            source_runtime: Source runtime name.
            target_runtime: Target runtime name.

        Returns:
            Tuple of (translated_config, warnings).
        """
        warnings: list[FeatureWarning] = []
        source_caps = get_runtime_capabilities(source_runtime)
        target_caps = get_runtime_capabilities(target_runtime)

        # Start with a copy of the config
        translated = config.model_copy(deep=True)
        translated.runtime = target_runtime

        # Check each feature category
        warnings.extend(self._check_network(config, source_caps, target_caps))
        warnings.extend(self._check_resources(config, source_caps, target_caps, translated))
        warnings.extend(self._check_security(config, source_caps, target_caps, translated))
        warnings.extend(self._check_runtime_features(source_caps, target_caps))

        return translated, warnings

    def _check_network(
        self,
        config: ContainerConfig,
        source_caps: RuntimeCapabilities,
        target_caps: RuntimeCapabilities,
    ) -> list[FeatureWarning]:
        """Check network configuration compatibility."""
        warnings: list[FeatureWarning] = []

        # Network mode is generally compatible across runtimes
        # but implementation details differ
        if config.network.mode == NetworkMode.HOST:
            if target_caps.name == "libvirt":
                warnings.append(
                    FeatureWarning(
                        feature="network_mode_host",
                        source_value="host",
                        target_behavior="Host networking requires bridge device passthrough",
                        severity=FeatureWarningSeverity.WARNING,
                    )
                )

        # Port mappings may work differently
        if config.network.ports and target_caps.name == "libvirt":
            warnings.append(
                FeatureWarning(
                    feature="port_mapping",
                    source_value=str(config.network.ports),
                    target_behavior="Port forwarding handled via iptables rules",
                    severity=FeatureWarningSeverity.INFO,
                )
            )

        return warnings

    def _check_resources(
        self,
        config: ContainerConfig,
        source_caps: RuntimeCapabilities,
        target_caps: RuntimeCapabilities,
        translated: ContainerConfig,
    ) -> list[FeatureWarning]:
        """Check resource limit compatibility."""
        warnings: list[FeatureWarning] = []

        # CPU shares
        if config.resources.cpu_shares and not target_caps.supports_cpu_shares:
            warnings.append(
                FeatureWarning(
                    feature="cpu_shares",
                    source_value=str(config.resources.cpu_shares),
                    target_behavior="CPU shares not supported; will use vCPU count instead",
                    severity=FeatureWarningSeverity.WARNING,
                )
            )
            # Clear cpu_shares in translated config
            translated.resources.cpu_shares = None

        # Memory granularity
        if config.resources.memory_mb:
            source_granularity = source_caps.memory_granularity_mb
            target_granularity = target_caps.memory_granularity_mb

            if target_granularity > source_granularity:
                # Round up to target granularity
                rounded = (
                    (config.resources.memory_mb + target_granularity - 1)
                    // target_granularity
                    * target_granularity
                )
                if rounded != config.resources.memory_mb:
                    warnings.append(
                        FeatureWarning(
                            feature="memory_limit",
                            source_value=f"{config.resources.memory_mb}MB",
                            target_behavior=f"Rounded to {rounded}MB ({target_granularity}MB granularity)",
                            severity=FeatureWarningSeverity.INFO,
                        )
                    )
                    translated.resources.memory_mb = rounded

        return warnings

    def _check_security(
        self,
        config: ContainerConfig,
        source_caps: RuntimeCapabilities,
        target_caps: RuntimeCapabilities,
        translated: ContainerConfig,
    ) -> list[FeatureWarning]:
        """Check security feature compatibility."""
        warnings: list[FeatureWarning] = []

        # Privileged mode
        if config.privileged and not target_caps.supports_privileged:
            warnings.append(
                FeatureWarning(
                    feature="privileged",
                    source_value="true",
                    target_behavior="Privileged mode not applicable to VMs (already isolated)",
                    severity=FeatureWarningSeverity.INFO,
                )
            )
            translated.privileged = False

        # Capabilities
        # Note: ContainerConfig doesn't have cap_add/cap_drop directly,
        # but profiles can add them. Check if there's any indication.

        # Read-only root
        if config.read_only and not target_caps.supports_read_only:
            warnings.append(
                FeatureWarning(
                    feature="read_only",
                    source_value="true",
                    target_behavior="Read-only root filesystem not supported on target runtime",
                    severity=FeatureWarningSeverity.WARNING,
                )
            )
            translated.read_only = False

        return warnings

    def _check_runtime_features(
        self,
        source_caps: RuntimeCapabilities,
        target_caps: RuntimeCapabilities,
    ) -> list[FeatureWarning]:
        """Check general runtime feature differences."""
        warnings: list[FeatureWarning] = []

        # Pause support
        if source_caps.supports_pause and not target_caps.supports_pause:
            warnings.append(
                FeatureWarning(
                    feature="pause",
                    target_behavior="Pause/unpause not supported on target runtime",
                    severity=FeatureWarningSeverity.INFO,
                )
            )

        # Filesystem type change
        if source_caps.filesystem_type != target_caps.filesystem_type:
            warnings.append(
                FeatureWarning(
                    feature="filesystem_type",
                    source_value=source_caps.filesystem_type,
                    target_behavior=f"Filesystem will be stored as {target_caps.filesystem_type}",
                    severity=FeatureWarningSeverity.INFO,
                )
            )

        return warnings

    def get_capabilities(self, runtime: str) -> RuntimeCapabilities:
        """Get capabilities for a runtime.

        Args:
            runtime: Runtime name.

        Returns:
            RuntimeCapabilities for the runtime.
        """
        return get_runtime_capabilities(runtime)

    def is_migration_supported(
        self,
        source_runtime: str,
        target_runtime: str,
    ) -> tuple[bool, str | None]:
        """Check if migration between two runtimes is supported.

        Args:
            source_runtime: Source runtime name.
            target_runtime: Target runtime name.

        Returns:
            Tuple of (is_supported, reason_if_not).
        """
        try:
            get_runtime_capabilities(source_runtime)
            get_runtime_capabilities(target_runtime)
        except ValueError as e:
            return False, str(e)

        if source_runtime == target_runtime:
            return False, "Source and target runtime are the same"

        # All combinations of docker, nspawn, libvirt are supported
        return True, None
