#!/usr/bin/env bash
#
# Git Credential Helper for Agent Relay Workspaces
#
# This script provides GitHub authentication for git operations using
# a multi-source fallback chain. It works offline and without cloud
# connectivity when local credentials are available.
#
# FALLBACK CHAIN (in order):
#   1. GH_TOKEN or GITHUB_TOKEN env vars - fastest, no I/O
#   2. ~/.config/gh/hosts.yml - gh CLI config file
#   3. gh auth token command - runs gh CLI
#   4. Cloud API - workspace-scoped token from Nango
#
# Usage: git config --global credential.helper /usr/local/bin/git-credential-relay
#
# Environment variables (only needed if fallbacks 1-3 fail):
#   WORKSPACE_ID      - The workspace ID for cloud token lookup
#   CLOUD_API_URL     - The cloud API base URL
#   WORKSPACE_TOKEN   - Bearer token for cloud API auth
#   GIT_CREDENTIAL_DEBUG=1 - Enable debug logging
#

set -euo pipefail

# Debug logging (enable with GIT_CREDENTIAL_DEBUG=1)
debug() {
  if [[ "${GIT_CREDENTIAL_DEBUG:-}" == "1" ]]; then
    echo "git-credential-relay: $*" >&2
  fi
}

debug "Called with args: $*"

# Only handle 'get' operation
if [[ "${1:-}" != "get" ]]; then
  debug "Ignoring non-get operation"
  exit 0
fi

# Read input from git (protocol=https, host=github.com, etc.)
declare -A input
while IFS='=' read -r key value; do
  [[ -z "$key" ]] && break
  input["$key"]="$value"
done

# Only provide credentials for github.com
host="${input[host]:-}"
debug "Host: $host"
if [[ "$host" != "github.com" ]]; then
  debug "Not github.com, skipping"
  exit 0
fi

# =====================================================================
# FALLBACK CHAIN (order matters - fastest/most reliable first):
# 1. GH_TOKEN/GITHUB_TOKEN env vars - direct, no lookup needed
# 2. ~/.config/gh/hosts.yml - local gh CLI config file
# 3. gh auth token command - runs gh CLI to get token
# 4. Cloud API - workspace-scoped token from Nango (requires network)
# =====================================================================

# Helper function to output credentials and exit successfully
output_credentials() {
  local token="$1"
  local source="$2"
  debug "Using token from: $source"
  echo "protocol=https"
  echo "host=github.com"
  echo "username=x-access-token"
  echo "password=${token}"
  exit 0
}

# Helper function to extract token from gh hosts.yml
extract_gh_hosts_token() {
  local hosts_file="$1"
  [[ ! -f "$hosts_file" ]] && return 1

  # Parse YAML to find github.com section and extract oauth_token or token
  local in_github_section=0
  while IFS= read -r line; do
    # Check for github.com host section (not indented)
    if [[ "$line" =~ ^github\.com: ]] || [[ "$line" == "github.com:" ]]; then
      in_github_section=1
      continue
    fi
    # Check if we've left the github.com section (new unindented line)
    if [[ $in_github_section -eq 1 ]] && [[ -n "$line" ]] && [[ ! "$line" =~ ^[[:space:]] ]]; then
      in_github_section=0
    fi
    # Extract token if in github.com section
    if [[ $in_github_section -eq 1 ]]; then
      if [[ "$line" =~ ^[[:space:]]*(oauth_token|token):[[:space:]]*(.+)$ ]]; then
        local token="${BASH_REMATCH[2]}"
        # Strip quotes and comments
        token="${token%%#*}"
        token="${token%\"}"
        token="${token#\"}"
        token="${token%\'}"
        token="${token#\'}"
        token="${token// /}"
        if [[ -n "$token" ]]; then
          echo "$token"
          return 0
        fi
      fi
    fi
  done < "$hosts_file"
  return 1
}

# FALLBACK 1: Environment variables (fastest - no I/O needed)
if [[ -n "${GH_TOKEN:-}" || -n "${GITHUB_TOKEN:-}" ]]; then
  token="${GH_TOKEN:-${GITHUB_TOKEN}}"
  output_credentials "$token" "GH_TOKEN/GITHUB_TOKEN env"
fi

# FALLBACK 2: gh CLI config file (~/.config/gh/hosts.yml)
# Check multiple possible locations for the hosts.yml file
gh_hosts_paths=(
  "${XDG_CONFIG_HOME:-$HOME/.config}/gh/hosts.yml"
  "$HOME/.config/gh/hosts.yml"
)

for hosts_path in "${gh_hosts_paths[@]}"; do
  if [[ -f "$hosts_path" ]]; then
    debug "Checking gh hosts.yml: $hosts_path"
    token=$(extract_gh_hosts_token "$hosts_path")
    if [[ -n "$token" ]]; then
      output_credentials "$token" "gh hosts.yml ($hosts_path)"
    fi
  fi
done

# FALLBACK 3: gh CLI command (requires gh to be installed and authenticated)
if command -v gh &>/dev/null; then
  debug "Trying gh auth token command"
  if token=$(gh auth token --hostname github.com 2>/dev/null); then
    token="${token// /}"
    if [[ -n "$token" ]]; then
      output_credentials "$token" "gh auth token"
    fi
  fi
fi

# FALLBACK 4: Cloud API (requires workspace env vars)
# Check required environment variables for cloud fallback
if [[ -z "${WORKSPACE_ID:-}" ]]; then
  echo "git-credential-relay: All credential sources failed." >&2
  echo "git-credential-relay: Fallback chain tried:" >&2
  echo "git-credential-relay:   1. GH_TOKEN/GITHUB_TOKEN env - not set" >&2
  echo "git-credential-relay:   2. ~/.config/gh/hosts.yml - no token found" >&2
  echo "git-credential-relay:   3. gh auth token - failed or not installed" >&2
  echo "git-credential-relay:   4. Cloud API - unavailable (WORKSPACE_ID not set)" >&2
  echo "git-credential-relay: Fix: Run 'gh auth login' or set GH_TOKEN env var" >&2
  exit 1
