#!/usr/bin/env bash
# gitea-token — manage Gitea npm tokens (rotate, validate, print).
#
# Usage:
#   bash scripts/gitea/token.sh status                # show env vs file status
#   bash scripts/gitea/token.sh print                 # print current token to stdout
#   bash scripts/gitea/token.sh validate              # HTTP 200 probe against registry
#   bash scripts/gitea/token.sh rotate                # mint new token, write to file
#                                                       (requires GITEA_ADMIN_USER/PASS in env
#                                                        or macOS Keychain entry 'gitea-admin')
#
# Token file resolution (matches switch-network.sh):
#   ~/.gitea_npm_token_${NETWORK}   (per-network, preferred)
#   ~/.gitea_npm_token              (fallback)
#
# Why this exists:
#   - Stops manual file editing → stale shell envs.
#   - One command rotates the token, writes the file, exports to current shell.
#   - In any shell, `eval "$(bash gitea/token.sh print --export)"` refreshes
#     GITEA_NPM_TOKEN without re-sourcing ~/.zshrc.

set -uo pipefail

cmd="${1:-status}"
shift 2>/dev/null || true

NETWORK="${NETWORK:-home}"
GITEA_NPM_HOST="${GITEA_NPM_HOST:-localhost}"
GITEA_NPM_OWNER="${GITEA_NPM_OWNER:-learning_ai_user}"

# ── Resolve token file path ─────────────────────────────────────
resolve_file() {
  for candidate in "$HOME/.gitea_npm_token_${NETWORK}" "$HOME/.gitea_npm_token"; do
    if [ -f "$candidate" ]; then
      echo "$candidate"
      return 0
    fi
  done
  # If neither exists, prefer per-network path for new file creation
  echo "$HOME/.gitea_npm_token_${NETWORK}"
}

TOKEN_FILE="$(resolve_file)"

read_token_file() {
  [ -f "$TOKEN_FILE" ] && tr -d '\n\r ' < "$TOKEN_FILE" || echo ""
}

# ── Resolve admin credentials (for rotate) ───────────────────────
# Priority: env vars → macOS Keychain → fail
get_admin_credentials() {
  if [ -n "${GITEA_ADMIN_USER:-}" ] && [ -n "${GITEA_ADMIN_PASS:-}" ]; then
    echo "$GITEA_ADMIN_USER:$GITEA_ADMIN_PASS"
    return 0
  fi
  if command -v security >/dev/null 2>&1; then
    local pass
    pass="$(security find-generic-password -s 'gitea-admin' -w 2>/dev/null || true)"
    local user
    user="$(security find-generic-password -s 'gitea-admin' 2>/dev/null \
            | awk -F'"' '/"acct"/{print $4}' || true)"
    if [ -n "$pass" ] && [ -n "$user" ]; then
      echo "$user:$pass"
      return 0
    fi
  fi
  return 1
}

# ── Subcommand: status ───────────────────────────────────────────
do_status() {
  echo "Network:       $NETWORK"
  echo "Host:          $GITEA_NPM_HOST"
  echo "Owner:         $GITEA_NPM_OWNER"
  echo "Token file:    $TOKEN_FILE"
  local f="$(read_token_file)"
  local e="${GITEA_NPM_TOKEN:-}"
  if [ -z "$f" ]; then
    echo "File status:   MISSING — run '$0 rotate' or create manually"
  else
    echo "File status:   exists (${#f} chars, starts ${f:0:8}…)"
  fi
  if [ -z "$e" ]; then
    echo "Env status:    UNSET in current shell"
  elif [ -z "$f" ]; then
    echo "Env status:    set but no file to compare"
  elif [ "$e" = "$f" ]; then
    echo "Env vs file:   ✓ MATCH"
  else
    echo "Env vs file:   ✗ STALE — env=${e:0:8}…, file=${f:0:8}… (run: source ~/.zshrc)"
  fi
}

# ── Subcommand: print ────────────────────────────────────────────
do_print() {
  local export_flag=false
  [ "${1:-}" = "--export" ] && export_flag=true
  local t="$(read_token_file)"
  if [ -z "$t" ]; then
    echo "Error: no token in $TOKEN_FILE" >&2
    exit 1
  fi
  if $export_flag; then
    echo "export GITEA_NPM_TOKEN='$t'"
  else
    echo "$t"
  fi
}

