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

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEFAULT_APP_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
APP_DIR="$(git -C "$DEFAULT_APP_DIR" rev-parse --show-toplevel 2>/dev/null || printf '%s' "$DEFAULT_APP_DIR")"
force_commit="${GIT_FORCE_COMMIT:-0}"
if [[ "${1:-}" == "--force-commit" ]]; then
  force_commit="1"
  shift
fi
if [[ ! "$force_commit" =~ ^[01]$ ]]; then
  echo "[vmess-domain-rotator] invalid GIT_FORCE_COMMIT=${force_commit}, expected 0 or 1"
  exit 1
fi
CONFIG_PATH="${1:-${APP_DIR}/config.server.json}"

export GIT_TERMINAL_PROMPT=0

commit_name="${GIT_COMMIT_NAME:-vmess-domain-rotator}"
commit_email="${GIT_COMMIT_EMAIL:-vmess-domain-rotator@localhost}"
runtime_branch="${GIT_RUNTIME_BRANCH:-runtime-state}"
push_remote="${GIT_PUSH_REMOTE:-origin}"
push_enabled="${GIT_PUSH_ENABLED:-1}"
push_required="${GIT_PUSH_REQUIRED:-${push_enabled}}"
http_user="${GIT_HTTP_USERNAME:-git}"
http_token="${GIT_HTTP_TOKEN:-}"
http_token_file="${GIT_HTTP_TOKEN_FILE:-}"
credential_helper="${GIT_CREDENTIAL_HELPER:-}"
ts="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"

if [[ -z "$http_token" ]] && [[ -n "$http_token_file" ]] && [[ -r "$http_token_file" ]]; then
  http_token="$(tr -d '\r\n' < "$http_token_file")"
fi
git_auth_opts=()
if [[ -n "$http_token" ]]; then
  auth_b64="$(printf '%s:%s' "$http_user" "$http_token" | base64 | tr -d '\n')"
  git_auth_opts=(-c "http.extraHeader=Authorization: Basic ${auth_b64}")
fi

git_auth() {
  local dir="$1"
  shift
  if [[ -n "$credential_helper" ]]; then
    git -C "$dir" -c credential.helper="$credential_helper" "${git_auth_opts[@]}" "$@"
  else
    git -C "$dir" "${git_auth_opts[@]}" "$@"
  fi
}

output_settings_json="$(/usr/bin/python3 "${APP_DIR}/scripts/domain_updater.py" --config "$CONFIG_PATH" --print-output-settings)"
mapfile -t output_settings < <(
  printf '%s' "$output_settings_json" | /usr/bin/python3 -c '
import json, sys
settings = json.load(sys.stdin)
for key in ["runtime_dir", "selected_text_path", "selected_json_path", "state_path", "vars_path"]:
    print(settings[key])
'
)

RUNTIME_DIR="${output_settings[0]}"
SELECTED_TEXT_FILE="${output_settings[1]}"
SELECTED_JSON_FILE="${output_settings[2]}"
STATE_FILE="${output_settings[3]}"
VARS_FILE="${output_settings[4]}"

repo_relpath() {
  /usr/bin/python3 - "$APP_DIR" "$1" <<'PY'
import os
import sys

base = os.path.realpath(sys.argv[1])
path = os.path.realpath(sys.argv[2])
try:
    common = os.path.commonpath([base, path])
except ValueError:
    common = ""
if common != base:
    print("")
else:
    print(os.path.relpath(path, base))
PY
}

/usr/bin/python3 "${APP_DIR}/scripts/domain_updater.py" --config "$CONFIG_PATH"

if [[ ! -f "$SELECTED_TEXT_FILE" ]]; then
  echo "[vmess-domain-rotator] selected value file missing after updater run (${SELECTED_TEXT_FILE}), skip git commit"
  exit 0
fi

after="$(tr -d '\r\n' < "$SELECTED_TEXT_FILE")"

if [[ -z "$after" ]]; then
  echo "[vmess-domain-rotator] empty selected value, skip git commit"
  exit 0
fi

selected_rel="$(repo_relpath "$SELECTED_TEXT_FILE")"
if [[ -z "$selected_rel" ]]; then
  echo "[vmess-domain-rotator] selected value file is outside repo (${SELECTED_TEXT_FILE}), skip git commit"
  exit 0
fi

if ! command -v git >/dev/null 2>&1; then
  echo "[vmess-domain-rotator] git not found, skip git commit"
  exit 0
fi

if ! git -C "$APP_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
  echo "[vmess-domain-rotator] not a git repo at ${APP_DIR}, skip git commit"
  echo "[vmess-domain-rotator] hint: reinstall service from a git clone path"
  exit 0
fi

if ! git -C "$APP_DIR" rev-parse --verify HEAD >/dev/null 2>&1; then
  echo "[vmess-domain-rotator] repo has no commits yet, skip git commit"
  exit 0
fi

if ! git -C "$APP_DIR" remote get-url "$push_remote" >/dev/null 2>&1; then
  push_remote=""
  while IFS= read -r r; do
    push_remote="$r"
    break
  done < <(git -C "$APP_DIR" remote)
fi

work_dir=""
cleanup_worktree="0"
current_branch="$(git -C "$APP_DIR" symbolic-ref --quiet --short HEAD 2>/dev/null || true)"

if [[ "$current_branch" == "$runtime_branch" ]]; then
  work_dir="$APP_DIR"