fi

if [[ -z "${CLOUD_API_URL:-}" ]]; then
  echo "git-credential-relay: All credential sources failed." >&2
  echo "git-credential-relay: Fallback chain tried:" >&2
  echo "git-credential-relay:   1. GH_TOKEN/GITHUB_TOKEN env - not set" >&2
  echo "git-credential-relay:   2. ~/.config/gh/hosts.yml - no token found" >&2
  echo "git-credential-relay:   3. gh auth token - failed or not installed" >&2
  echo "git-credential-relay:   4. Cloud API - unavailable (CLOUD_API_URL not set)" >&2
  echo "git-credential-relay: Fix: Run 'gh auth login' or set GH_TOKEN env var" >&2
  exit 1
fi

if [[ -z "${WORKSPACE_TOKEN:-}" ]]; then
  echo "git-credential-relay: All credential sources failed." >&2
  echo "git-credential-relay: Fallback chain tried:" >&2
  echo "git-credential-relay:   1. GH_TOKEN/GITHUB_TOKEN env - not set" >&2
  echo "git-credential-relay:   2. ~/.config/gh/hosts.yml - no token found" >&2
  echo "git-credential-relay:   3. gh auth token - failed or not installed" >&2
  echo "git-credential-relay:   4. Cloud API - unavailable (WORKSPACE_TOKEN not set)" >&2
  echo "git-credential-relay: Fix: Run 'gh auth login' or set GH_TOKEN env var" >&2
  exit 1
fi

debug "Fetching token from ${CLOUD_API_URL}/api/git/token?workspaceId=${WORKSPACE_ID}"

# Fetch fresh token from gateway (capture stderr for debugging)
http_code=""
response=""
if [[ "${GIT_CREDENTIAL_DEBUG:-}" == "1" ]]; then
  # With debug, show full curl output (5 second timeout)
  response=$(curl -sf --max-time 5 -w "\n%{http_code}" \
    -H "Authorization: Bearer ${WORKSPACE_TOKEN}" \
    "${CLOUD_API_URL}/api/git/token?workspaceId=${WORKSPACE_ID}" \
    2>&1) || true
  http_code="${response##*$'\n'}"
  response="${response%$'\n'*}"
  debug "HTTP response code: $http_code"
  debug "Response: ${response:0:200}"
else
  # 5 second timeout to prevent git operations from hanging
  response=$(curl -sf --max-time 5 \
    -H "Authorization: Bearer ${WORKSPACE_TOKEN}" \
    "${CLOUD_API_URL}/api/git/token?workspaceId=${WORKSPACE_ID}" \
    2>/dev/null) || true
fi

if [[ -z "$response" ]]; then
  echo "git-credential-relay: All credential sources failed." >&2
  echo "git-credential-relay: Fallback chain tried:" >&2
  echo "git-credential-relay:   1. GH_TOKEN/GITHUB_TOKEN env - not set" >&2
  echo "git-credential-relay:   2. ~/.config/gh/hosts.yml - no token found" >&2
  echo "git-credential-relay:   3. gh auth token - failed or not installed" >&2
  echo "git-credential-relay:   4. Cloud API (${CLOUD_API_URL}) - failed to fetch" >&2
  echo "git-credential-relay: Fix: Run 'gh auth login' or set GH_TOKEN env var" >&2
  exit 1
fi

# Parse JSON response using jq (more robust than grep)
# Prefer userToken for git operations (works with credential helpers)
# Fall back to token field (which is also userToken-first since the API change)
token=$(echo "$response" | jq -r '.userToken // .token // empty')
username=$(echo "$response" | jq -r '.username // "x-access-token"')
token_type=$(echo "$response" | jq -r '.tokenType // "unknown"')
debug "Token type: $token_type"

if [[ -z "$token" ]]; then
  # Check if there's an error message with details
  error=$(echo "$response" | jq -r '.error // empty')
  code=$(echo "$response" | jq -r '.code // empty')
  hint=$(echo "$response" | jq -r '.hint // empty')
  details=$(echo "$response" | jq -r '.details // empty')

  echo "git-credential-relay: All credential sources failed." >&2
  echo "git-credential-relay: Fallback chain tried:" >&2
  echo "git-credential-relay:   1. GH_TOKEN/GITHUB_TOKEN env - not set" >&2
  echo "git-credential-relay:   2. ~/.config/gh/hosts.yml - no token found" >&2
  echo "git-credential-relay:   3. gh auth token - failed or not installed" >&2
  echo "git-credential-relay:   4. Cloud API - " >&2
  if [[ -n "$error" ]]; then
    echo "git-credential-relay:      Error: $error" >&2
    [[ -n "$code" ]] && echo "git-credential-relay:      Code: $code" >&2
    [[ -n "$hint" ]] && echo "git-credential-relay:      Hint: $hint" >&2
    [[ -n "$details" ]] && echo "git-credential-relay:      Details: $details" >&2
  else
    echo "git-credential-relay:      No token in response" >&2
    debug "Raw response: $response"
  fi
  echo "git-credential-relay: Fix: Run 'gh auth login' or set GH_TOKEN env var" >&2
  exit 1
fi

# Output credentials in git credential format
echo "protocol=https"
echo "host=github.com"
echo "username=${username:-x-access-token}"
echo "password=${token}"
