#!/usr/bin/env -S uv run python

from __future__ import annotations

__VERSION__ = "1"

import os
import sys
from pathlib import Path

from pygittools.hooks import HookResult, RefUpdate, parse_ref_updates
from pygitweb.auth_config import DEFAULT_AUTH_CONFIG_PATH, AuthConfig
from pygitweb.permissions import PermissionsMap, has_branch_write_permission


def _normalize_env(name: str) -> str | None:
	value = os.environ.get(name)
	if value is None:
		return None
	stripped = value.strip()
	return stripped or None


def _load_permissions() -> PermissionsMap | None:
	config_path_env = _normalize_env("PYGITWEB_AUTH_CONFIG")
	path = Path(config_path_env).expanduser() if config_path_env is not None else DEFAULT_AUTH_CONFIG_PATH
	try:
		text = path.read_text(encoding="utf-8")
	except OSError:
		return None
	try:
		config = AuthConfig.model_validate_json(text)
	except Exception:
		return None
	return config.oauth_permissions


def _check_updates(
	principal: str,
	project: str,
	updates: list[RefUpdate],
	permissions: PermissionsMap,
) -> HookResult:
	for _, _, ref_name in updates:
		if has_branch_write_permission(permissions, principal, project, ref_name):
			continue
		sys.stderr.write(
			f"Push rejected: {principal!r} lacks branch write permission for project {project!r} ref {ref_name!r}.\n",
		)
		return HookResult.FAILURE
	return HookResult.SUCCESS


def main() -> int:
	principal = _normalize_env("PYGITWEB_PRINCIPAL")
	project = _normalize_env("PYGITWEB_PROJECT")
	if principal is None or project is None:
		return int(HookResult.SUCCESS.value)
	permissions = _load_permissions()
	if permissions is None:
		return int(HookResult.SUCCESS.value)
	updates = parse_ref_updates(sys.stdin)
	result = _check_updates(principal, project, updates, permissions)
	return int(result.value)


if __name__ == "__main__":
	raise SystemExit(main())