#!/bin/bash

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

## style-ok: no-strict
##
## UTF-8 locale default (no block "export LC_ALL=C"): these tools process
## Unicode wiki content, so the C byte-locale would break nocasematch,
## "[:space:]" trimming and "grep -i" on non-ASCII. Byte-exact operations
## carry an explicit "LC_ALL=C" prefix instead.
set -o errexit
set -o nounset
set -o errtrace
set -o pipefail
shopt -s inherit_errexit
shopt -s shift_verbose

# shellcheck source=../share/mediawiki-shell/common
source /usr/share/mediawiki-shell/common
# shellcheck source=../../../helper-scripts/usr/libexec/helper-scripts/strings.bsh
source "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/strings.bsh

log info "START"

# shellcheck disable=SC2317
exit_handler() {
  [[ -v retry_counter ]] || retry_counter=0
  is_whole_number "${retry_counter}" || retry_counter=0
  if (( retry_counter > 1 )); then
    log info "success after attempt ${retry_counter}"
  fi
}

trap exit_handler EXIT

usage() {
  printf '%s\n' "Usage: ${0##*/} WIKI PAGE OUTPUT
Example:
  ${0##*/} 'https://www.kicksecure.com/w' About /tmp/a" >&2
  exit 1
}

if [[ -z "${3-}" || "${1-}" =~ (-h|--help) ]]; then
  usage
fi

wiki_url="$1"
page="$2"
output="$3"

check_vars_exist page output

output_dir="$(dirname -- "${output}")"

temp_page_normalized="$(set_backup_filename_item "$(set_backup_page_item "${page}")")"
temp_output_file="${TMPFOLDER}/${temp_page_normalized}"
assert_path_within_dir "${TMPFOLDER}" "${temp_output_file}"

log info "wiki_url        : ${wiki_url}"
log info "page            : ${page}"
log info "temp_output_file: ${temp_output_file}"
log info "output          : ${output}"

mkdir -p -- "${output_dir}"
if ! test -d "${output_dir}"; then
  die 1 "output_dir '${output_dir}' does not exist! Run?: mkdir --parents -- '${output_dir}'"
fi

if ! test -w "${output_dir}"; then
  die 1 "output_dir '${output_dir}' unwritable! Run?: chown --recursive -- '${USER}:${USER}' '${output_dir}'"
fi

for retry_counter in {1..5}; do
  if ! mw-fetch "${wiki_url}" "${page}" "${temp_output_file}"; then
    log warn "fetch attempt ${retry_counter} failed for page '${page}'; retrying..."
    sleep 5
    continue
  fi

  ## time-of-check to time-of-use TOCTOU
  ## Check for pending edits only after page was fetched.
  ## Checking for pending edits before fetching page would leave room for
  ## making a pending edit after the page has been fetched.
  ## This ensures that the fetched edit was not pending, i.e. confirmed.
  ##
  ## mw-page-pending-check exits 10 specifically for "page has pending edits".
  ## Any other non-zero is a CHECK FAILURE (e.g. network error) and must NOT
  ## be silently treated as "pending" -- doing so would drop the page from the
  ## backup on a transient failure. Distinguish the two by exit code, mirroring
  ## mw-multi-wiki's handling.
  pending_exit_code=0
  mw-page-pending-check "${wiki_url}" "${page}" || pending_exit_code="$?"
  if [ "${pending_exit_code}" = "10" ]; then
    log warn "SKIP: page '${page}' has PENDING edits."
    exit 0
  fi
  if [ "${pending_exit_code}" != "0" ]; then
    log warn "pending-check failed (rc=${pending_exit_code}) for page '${page}'; retrying..."
    sleep 5
    continue
  fi

  mv -- "${temp_output_file}" "${output}"
  log info "SUCCESS: page '${page}' | output: '${output}'"

  exit 0
done

## Failed even after retry attempts. Therefore exit non-zero.
exit 1
