"""Add an OSM basemap with a SIGALRM-based timeout (Unix only)."""

from __future__ import annotations

import signal
from pathlib import Path


def add_basemap_with_timeout(
    ax: "Axes",
    zoom: int = 9,
    cache_dir: "str | Path | None" = None,
    timeout_s: float = 15.0,
) -> bool:
    """Add an OpenStreetMap basemap with a hard timeout (Unix only).

    Uses SIGALRM to enforce a wall-clock timeout on the tile fetch. If the
    download does not complete within ``timeout_s`` seconds the function
    returns False without modifying the Axes further.

    **Unix only** — SIGALRM is not available on Windows. On Windows this
    function always returns False immediately.

    Args:
        ax: matplotlib Axes with projected extent (EPSG:3857).
        zoom: Tile zoom level (1–19).
        cache_dir: Optional tile cache directory.
        timeout_s: Maximum seconds to wait for tiles. Default 15.0.

    Returns:
        True if the basemap was added successfully; False on timeout or error.
    """
    if not hasattr(signal, "SIGALRM"):
        # Windows — SIGALRM not available
        return False

    try:
        import contextily as ctx  # type: ignore
    except ImportError:
        return False

    def _handler(signum: int, frame: object) -> None:  # noqa: ARG001
        raise TimeoutError("basemap fetch timed out")

    old_handler = signal.signal(signal.SIGALRM, _handler)
    signal.setitimer(signal.ITIMER_REAL, timeout_s)

    try:
        if cache_dir is not None:
            ctx.set_cache_dir(str(cache_dir))
        ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.Mapnik, zoom=zoom)
        return True
    except Exception:  # noqa: BLE001
        return False
    finally:
        signal.setitimer(signal.ITIMER_REAL, 0)
        signal.signal(signal.SIGALRM, old_handler)