# ── Subcommand: validate ─────────────────────────────────────────
do_validate() {
  local t="${GITEA_NPM_TOKEN:-$(read_token_file)}"
  if [ -z "$t" ]; then
    echo "Error: no token available" >&2
    exit 1
  fi
  local url="http://${GITEA_NPM_HOST}:3300/api/packages/${GITEA_NPM_OWNER}/npm/@bytelyst%2Ferrors"
  local code
  code=$(curl -fsS -o /dev/null -w "%{http_code}" "$url" \
    -H "Authorization: token $t" --noproxy '*' --max-time 5 2>/dev/null || echo "000")
  case "$code" in
    200) echo "✓ Token valid (HTTP 200 against @bytelyst/errors)" ;;
    401|403) echo "✗ Token rejected (HTTP $code) — rotate it"; exit 1 ;;
    404) echo "✗ Owner '$GITEA_NPM_OWNER' not found on $GITEA_NPM_HOST (HTTP 404)"; exit 1 ;;
    000) echo "✗ Registry unreachable at $url"; exit 1 ;;
    *)   echo "✗ Unexpected HTTP $code"; exit 1 ;;
  esac
}

# ── Subcommand: rotate ───────────────────────────────────────────
do_rotate() {
  local creds
  if ! creds=$(get_admin_credentials); then
    cat >&2 <<EOF
Error: cannot rotate without admin credentials.

Set one of:
  1. Env vars:        GITEA_ADMIN_USER=<u> GITEA_ADMIN_PASS=<p>
  2. macOS Keychain:  security add-generic-password -s 'gitea-admin' \\
                        -a '<gitea-username>' -w '<password>'

Then re-run: $0 rotate
EOF
    exit 1
  fi

  local user="${creds%:*}"
  local pass="${creds#*:}"
  local token_name="npm-$(date +%Y%m%d-%H%M%S)-$(hostname -s)"

  echo "Minting token '$token_name' for user '$user' on $GITEA_NPM_HOST…"
  local response
  response=$(curl -fsS -u "$user:$pass" \
    -X POST "http://${GITEA_NPM_HOST}:3300/api/v1/users/$user/tokens" \
    -H 'Content-Type: application/json' \
    --noproxy '*' --max-time 10 \
    -d "{\"name\":\"$token_name\",\"scopes\":[\"write:package\",\"read:package\"]}" 2>&1)
  local rc=$?

  if [ $rc -ne 0 ]; then
    echo "✗ API call failed:" >&2
    echo "$response" >&2
    exit 1
  fi

  # Gitea returns the secret as "sha1" (older) or "token" (newer)
  local new_token
  new_token=$(echo "$response" | grep -oE '"(sha1|token)":"[^"]+' | head -1 | sed 's/.*":"//')
  if [ -z "$new_token" ]; then
    echo "✗ Could not extract token from response:" >&2
    echo "$response" >&2
    exit 1
  fi

  # Backup old, write new
  if [ -f "$TOKEN_FILE" ]; then
    cp "$TOKEN_FILE" "${TOKEN_FILE}.bak"
  fi
  printf '%s' "$new_token" > "$TOKEN_FILE"
  chmod 600 "$TOKEN_FILE"

  echo "✓ Written to $TOKEN_FILE (mode 600, ${#new_token} chars)"
  echo "✓ Old token backed up to ${TOKEN_FILE}.bak"
  echo ""
  echo "To refresh the current shell:"
  echo "  eval \"\$(bash '$0' print --export)\""
  echo ""
  echo "Validating new token…"
  GITEA_NPM_TOKEN="$new_token" do_validate
}

case "$cmd" in
  status)   do_status ;;
  print)    do_print "$@" ;;
  validate) do_validate ;;
  rotate)   do_rotate ;;
  -h|--help) sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//' ;;
  *) echo "Unknown command: $cmd (use: status|print|validate|rotate)" >&2; exit 2 ;;
esac
