"""Path validation and security utilities."""

from __future__ import annotations

from pathlib import Path

from pptx_mcp.utils.errors import PathValidationError

ALLOWED_OUTPUT_EXTENSIONS = {".pptx"}
ALLOWED_INPUT_EXTENSIONS = {".pptx"}
ALLOWED_CONFIG_EXTENSIONS = {".json", ".yaml", ".yml"}
ALLOWED_IMAGE_EXTENSIONS = {
    ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".svg", ".emf", ".wmf",
}
ALLOWED_TEMPLATE_EXTENSIONS = {".pptx"}

MAX_PATH_LENGTH = 1024


_SYSTEM_SYMLINK_ROOTS = frozenset({"/tmp", "/var", "/etc", "/private"})


def _check_symlink(path: Path) -> None:
    """Reject symlinks on the target file to prevent path-traversal attacks.

    Only checks the file itself and its immediate parent directory.
    System-level symlinks (e.g. /var, /tmp on macOS) are not flagged.
    """
    if path.is_symlink():
        raise PathValidationError(
            f"Symlinks are not allowed: {path.name}"
        )
    parent = path.parent
    if parent.is_symlink() and str(parent) not in _SYSTEM_SYMLINK_ROOTS:
        raise PathValidationError(
            f"Symlink detected in parent directory: {parent.name}"
        )


def validate_output_path(path: str | Path) -> Path:
    """Validate and resolve an output file path.

    Checks:
      - Path length within bounds
      - Extension is .pptx
      - No symlinks in path
      - Parent directory exists or can be created

    Returns:
        Resolved Path object.

    Raises:
        PathValidationError: If validation fails.
    """
    if len(str(path)) > MAX_PATH_LENGTH:
        raise PathValidationError("Output path exceeds maximum length")

    raw = Path(path)
    _check_symlink(raw)
    path = raw.resolve()

    if path.suffix.lower() not in ALLOWED_OUTPUT_EXTENSIONS:
        raise PathValidationError(
            f"Output file must have a .pptx extension, got '{path.suffix}'"
        )

    return path


def validate_input_path(
    path: str | Path,
    allowed_extensions: set[str] | None = None,
) -> Path:
    """Validate an input file path exists and has an allowed extension.

    Returns:
        Resolved Path object.

    Raises:
        PathValidationError: If validation fails.
    """
    if len(str(path)) > MAX_PATH_LENGTH:
        raise PathValidationError("Input path exceeds maximum length")

    raw = Path(path)
    _check_symlink(raw)
    path = raw.resolve()

    if not path.exists():
        raise PathValidationError(f"File not found: {path.name}")

    if not path.is_file():
        raise PathValidationError(f"Path is not a file: {path.name}")

    if allowed_extensions and path.suffix.lower() not in allowed_extensions:
        raise PathValidationError(
            f"Unsupported file type '{path.suffix}'. "
            f"Allowed: {', '.join(sorted(allowed_extensions))}"
        )

    return path


def validate_pptx_input(path: str | Path) -> Path:
    """Validate a PPTX input file path."""
    return validate_input_path(path, ALLOWED_INPUT_EXTENSIONS)


def validate_config_path(path: str | Path) -> Path:
    """Validate a brand config file path."""
    return validate_input_path(path, ALLOWED_CONFIG_EXTENSIONS)


def validate_save_path(path: str | Path) -> Path:
    """Validate a save path for config output (.yaml/.yml/.json).

    Checks path length, extension, symlinks, and creates parent dirs.

    Returns:
        Resolved Path object.

    Raises:
        PathValidationError: If validation fails.
    """
    if len(str(path)) > MAX_PATH_LENGTH:
        raise PathValidationError("Save path exceeds maximum length")

    raw = Path(path)

    if raw.suffix.lower() not in ALLOWED_CONFIG_EXTENSIONS:
        raise PathValidationError(
            f"Save path must end in .yaml, .yml, or .json, got '{raw.suffix}'"
        )

    _check_symlink(raw)
    raw.parent.mkdir(parents=True, exist_ok=True)
    return raw.resolve()


def validate_image_path(path: str | Path) -> Path:
    """Validate an image file path."""
    return validate_input_path(path, ALLOWED_IMAGE_EXTENSIONS)


def validate_template_path(path: str | Path) -> Path:
    """Validate a PPTX template file path."""
    return validate_input_path(path, ALLOWED_TEMPLATE_EXTENSIONS)