else
  work_dir="$(mktemp -d "${TMPDIR:-/tmp}/vmess-runtime-state.XXXXXX")"
  cleanup_worktree="1"

  if git -C "$APP_DIR" show-ref --verify --quiet "refs/heads/${runtime_branch}"; then
    git -C "$APP_DIR" worktree add --force "$work_dir" "$runtime_branch"
  else
    if [[ -n "$push_remote" ]] && git_auth "$APP_DIR" ls-remote --exit-code --heads "$push_remote" "$runtime_branch" >/dev/null 2>&1; then
      git_auth "$APP_DIR" fetch "$push_remote" "$runtime_branch:$runtime_branch"
      git -C "$APP_DIR" worktree add --force "$work_dir" "$runtime_branch"
    else
      git -C "$APP_DIR" worktree add --force --detach "$work_dir"
      git -C "$work_dir" checkout --orphan "$runtime_branch"
      git -C "$work_dir" rm -rf . >/dev/null 2>&1 || true
      echo "[vmess-domain-rotator] initialized branch ${runtime_branch}"
    fi
  fi
fi

if [[ "$cleanup_worktree" == "1" ]]; then
  cleanup() {
    git -C "$APP_DIR" worktree remove --force "$work_dir" >/dev/null 2>&1 || rm -rf "$work_dir"
  }
  trap cleanup EXIT
fi

work_branch="$(git -C "$work_dir" symbolic-ref --quiet --short HEAD 2>/dev/null || true)"
if [[ "$work_branch" != "$runtime_branch" ]]; then
  echo "[vmess-domain-rotator] safety check failed: worktree branch is '${work_branch:-detached}', expected '${runtime_branch}'"
  exit 1
fi

before=""
if before_raw="$(git -C "$work_dir" show "HEAD:${selected_rel}" 2>/dev/null)"; then
  before="$(printf '%s' "$before_raw" | tr -d '\r\n')"
fi

if [[ "$force_commit" != "1" ]] && [[ -n "$before" ]] && [[ "$after" == "$before" ]]; then
  echo "[vmess-domain-rotator] selected value unchanged (${after}), skip git commit and push"
  exit 0
fi

tracked_src_files=("$SELECTED_TEXT_FILE" "$SELECTED_JSON_FILE" "$STATE_FILE" "$VARS_FILE")
tracked_rel_files=()
for src in "${tracked_src_files[@]}"; do
  rel="$(repo_relpath "$src")"
  if [[ -z "$rel" ]]; then
    echo "[vmess-domain-rotator] skip non-repo output file: ${src}"
    continue
  fi
  tracked_rel_files+=("$rel")
  dst="$work_dir/$rel"
  mkdir -p "$(dirname "$dst")"
  if [[ -f "$src" ]]; then
    cp "$src" "$dst"
  else
    rm -f "$dst"
  fi
done

if [[ "${#tracked_rel_files[@]}" -eq 0 ]]; then
  echo "[vmess-domain-rotator] no repo-local output files from config (${CONFIG_PATH}), skip git commit"
  exit 0
fi

git -C "$work_dir" add -A -- "${tracked_rel_files[@]}" || true

staged_changed="1"
if git -C "$work_dir" diff --cached --quiet; then
  staged_changed="0"
fi

if [[ "$staged_changed" == "0" ]] && [[ "$force_commit" != "1" ]]; then
  echo "[vmess-domain-rotator] no staged changes for ${runtime_branch}, skip git commit"
  exit 0
fi

commit_extra_args=()
if [[ "$staged_changed" == "0" ]] && [[ "$force_commit" == "1" ]]; then
  commit_extra_args+=(--allow-empty)
  echo "[vmess-domain-rotator] force commit enabled with unchanged content, creating empty commit"
fi

commit_message="chore: rotate preferred value to ${after} (${ts})"
if [[ "$force_commit" == "1" ]]; then
  commit_message="manual: value ${after}, updated at ${ts}"
fi

git -C "$work_dir" \
  -c user.name="$commit_name" \
  -c user.email="$commit_email" \
  commit "${commit_extra_args[@]}" -m "$commit_message"

if [[ "$push_enabled" != "1" ]]; then
  echo "[vmess-domain-rotator] git push disabled by GIT_PUSH_ENABLED=${push_enabled}"
elif [[ -z "$push_remote" ]]; then
  if [[ "$push_required" == "1" ]]; then
    echo "[vmess-domain-rotator] no remote found but push is required"
    exit 1
  fi
  echo "[vmess-domain-rotator] no remote found, skip git push"
else
  push_ok="0"
  if git -C "$work_dir" rev-parse --abbrev-ref --symbolic-full-name "@{u}" >/dev/null 2>&1; then
    if git_auth "$work_dir" push "$push_remote" "$runtime_branch:$runtime_branch"; then
      push_ok="1"
      echo "[vmess-domain-rotator] pushed to ${push_remote}/${runtime_branch}"
    fi
  else
    if git_auth "$work_dir" push -u "$push_remote" "$runtime_branch:$runtime_branch"; then
      push_ok="1"
      echo "[vmess-domain-rotator] pushed to ${push_remote}/${runtime_branch} (set upstream)"
    fi
  fi

  if [[ "$push_ok" != "1" ]]; then
    echo "[vmess-domain-rotator] git push failed"
    echo "[vmess-domain-rotator] hint: configure non-interactive auth (credential.helper store, SSH deploy key, or GIT_HTTP_USERNAME/GIT_HTTP_TOKEN)"
    if [[ "$push_required" == "1" ]]; then
      exit 1
    fi
  fi
fi

echo "[vmess-domain-rotator] committed output changes on ${runtime_branch}: selected value ${after} from ${RUNTIME_DIR}"
