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

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