#!/bin/bash
# RepoGoon pre-receive hook
# This hook enforces branch protection rules including require_pr

# Get the server URL from environment or default
REPOGOON_INTERNAL_URL="${REPOGOON_INTERNAL_URL:-http://localhost:3001}"
REPOGOON_CONFIG="${REPOGOON_CONFIG:-/etc/repogoon/config.yml}"

get_internal_secret_from_config() {
    if [ ! -f "$REPOGOON_CONFIG" ]; then
        return 0
    fi

    if command -v yq >/dev/null 2>&1; then
        yq '.server.internalSecret // ""' "$REPOGOON_CONFIG" 2>/dev/null | sed 's/^"//' | sed 's/"$//'
        return 0
    fi

    grep -E '^[[:space:]]*internalSecret:' "$REPOGOON_CONFIG" 2>/dev/null | head -1 | awk -F: '{print $2}' | xargs
}

# Prefer config value, fallback to environment variable.
CONFIG_INTERNAL_SECRET="$(get_internal_secret_from_config)"
if [ -n "$CONFIG_INTERNAL_SECRET" ]; then
    REPOGOON_INTERNAL_SECRET="$CONFIG_INTERNAL_SECRET"
else
    REPOGOON_INTERNAL_SECRET="${REPOGOON_INTERNAL_SECRET:-}"
fi

if [ -z "$REPOGOON_INTERNAL_SECRET" ]; then
    echo "remote: ERROR: Internal secret is not configured (server.internalSecret or REPOGOON_INTERNAL_SECRET)."
    exit 1
fi

# Read all ref updates from stdin
while read oldrev newrev refname; do
    # Skip if deleting a branch (newrev is all zeros)
    if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then
        continue
    fi
    
    # Extract branch name from refs/heads/branchname
    if [[ "$refname" == refs/heads/* ]]; then
        branch="${refname#refs/heads/}"
    else
        # Not a branch update (could be tag), allow it
        continue
    fi
    
    # Detect force push (when history is rewritten)
    is_force_push=false
    if [ "$oldrev" != "0000000000000000000000000000000000000000" ]; then
        # Check if old commit is ancestor of new commit
        # If not, it's a force push
        if ! git merge-base --is-ancestor "$oldrev" "$newrev" 2>/dev/null; then
            is_force_push=true
        fi
    fi
    
    # Get repository path components
    # GIT_DIR is set to the repo path (e.g., /path/to/repos/username/reponame.git)
    # Resolve to absolute path in case GIT_DIR is "." or relative
    if [ "$GIT_DIR" = "." ] || [[ "$GIT_DIR" != /* ]]; then
        repo_path="$(cd "$GIT_DIR" && pwd)"
    else
        repo_path="$GIT_DIR"
    fi
    repo_basename=$(basename "$repo_path" .git)
    namespace_dir=$(dirname "$repo_path")
    namespace=$(basename "$namespace_dir")
    
    # Call the internal validation API
    response=$(curl -s -X POST "${REPOGOON_INTERNAL_URL}/api/internal/validate-push" \
        -H "Content-Type: application/json" \
        -H "X-Internal-Secret: ${REPOGOON_INTERNAL_SECRET}" \
        -d "{
            \"namespace\": \"${namespace}\",
            \"repo\": \"${repo_basename}\",
            \"branch\": \"${branch}\",
            \"oldrev\": \"${oldrev}\",
            \"newrev\": \"${newrev}\",
            \"is_force_push\": ${is_force_push},
            \"username\": \"${REMOTE_USER}\"
        }" 2>/dev/null)
    
    # Check response
    allowed=$(echo "$response" | grep -o '"allowed":[^,}]*' | cut -d':' -f2 | tr -d ' ')
    message=$(echo "$response" | grep -o '"message":"[^"]*"' | cut -d'"' -f4)
    
    if [ "$allowed" != "true" ]; then
        echo "remote: ERROR: ${message:-Push rejected by branch protection rules}"
        exit 1
    fi
done

exit 0
