"""
Post-commit hook helpers: force-with-lease push to remotes via the git CLI.
"""

from __future__ import annotations

import os
import re
import shutil
import subprocess
from sys import stderr

import pygit2

from pygittools.hooks import HookResult, PostCommit


def git_executable() -> str:
	"""Return the git binary to invoke (``GIT`` env, then ``PATH``, else ``git``)."""
	return os.environ.get("GIT") or shutil.which("git") or "git"


def force_with_lease_push(
	repo: pygit2.Repository,
	remote_name: str,
	branch: str,
	*,
	git: str | None = None,
) -> str | None:
	"""Force-with-lease push ``branch`` to ``remote_name``. Returns an error string or None."""
	workdir: str | None = repo.workdir
	if workdir is None:
		return "bare repository has no working tree"
	if branch not in repo.branches.local:
		return f"branch {branch!r} does not exist locally"
	if remote_name not in repo.remotes.names():
		return f"remote {remote_name!r} not configured"
	binary: str = git or git_executable()
	proc: subprocess.CompletedProcess[str] = subprocess.run(
		[binary, "-C", workdir, "push", "--force-with-lease", remote_name, branch],
		capture_output=True,
		text=True,
	)
	if proc.returncode != 0:
		return (proc.stderr or proc.stdout or "push failed").strip()
	return None


class PostCommitPushRemotes(PostCommit):
	"""After each commit, force-with-lease push the current branch to every remote if it matches a pattern."""

	def __init__(self, repo: pygit2.Repository, branch_pattern: str) -> None:
		super().__init__(repo)
		self._branch_exp: re.Pattern[str] = re.compile(branch_pattern)

	def run(self) -> HookResult:
		if self.repo.head_is_detached:
			return HookResult.SUCCESS
		branch: str = self.repo.head.shorthand
		if not self._branch_exp.match(branch):
			return HookResult.SUCCESS
		if self.repo.workdir is None:
			stderr.write("PostCommitPushRemotes: bare repository; skipping push.\n")
			return HookResult.SUCCESS
		remote_names: list[str] = list(self.repo.remotes.names())
		if not remote_names:
			return HookResult.SUCCESS
		failures: list[str] = []
		for remote_name in remote_names:
			error: str | None = force_with_lease_push(self.repo, remote_name, branch)
			if error is not None:
				failures.append(f"{remote_name}: {error}")
		if failures:
			stderr.write(f"PostCommitPushRemotes ({branch}): push failed:\n")
			for line in failures:
				stderr.write(f"  {line}\n")
		return HookResult.SUCCESS