"""Read-only Git repository discovery.

For every repository found we collect only non-sensitive metadata. Remote URLs
are sanitized to strip any embedded credentials/tokens. We never read git
config secrets, stored credentials, or commit contents.
"""

from __future__ import annotations

import re
from pathlib import Path
from typing import Any

from discovery.system import run_readonly
from logger import get_logger

log = get_logger("discovery.git")

# Common roots to scan. Kept shallow for v1 to avoid heavy filesystem walks.
_SCAN_ROOTS = ("/var/www", "/srv", "/home", "/opt")
_MAX_DEPTH = 3


def sanitize_remote(url: str | None) -> str | None:
    """Strip credentials from a remote URL.

    https://user:token@github.com/x/y.git -> https://github.com/x/y.git
    Leaves SSH-style remotes (git@host:repo) untouched, as they carry no secret.
    """
    if not url:
        return None
    # Remove userinfo (anything before '@') in the authority component.
    return re.sub(r"(https?://)[^/@]*@", r"\1", url.strip())


def _git(repo: Path, args: list[str]) -> str | None:
    output = run_readonly(["git", "-C", str(repo), *args])
    return output.strip() if output else None


def inspect_repo(repo_dir: Path) -> dict[str, Any]:
    """Collect the allow-listed metadata for a single repository."""
    repo = repo_dir.parent  # repo_dir is the .git directory
    remote = _git(repo, ["config", "--get", "remote.origin.url"])
    status = _git(repo, ["status", "--porcelain"])
    return {
        "path": str(repo),
        "remote_url": sanitize_remote(remote),
        "current_branch": _git(repo, ["rev-parse", "--abbrev-ref", "HEAD"]),
        "last_commit_hash": _git(repo, ["log", "-1", "--format=%H"]),
        "last_commit_date": _git(repo, ["log", "-1", "--format=%cI"]),
        "dirty_state": bool(status),  # True if there are uncommitted changes
    }


def find_repositories(roots: tuple[str, ...] = _SCAN_ROOTS) -> list[dict[str, Any]]:
    """Find .git directories under the scan roots (bounded depth)."""
    repos: list[dict[str, Any]] = []
    seen: set[str] = set()
    for root in roots:
        base = Path(root)
        if not base.is_dir():
            continue
        for git_dir in _bounded_glob(base, ".git", _MAX_DEPTH):
            key = str(git_dir.parent)
            if key in seen:
                continue
            seen.add(key)
            try:
                repos.append(inspect_repo(git_dir))
            except OSError as exc:  # pragma: no cover - fs edge cases
                log.debug("failed to inspect %s: %s", git_dir, exc)
    return repos


def _bounded_glob(base: Path, name: str, max_depth: int):
    """Yield paths named `name` up to max_depth levels below base."""
    for depth in range(max_depth + 1):
        pattern = "/".join(["*"] * depth + [name]) if depth else name
        try:
            yield from base.glob(pattern)
        except OSError:
            continue
