"""
Helpers for dropping root ownership on files created during privileged
operations (e.g. `sudo decnet deploy` needs root for MACVLAN, but its log
files should be owned by the invoking user so a subsequent non-root
`decnet api` can append to them).

When sudo invokes a process, it sets SUDO_UID / SUDO_GID in the
environment to the original user's IDs. We use those to chown files
back after creation.
"""
from __future__ import annotations

import os
from pathlib import Path
from typing import Optional


def _sudo_ids() -> Optional[tuple[int, int]]:
    """Return (uid, gid) of the sudo-invoking user, or None when the
    process was not launched via sudo / the env vars are missing."""
    raw_uid = os.environ.get("SUDO_UID")
    raw_gid = os.environ.get("SUDO_GID")
    if not raw_uid or not raw_gid:
        return None
    try:
        return int(raw_uid), int(raw_gid)
    except ValueError:
        return None


def chown_to_invoking_user(path: str | os.PathLike[str]) -> None:
    """Best-effort chown of *path* to the sudo-invoking user.

    No-op when:
      * not running as root (nothing to drop),
      * not launched via sudo (no SUDO_UID/SUDO_GID),
      * the path does not exist,
      * chown fails (logged-only — never raises).
    """
    if os.geteuid() != 0:
        return
    ids = _sudo_ids()
    if ids is None:
        return
    uid, gid = ids
    p = Path(path)
    if not p.exists():
        return
    try:
        os.chown(p, uid, gid)
    except OSError:
        # Best-effort; a failed chown is not fatal to logging.
        pass


def chown_tree_to_invoking_user(root: str | os.PathLike[str]) -> None:
    """Apply :func:`chown_to_invoking_user` to *root* and every file/dir
    beneath it. Used for parent directories that we just created with
    ``mkdir(parents=True)`` as root."""
    if os.geteuid() != 0 or _sudo_ids() is None:
        return
    root_path = Path(root)
    if not root_path.exists():
        return
    chown_to_invoking_user(root_path)
    for entry in root_path.rglob("*"):
        chown_to_invoking_user(entry)
