"""disk-maintain: single-flight lock + worktree GC integration."""

from __future__ import annotations

import fcntl
import os
import subprocess
import time
from pathlib import Path

MAINTAIN = Path(__file__).resolve().parents[1] / "slices" / "bin" / "disk-maintain"


def _git(cwd: Path, args: list[str]) -> str:
    result = subprocess.run(
        ["git", "-C", str(cwd), *args],
        capture_output=True,
        text=True,
        check=False,
    )
    if result.returncode != 0:
        raise RuntimeError(result.stderr)
    return result.stdout


def _make_repo(projects: Path) -> Path:
    repo = projects / "repo"
    repo.mkdir(parents=True)
    _git(repo, ["init", "-q", "-b", "main"])
    _git(repo, ["config", "user.email", "test@test"])
    _git(repo, ["config", "user.name", "test"])
    (repo / "README").write_text("x", encoding="utf-8")
    (repo / ".gitignore").write_text("node_modules/\n", encoding="utf-8")
    _git(repo, ["add", "-A"])
    _git(repo, ["commit", "-qm", "init"])
    origin = projects / "origin.git"
    _git(repo, ["init", "-q", "--bare", str(origin)])
    _git(repo, ["remote", "add", "origin", str(origin)])
    _git(repo, ["push", "-q", "origin", "main"])
    return repo


def _add_worktree(repo: Path, slug: str) -> Path:
    wt = repo / ".worktrees" / slug
    wt.parent.mkdir(parents=True, exist_ok=True)
    _git(repo, ["worktree", "add", "-q", "-b", f"task/{slug}", str(wt), "main"])
    return wt


def _age(path: Path, age_s: float) -> None:
    old = time.time() - age_s
    os.utime(path, (old, old))
    if path.is_dir():
        for root, dirs, files in os.walk(path):
            for name in dirs + files:
                try:
                    os.utime(os.path.join(root, name), (old, old), follow_symlinks=False)
                except OSError:
                    pass
        dotgit = path / ".git"
        if dotgit.is_file():
            gitdir = dotgit.read_text(encoding="utf-8").replace("gitdir:", "").strip()
            for rel in ("index", "HEAD", os.path.join("logs", "HEAD")):
                candidate = Path(gitdir) / rel
                if candidate.exists():
                    os.utime(candidate, (old, old))
    if path.is_file():
        return
    gitfile = path / ".git"
    if gitfile.is_file():
        os.utime(gitfile, (old, old))
        gitdir = gitfile.read_text(encoding="utf-8").replace("gitdir:", "").strip()
        index = Path(gitdir) / "index"
        if index.exists():
            os.utime(index, (old, old))


def _run_maintain(env: dict[str, str]) -> subprocess.CompletedProcess[str]:
    return subprocess.run(
        ["bash", str(MAINTAIN)],
        env={**os.environ, **env},
        text=True,
        capture_output=True,
    )


def test_lock_contention_skips_second_maintain(tmp_path: Path):
    xdg = tmp_path / "xdg"
    state = xdg / "system-monitor"
    state.mkdir(parents=True)
    (tmp_path / "home").mkdir()
    (tmp_path / "empty-projects").mkdir()
    real_lock = state / "disk-maintain.lock"

    with open(real_lock, "w", encoding="utf-8") as held:
        fcntl.flock(held.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
        env = {
            "HOME": str(tmp_path / "home"),
            "XDG_STATE_HOME": str(xdg),
            "SM_MAINTAIN_LOCK_WAIT_S": "0",
            "SM_WORKTREE_GC_PROJECT_ROOTS": str(tmp_path / "empty-projects"),
        }
        result = _run_maintain(env)
        assert result.returncode == 0, result.stderr
        assert "skipped:lock" in result.stdout


def test_maintain_reaps_eligible_worktree(tmp_path: Path):
    xdg = tmp_path / "xdg"
    home = tmp_path / "home"
    projects = tmp_path / "projects"
    home.mkdir()
    projects.mkdir()
    proc_root = tmp_path / "proc"
    proc_root.mkdir()
    repo = _make_repo(projects)
    wt = _add_worktree(repo, "abandoned")
    _age(wt, 8 * 24 * 60 * 60)

    env = {
        "HOME": str(home),
        "XDG_STATE_HOME": str(xdg),
        "SM_WORKTREE_GC_PROJECT_ROOTS": str(projects),
        "SM_WORKTREE_GC_PROC_ROOT": str(proc_root),
        "SM_WORKTREE_GC_BUDGET_MS": "120000",
        "SM_MAINTAIN_LOCK_WAIT_S": "0",
        "SM_BUDGET_UV_GIB": "9999",
        "SM_BUDGET_PNPM_GIB": "9999",
        "SM_BUDGET_PODMAN_GIB": "9999",
    }
    result = _run_maintain(env)
    assert result.returncode == 0, result.stdout + result.stderr
    assert "worktree-gc:1(0s)" in result.stdout
    assert not wt.exists(), result.stdout


def test_maintain_does_not_force_wipe_npm_or_pip(tmp_path: Path):
    text = MAINTAIN.read_text(encoding="utf-8")
    assert "npm cache clean --force" not in text
    assert "pip cache purge" not in text
    assert "AGENT_TMP_MAX_AGE" not in text
    assert "clean_agent_tmp" not in text
    assert "uv cache prune" in text
    assert "pnpm store prune" in text
    assert '--budget-ms "${SM_WORKTREE_GC_BUDGET_MS:-60000}"' in text
    assert '--proc-root "${SM_WORKTREE_GC_PROC_ROOT:-/proc}"' in text
