#!/bin/bash

## Copyright (C) 2025 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

set -o errexit
set -o nounset
set -o errtrace
set -o pipefail
shopt -s inherit_errexit
shopt -s shift_verbose
export LC_ALL=C
## style-ok: no-tmp-hardcode -- /tmp appears only in usage() example paths.

# shellcheck source=../share/mediawiki-shell/common
source /usr/share/mediawiki-shell/common

log info "START"

usage() {
  printf '%s\n' "Usage: ${0##*/} [--dry-run] WIKI LIST_FILE [EXPIRY] [REASON]
Reads LIST_FILE (one page title per line, blank lines ignored) and sets
edit and move protection to sysop (admin) only on each page.
Options:
  --dry-run        Preview only; skip the actual protect on the server.
Defaults:
  EXPIRY=${default_protect_expiry}
  REASON=${default_protect_reason}
Example:
  ${0##*/} 'https://www.whonix.org/w' /tmp/pages.txt
  ${0##*/} 'https://www.whonix.org/w' /tmp/pages.txt 'infinite' 'lock down'" >&2
  exit 1
}

default_protect_expiry="infinite"
default_protect_reason="mediawiki-shell-bot-protect"

while true; do
  case "${1-}" in
    --dry-run)
      export DRY_RUN="true"
      shift
      ;;
    -h|--help)
      usage
      ;;
    --)
      shift
      break
      ;;
    -*)
      die 2 "Invalid option: '$1'"
      ;;
    *)
      break
      ;;
  esac
done

if [ -z "${2-}" ]; then
  usage
fi

WIKI_URL="$1"
list_file="$2"
protect_expiry="${3-"${default_protect_expiry}"}"
protect_reason="${4-"${default_protect_reason}"}"

check_vars_exist list_file

if [ -d "${list_file}" ]; then
  die 1 "list_file '${list_file}' is a folder!"
fi

if [ ! -r "${list_file}" ]; then
  die 2 "List file '${list_file}' does not exist or is not readable!"
fi

# shellcheck source=../share/mediawiki-shell/wiki-config
source /usr/share/mediawiki-shell/wiki-config

log info "WIKI_URL  : ${WIKI_URL}"
log info "WIKI_API  : ${WIKI_API}"
log info "list_file : ${list_file}"

## Defense-in-depth: check the whole list for malicious unicode up front.
unicode-show "${list_file}"

login_function() {
  log info "Logging in..."
  mw-login-test "${WIKI_URL}"
  log info "Login ok."
}

protect_page() {
  protect_page_exit_code=0
  mw-protect "${WIKI_URL}" "${page_to_protect}" "${protect_expiry}" "${protect_reason}" \
    || protect_page_exit_code="$?"
}

login_function

## Count non-blank lines so the progress display matches the pages processed.
counter_total="$(awk 'NF{counter++} END {print counter+0}' "${list_file}")"

counter_currently=0
error_counter=0
while IFS=$'\n' read -r item_from_list; do
  ## Skip blank or whitespace-only lines.
  if [[ "${item_from_list}" =~ ^[[:space:]]*$ ]]; then
    continue
  fi
  (( counter_currently++ )) || true
  ## Raw page name - no filesystem encoding. The API handles spaces/underscores
  ## and curl_run handles URL encoding.
  page_to_protect="${item_from_list}"
  log info "${counter_currently} / ${counter_total}"
  printf '%s\n' "mw-protect '${WIKI_URL}' '${page_to_protect}'"
  protect_page
  if [ "${protect_page_exit_code}" = "0" ]; then
    log info "Success at first attempt, ok."
    continue
  elif [ "${protect_page_exit_code}" = "254" ]; then
    log info "Got exit code 254. Login probably expired."
    login_function
    log info "Try again..."
    protect_page
  fi

  if [ "${protect_page_exit_code}" = "0" ]; then
    log info "Success after second attempt, ok."
  else
    (( error_counter++ )) || true
    log error "Failed to protect '${page_to_protect}'!"
  fi
done <"${list_file}"

if [ "${error_counter}" = "0" ]; then
  log info "Success."
else
  die 1 "${error_counter} error(s) detected."
fi
