#!/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

usage() {
  printf '%s\n' "Usage: ${0##*/} [OPTIONS] WIKI SCRIPT OUTPUT_DIR
Options:
  --continue-from=N|TITLE    Continue from page index (N) or title (case-insensitive)
  --article-sanity-test=X    Guarantee that string is present on the fetched pages
  --namespace-default-list=N Page collection per namespace
  --namespace-extra-list=N   Extra page collection per namespace
  --keep-going               Continue past per-item failures (record them, exit non-zero)
  --retry                    Skip items already recorded done; retry the rest
  --reset                    Clear any prior state before starting
  --state-file=PATH          Override the state-file location (default: under TMPFOLDER)
Note:
  ARGS are passed to the SCRIPT.
Example:
  ${0##*/} 'https://www.kicksecure.com/w' 'mw-patch-modify-wiki-page' '/tmp/user/1000/mw'" >&2
  exit 1
}

# shellcheck source=../../../helper-scripts/usr/libexec/helper-scripts/parse_opt.sh
source "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/parse_opt.sh

continue_from=""
article_sanity_test=""
namespace_default_list=""
namespace_extra_list=""

# shellcheck disable=SC2034  # KEEP_GOING/RETRY/STATE_RESET/STATE_FILE set here, read by common's state_* helpers
while true; do
  [[ "${1-}" =~ ^- ]] || break
  begin_optparse "${1:-}" "${2:-}" || break
  true "${opt-}" "${arg-}" "${opt_orig-}"
  case "${opt}" in
    continue-from)
      get_arg
      continue_from="${arg}"
      ;;
    article-sanity-test)
      get_arg
      article_sanity_test="${arg}"
      ;;
    namespace-default-list)
      get_arg
      namespace_default_list="${arg}"
      ;;
    namespace-extra-list)
      get_arg
      namespace_extra_list="${arg}"
      ;;
    keep-going)
      KEEP_GOING="true"
      ;;
    retry)
      RETRY="true"
      ;;
    reset)
      STATE_RESET="true"
      ;;
    state-file)
      get_arg
      STATE_FILE="${arg}"
      ;;
    h|help)
      usage
      ;;
    --|"")
      break
      ;;
    *)
      die 2 "Invalid option: '${opt_orig}'"
      ;;
  esac
  shift "${shift_n:-1}"
done

if [[ -z "${3-}" ]]; then
  usage
fi
WIKI_URL="$1"
wiki_script="$2"
output_dir="$3"

check_vars_exist wiki_script output_dir

case "${wiki_script}" in
  "mw-wiki-fetch-backup")
    true
    ;;
  "mw-patch-modify-wiki-page")
    true
    ;;
  *)
    log error "Unknown fetcher '${wiki_script}'!"
    exit 1
    ;;
esac

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

log info "TMPFOLDER    : ${TMPFOLDER}"
log info "WIKI_URL     : ${WIKI_URL}"
log info "continue_from: ${continue_from-}"

state_setup "${WIKI_URL}"

## Not required for public wiki.
#mw-login-test "$WIKI_URL"

allpages_file="${TMPFOLDER}/allpages.txt"

safe-rm -f -- "${allpages_file}"

mw_all_pages_opts=()
if [ -n "${article_sanity_test}" ]; then
  mw_all_pages_opts+=("--article-sanity-test=${article_sanity_test}")
fi
if [ -n "${namespace_default_list}" ]; then
  mw_all_pages_opts+=("--namespace-default-list=${namespace_default_list}")
fi
if [ -n "${namespace_extra_list}" ]; then
  mw_all_pages_opts+=("--namespace-extra-list=${namespace_extra_list}")
fi

mw-all-pages "${mw_all_pages_opts[@]}" "${WIKI_URL}" allpages "${allpages_file}"

test -r "${allpages_file}"
unicode-show "${allpages_file}"

counter_total="$(awk 'END {print NR}' "${allpages_file}")"

# shellcheck disable=SC2034  # mutated by should_start_processing via nameref
continue_state="no"
counter_currently=0
counter_chunk=0
chunk_max_size=10

while IFS=$'\n' read -r item_from_all_pages; do
  (( counter_currently++ )) || true
  backup_page_item="$(set_backup_page_item "${item_from_all_pages}")"
  backup_filename_item="$(set_backup_filename_item "${backup_page_item}")"

  (( counter_chunk++ )) || true

  if ! should_start_processing "${counter_currently}" "${item_from_all_pages}" "${continue_from}" continue_state; then
    log info "skip: ${counter_currently} / ${counter_total} | counter_chunk: ${counter_chunk} | ${item_from_all_pages} | ${backup_filename_item}"
    continue
  fi

  if state_should_skip "${item_from_all_pages}"; then
    log info "retry-skip: ${counter_currently} / ${counter_total} | already done | ${item_from_all_pages}"
    continue
  fi
  log info "act: ${counter_currently} / ${counter_total} | counter_chunk: ${counter_chunk} | ${item_from_all_pages} | ${backup_filename_item}"

  assert_path_within_dir "${output_dir}" "${output_dir}/${backup_filename_item}"

  if [ "${item_from_all_pages}" = "Changelog" ]; then
    continue
  fi

  TMPFOLDER_SEPARATE="${TMPFOLDER}/separate/${counter_currently}"
  mkdir --parents -- "${TMPFOLDER_SEPARATE}"

  item_rc=0
  log_run \
    info \
    env \
    counter_currently="${counter_currently}" \
    counter_chunk="${counter_chunk}" \
    TMPFOLDER="${TMPFOLDER_SEPARATE}" \
    mw-retry-wrapper "${wiki_script}" "${WIKI_URL}" "${item_from_all_pages}" "${output_dir}/${backup_filename_item}" \
    || item_rc="$?"

  if [ "${item_rc}" = "0" ]; then
    state_record_done "${item_from_all_pages}"
  else
    state_handle_failure "${item_from_all_pages}" "${wiki_script} rc=${item_rc}"
  fi

  if [ "${counter_chunk}" -ge "${chunk_max_size}" ] || [ "${counter_currently}" -ge "${counter_total}" ]; then
    counter_chunk=0
  fi

done <"${allpages_file}"

state_finish
if [ "${state_fail_count}" -gt 0 ]; then
  exit 2
fi
