"""Shared validation utilities for tool types."""

import re

import yaml
from fastapi import HTTPException, status


def sanitize_template_vars(template: str) -> str:
    """Replace template variables like {{VAR}} with placeholders to avoid YAML parsing errors."""
    return re.sub(r"\{\{[A-Za-z_][A-Za-z0-9_]*\}\}", "__PLACEHOLDER__", template)


def validate_compose_yaml(template: str) -> dict:
    """Validate and parse a compose template.

    Args:
        template: Raw compose template string.

    Returns:
        Parsed YAML dict.

    Raises:
        ValueError: If YAML is invalid or missing required keys.
    """
    sanitized = sanitize_template_vars(template)

    try:
        parsed = yaml.safe_load(sanitized)
    except yaml.YAMLError as e:
        raise ValueError(f"Invalid YAML: {e}")

    if not isinstance(parsed, dict):
        raise ValueError("Compose template must be a YAML mapping")

    if "services" not in parsed:
        raise ValueError("Compose template must contain 'services' key")

    if not parsed["services"]:
        raise ValueError("Compose template must define at least one service")

    return parsed


def check_port_exposed(parsed: dict, port: int) -> bool:
    """Check if a port is exposed in a parsed compose template.

    Args:
        parsed: Parsed compose YAML dict.
        port: Port number to check.

    Returns:
        True if port is exposed in any service.
    """
    port_str = str(port)

    if not isinstance(parsed, dict) or "services" not in parsed:
        return False

    for service_config in parsed["services"].values():
        if isinstance(service_config, dict) and "ports" in service_config:
            for port_mapping in service_config["ports"]:
                if isinstance(port_mapping, str):
                    # Port mappings can be "host:container", "ip:host:container",
                    # "container", or ".../protocol". The container port is the
                    # last numeric segment before any protocol suffix.
                    mapping = port_mapping.split("/")[0]
                    parts = mapping.split(":")
                    if parts[-1] == port_str:
                        return True
                elif isinstance(port_mapping, int) and port_mapping == port:
                    return True

    return False


def validate_required_variables(template: str, variables: list[str]) -> None:
    """Validate that all required variables exist in the template.

    Args:
        template: Compose template string.
        variables: List of required variable names.

    Raises:
        HTTPException: If any variable is not found in the template.
    """
    for var in variables:
        placeholder = f"{{{{{var}}}}}"
        if placeholder not in template:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Required variable '{var}' not found in compose template",
            )
