"""Prepare CI updates away from action manifests the current runner may reload."""
from __future__ import annotations

import os
from pathlib import Path
import re
import shutil
import subprocess
import sys
import tempfile


def git(root: Path, *args: str) -> str:
    result = subprocess.run(["git", *args], cwd=root, capture_output=True,
                            text=True, check=False, timeout=60)
    if result.returncode:
        raise RuntimeError("autoupdate_worktree_git_failed")
    return result.stdout.strip()


def stage(root: Path) -> None:
    git(root, "add", "-A", "--force", "--", ".github/actions/swift-app/", ".github/actions/android-app/")
    names = git(root, "diff", "--cached", "--name-only", "-z").split("\0")
    bytecode = [name for name in names if "/__pycache__/" in name or name.endswith((".pyc", ".pyo"))]
    if bytecode:
        git(root, "reset", "--quiet", "HEAD", "--", *bytecode)


def update(version: str) -> None:
    if not re.fullmatch(r"\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?(?:\+[A-Za-z0-9.-]+)?", version):
        raise RuntimeError("autoupdate_version_invalid")
    root = Path.cwd()
    base = git(root, "rev-parse", "HEAD")
    parent = Path(tempfile.mkdtemp(prefix="app-ci-update-", dir=os.environ["RUNNER_TEMP"]))
    worktree = parent / "checkout"
    added = False
    try:
        git(root, "worktree", "add", "--detach", str(worktree), base)
        added = True
        result = subprocess.run(["npx", "--yes", "gowalk-cicd@" + version], cwd=worktree,
                                check=False, timeout=180)
        if result.returncode:
            print("::warning::autoupdate: pinned package installation failed; keeping the current build")
            return
        stage(worktree)
        script = Path(__file__).with_name("commit_bot_changes.sh")
        result = subprocess.run(["bash", str(script)], cwd=worktree, check=False, timeout=180)
        if result.returncode:
            raise RuntimeError("autoupdate_source_preservation_failed")
    finally:
        if added:
            git(root, "worktree", "remove", "--force", str(worktree))
        shutil.rmtree(parent)


if __name__ == "__main__":
    try:
        update(sys.argv[1])
    except (RuntimeError, OSError, subprocess.SubprocessError) as exc:
        code = str(exc) if isinstance(exc, RuntimeError) else "autoupdate_operation_unverified"
        print("::error::" + code, file=sys.stderr)
        raise SystemExit(1) from None
