"""Mounts directories as static files for serving through the web server."""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/serving/mounter.ipynb.

# %% auto #0
__all__ = ['DirectoryMounter']

# %% ../../nbs/serving/mounter.ipynb #c3d4e5f6
import hashlib
from pathlib import Path
from typing import Dict, List, Optional
from fastcore.basics import patch

from starlette.staticfiles import StaticFiles
from starlette.routing import Mount

# %% ../../nbs/serving/mounter.ipynb #e5f6a7b8
class DirectoryMounter:
    """Mounts directories for static file serving with instance-level state."""

    # Prefix pattern for this mounter's routes
    ROUTE_PREFIX_PATTERN = "mg_static_"

    def __init__(self):
        """Initialize the mounter with empty state."""
        self._mounted: Dict[str, str] = {}  # directory -> route_prefix
        self._app = None

# %% ../../nbs/serving/mounter.ipynb #f6a7b8c9
@patch
def mount(
    self: DirectoryMounter,
    app,  # FastHTML/Starlette application instance
    directories: List[str]  # List of directory paths to mount
) -> None:
    """Mount directories to app for static file serving."""
    self._app = app
    self._mounted.clear()

    # Remove any existing mounts from this instance
    self._remove_existing_mounts(app)

    for directory in directories:
        self._mount_directory(app, directory)

# %% ../../nbs/serving/mounter.ipynb #g7b8c9d0
@patch
def get_url(
    self: DirectoryMounter,
    file_path: str  # Full path to the file
) -> Optional[str]:  # URL to access the file, or None if not in a mounted directory
    """Get URL for a file based on mounted directories."""
    file_path_resolved = Path(file_path).resolve()

    for directory, prefix in self._mounted.items():
        dir_path = Path(directory).resolve()
        try:
            relative_path = file_path_resolved.relative_to(dir_path)
            return f"/{prefix}/{relative_path.as_posix()}"
        except ValueError:
            # File is not in this directory
            continue

    return None

# %% ../../nbs/serving/mounter.ipynb #h8c9d0e1
@patch
def is_mounted(
    self: DirectoryMounter,
    directory: str  # Directory path to check
) -> bool:  # True if the directory is mounted
    """Check if a directory is currently mounted."""
    return directory in self._mounted

# %% ../../nbs/serving/mounter.ipynb #i9d0e1f2
@patch
def get_mounted_directories(
    self: DirectoryMounter
) -> List[str]:  # List of mounted directory paths
    """Get list of currently mounted directories."""
    return list(self._mounted.keys())

# %% ../../nbs/serving/mounter.ipynb #j0e1f2g3
@patch
def unmount_all(
    self: DirectoryMounter
) -> None:
    """Remove all mounts from this instance."""
    if self._app:
        self._remove_existing_mounts(self._app)
    self._mounted.clear()

# %% ../../nbs/serving/mounter.ipynb #k1f2g3h4
@patch
def _mount_directory(
    self: DirectoryMounter, 
    app,  # FastHTML/Starlette application instance
    directory: str  # Directory path to mount
) -> None:
    """Mount a single directory."""
    dir_path = Path(directory)

    if not dir_path.exists():
        print(f"[DirectoryMounter] Warning: Directory does not exist: {directory}")
        return

    if not dir_path.is_dir():
        print(f"[DirectoryMounter] Warning: Path is not a directory: {directory}")
        return

    prefix = self._generate_prefix(directory)

    try:
        mount = Mount(
            f"/{prefix}",
            app=StaticFiles(directory=str(dir_path)),
            name=prefix
        )

        # Insert at the beginning of routes (before other routes)
        app.routes.insert(0, mount)

        # Store the mapping
        self._mounted[directory] = prefix

    except Exception as e:
        print(f"[DirectoryMounter] Error mounting {directory}: {e}")

# %% ../../nbs/serving/mounter.ipynb #l2g3h4i5
@patch
def _generate_prefix(
    self: DirectoryMounter, 
    directory: str  # Directory path
) -> str:  # Route prefix string (e.g., "mg_static_abc12345")
    """Generate a unique route prefix for a directory using MD5 hash."""
    dir_hash = hashlib.md5(directory.encode()).hexdigest()[:8]
    return f"{self.ROUTE_PREFIX_PATTERN}{dir_hash}"

# %% ../../nbs/serving/mounter.ipynb #u4dwwf78h3
@patch
def _remove_existing_mounts(
    self: DirectoryMounter, 
    app  # FastHTML/Starlette application instance
) -> None:
    """Remove existing mounts matching this mounter's prefix pattern."""
    # Filter out mounts with our prefix pattern
    app.routes[:] = [
        route for route in app.routes
        if not (
            isinstance(route, Mount) and
            route.path.startswith(f"/{self.ROUTE_PREFIX_PATTERN}")
        )
    ]

# %% ../../nbs/serving/mounter.ipynb #bxokni6u4cs
@patch
def create_url_getter(
    self: DirectoryMounter
) -> callable:  # Function that converts path to URL
    """Create a URL getter function for use with gallery components."""
    def get_url(path: str) -> Optional[str]:
        return self.get_url(path)
    return get_url
