#!/usr/bin/env bash
set -euo pipefail

root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "${root}"

host="${EVERY_CHANNEL_FORGE_HOST:-https://git.every.channel}"
repo="${EVERY_CHANNEL_FORGE_REPO:-every-channel/every.channel}"
branch="${EVERY_CHANNEL_PROTECTED_BRANCH:-main}"
required_checks_csv="${EVERY_CHANNEL_REQUIRED_CHECKS:-ci-gates / checks}"
required_approvals="${EVERY_CHANNEL_REQUIRED_APPROVALS:-1}"
require_signed_commits_raw="${EVERY_CHANNEL_REQUIRE_SIGNED_COMMITS:-true}"

rules_file="${EVERY_CHANNEL_AGE_RULES_FILE:-./secrets.nix}"
identity_file="${EVERY_CHANNEL_AGE_IDENTITY_FILE:-$HOME/.config/every.channel/keys/founder_ed25519}"
token_file_primary="${EVERY_CHANNEL_FORGE_TOKEN_FILE:-secrets/forgejo-api-token.age}"
token_file_secondary="${EVERY_CHANNEL_LEGACY_FORGE_TOKEN_FILE:-secrets/forge-token.age}"
token_file_compat="${EVERY_CHANNEL_CODEBERG_TOKEN_FILE:-secrets/codeberg-token.age}"

token="${EVERY_CHANNEL_FORGE_TOKEN:-${FORGE_TOKEN:-${CODEBERG_TOKEN:-}}}"

load_token_from_file() {
  local candidate="$1"
  [[ -f "${candidate}" && -f "${identity_file}" ]] || return 1
  if command -v agenix >/dev/null 2>&1; then
    RULES="${rules_file}" agenix -d "${candidate}" -i "${identity_file}" 2>/dev/null || return 1
    return 0
  fi
  if command -v age >/dev/null 2>&1; then
    age -d -i "${identity_file}" "${candidate}" 2>/dev/null || return 1
    return 0
  fi
  return 1
}

if [[ -z "${token}" ]]; then
  token="$(load_token_from_file "${token_file_primary}" || true)"
fi
if [[ -z "${token}" ]]; then
  token="$(load_token_from_file "${token_file_secondary}" || true)"
fi
if [[ -z "${token}" ]]; then
  token="$(load_token_from_file "${token_file_compat}" || true)"
fi

if [[ -z "${token}" ]]; then
  echo "error: forge token is not set" >&2
  echo "hint: set EVERY_CHANNEL_FORGE_TOKEN/FORGE_TOKEN or configure ${token_file_primary}" >&2
  exit 2
fi

if [[ ! "${repo}" =~ ^[^/]+/[^/]+$ ]]; then
  echo "error: EVERY_CHANNEL_FORGE_REPO must be '<owner>/<repo>' (got '${repo}')" >&2
  exit 2
fi

case "${required_approvals}" in
  ''|*[!0-9]*)
    echo "error: EVERY_CHANNEL_REQUIRED_APPROVALS must be a non-negative integer" >&2
    exit 2
    ;;
esac

require_signed_commits_raw_lc="$(printf '%s' "${require_signed_commits_raw}" | tr '[:upper:]' '[:lower:]')"
require_signed_commits="false"
if [[ "${require_signed_commits_raw_lc}" == "true" || "${require_signed_commits_raw}" == "1" ]]; then
  require_signed_commits="true"
fi

owner="${repo%%/*}"
repo_name="${repo#*/}"
api="${host%/}/api/v1/repos/${owner}/${repo_name}/branch_protections"

contexts_json=""
IFS=',' read -r -a contexts <<< "${required_checks_csv}"
for ctx in "${contexts[@]}"; do
  trimmed="$(echo "${ctx}" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')"
  [[ -n "${trimmed}" ]] || continue
  escaped="$(printf '%s' "${trimmed}" | sed 's/\\/\\\\/g; s/"/\\"/g')"
  if [[ -n "${contexts_json}" ]]; then
    contexts_json+=", "
  fi
  contexts_json+="\"${escaped}\""
done

if [[ -z "${contexts_json}" ]]; then
  echo "error: no required status checks specified (EVERY_CHANNEL_REQUIRED_CHECKS)" >&2
  exit 2
fi

payload="$(cat <<JSON
{
  "rule_name": "${branch}",
  "enable_push": false,
  "enable_push_whitelist": false,
  "enable_merge_whitelist": false,
  "enable_status_check": true,
  "status_check_contexts": [${contexts_json}],
  "required_approvals": ${required_approvals},
  "require_signed_commits": ${require_signed_commits}
}
JSON
)"

status="$(curl -sS -o /dev/null -w '%{http_code}' \
  -H "Authorization: token ${token}" \
  "${api}/${branch}" || true)"

if [[ "${status}" == "404" ]]; then
  curl -fsSL -X POST \
    -H "Authorization: token ${token}" \
    -H "content-type: application/json" \
    "${api}" \
    -d "${payload}" >/dev/null
elif [[ "${status}" == "200" ]]; then
  curl -fsSL -X PATCH \
    -H "Authorization: token ${token}" \
    -H "content-type: application/json" \
    "${api}/${branch}" \
    -d "${payload}" >/dev/null
else
  echo "error: unexpected status while reading branch protection: ${status}" >&2
  exit 2
fi

current="$(curl -fsSL \
  -H "Authorization: token ${token}" \
  "${api}/${branch}")"

if ! printf '%s' "${current}" | rg -q '"enable_status_check":\s*true'; then
  echo "error: branch protection update did not enable status checks" >&2
  exit 2
fi
if ! printf '%s' "${current}" | rg -q "\"required_approvals\":\\s*${required_approvals}"; then
  echo "error: branch protection update did not set required approvals to ${required_approvals}" >&2
  exit 2
fi
for ctx in "${contexts[@]}"; do
  trimmed="$(echo "${ctx}" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')"
  [[ -n "${trimmed}" ]] || continue
  if ! printf '%s' "${current}" | rg -F -q "\"${trimmed}\""; then
    echo "error: required status check context missing after update: ${trimmed}" >&2
    exit 2
  fi
done

echo "ok: enforced branch protection for ${repo}:${branch}"
echo "ok: required checks: ${required_checks_csv}"
echo "ok: required approvals: ${required_approvals}"
