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

# shellcheck disable=SC1091
{
  source /usr/libexec/helper-scripts/log_run_die.sh
  source /usr/libexec/helper-scripts/has.sh
  source /usr/libexec/helper-scripts/not_as_root.sh
  source /usr/libexec/helper-scripts/strings.bsh
}

collect_reqs() {
  local collect cmd
  collect=""
  for cmd in "${@}"; do
    if ! has "$cmd"; then
      collect="${collect:+$collect }$cmd"
    fi
  done
  if test ${#collect} -gt 0; then
    die 1 "${FUNCNAME[0]}: command(s) unavailable: '$collect'" >&2
  fi
}
collect_reqs retry curl jq safe-rm str_replace stprint

check_vars_exist() {
  local var_name
  for var_name in "$@"; do
    if [ -z "${!var_name+x}" ]; then
      die 1 "Variable '$var_name' is not set or is empty."
      exit 1
    fi
  done
}

missing_variable() {
  log error "MISSING VARIABLE: $*"
  exit 1
}

error_output() {
  stecho "error_msg: '${1:-none}'
WIKI_INDEX: '${WIKI_INDEX-unset}'
TITLE: '${TITLE-unset}'
TMPFOLDER: '${TMPFOLDER-unset}'
counter_chunk: '${counter_chunk-unset}'
counter_currently: '${counter_currently-unset}'
###" >&2
}

error_handler() {
  local last_exit_code="$?"
  log error "
BASH_COMMAND: '$BASH_COMMAND'
failed with exit code '$last_exit_code'." >&2
  error_output "called-by-error_handler"
  exit 1
}

trap error_handler ERR

exit_handler() {
  trap - INT HUP ABRT QUIT EXIT
  local exit_code="${1:-}"
  if [ "$exit_code" = "0" ]; then
    log info "END: with OK exit code: '$exit_code'"
  else
    log error "END: with ERROR exit code: '$exit_code'"
  fi
  exit "$exit_code"
}

set_curl_binary_default() {
  if has scurl; then
    curl=scurl
  else
    curl=curl
  fi
}

set_backup_page_item() {
  local backup_page_item search replace

  backup_page_item="$(stecho "$1")"
  if [ -z "$backup_page_item" ]; then
    die 1 "${FUNCNAME[0]}: 1 is empty!"
  fi

  ## Not longer needed since no longer using 'jq' with '@sh'.
  ## remove last letter ("'")
  #backup_page_item="${backup_page_item::-1}"
  ## remove first letter ("'")
  #backup_page_item="${backup_page_item:1}"

  search="&"
  replace="#ampersand#"
  backup_page_item=$(stecho "$backup_page_item" | str_replace "$search" "$replace")

  ## Same format as git-mediawiki: replace ' ' with '_'.
  ## Replace spaces with underscore.
  search=" "
  replace="_"
  backup_page_item=$(stecho "$backup_page_item" | str_replace "$search" "$replace")

  search="/"
  replace="_"
  backup_page_item="$(stecho "$backup_page_item" | str_replace "$search" "$replace")"

  ## Colon is safe in file names.
#   search=":"
#   replace="#colon#"
#   backup_page_item="$(stecho "$backup_page_item" | str_replace "$search" "$replace")"

  ## A single dot is safe in file names. Double dot is not
#   search="."
#   replace="_dot_"
#   backup_page_item="$(stecho "$backup_page_item" | str_replace "$search" "$replace")"

  check_is_not_empty_and_only_one_line backup_page_item
  if ! validate_safe_filename backup_page_item; then
    log error "${FUNCNAME[0]}: validate_safe_filename backup_page_item failed. Checking $backup_page_item for unicode using unicode-show for debugging purposes."
    printf '%s\n' "$backup_page_item" | unicode-show
    return 1
  fi

  ## Superfluous due to 'stecho'.
  #printf '%s\n' "$backup_page_item" | unicode-show

  stecho "$backup_page_item"
}

set_backup_filename_item() {
  local backup_filename_item search replace

  backup_filename_item="$1"

  if [ -z "$backup_filename_item" ]; then
    die 1 "${FUNCNAME[0]}: 1 is empty!"
  fi

  ## Same format as git-mediawiki: replace '/' with '%2F'.
  ## Also the file system does not accept files containing '/'.
  search="/"
  replace="%2F"
  backup_filename_item=$(stecho "$backup_filename_item" | str_replace "$search" "$replace")

  ## Same format as git-mediawiki: add '.mw' file extension.
  backup_filename_item="${backup_filename_item}.mw"

  stecho "$backup_filename_item"
}

curl_get_output_parameter() {
  local loop_counter loop_max
  loop_counter=0
  loop_max=50

  output_file=""

  while true; do
    (( loop_counter++ )) || true
    if (( loop_counter >= loop_max )); then
      die 1 "${FUNCNAME[0]}: loop_max reached!"
    fi

    case "${1-}" in
      "")
        break
        ;;
      --)
        shift || true
        break
        ;;
      --output)
        if [ -z "${2-}" ]; then
          die 1 "${FUNCNAME[0]}: --output given but missing value"
        fi
        output_file="$2"
        shift 2 || true
        ;;
      --output=*)
        output_file="${1#--output=}"
        shift || true
        ;;
      -o)
        if [ -z "${2-}" ]; then
          die 1 "${FUNCNAME[0]}: -o given but missing value"
        fi
        output_file="$2"
        shift 2 || true
        ;;
      -o*)
        ## supports: -oFILE
        output_file="${1#-o}"
        shift || true
        ;;
      *)
        shift || true
        ;;
    esac
  done
}

curl_run() {
  local curl_run_no_encode args url curl_exit_code encoded_url output_file
  local created_temp_output output_is_stdout

  curl_get_output_parameter "$@"

  created_temp_output="false"
  output_is_stdout="false"

  ## If caller didn't provide an output file, capture to a temp file
  if [ -z "${output_file-}" ]; then
    created_temp_output="true"
    output_file="$(mktemp -t curl_run.XXXXXXXX)" || die 1 "${FUNCNAME[0]}: mktemp failed"
  else
    ## If caller explicitly targets stdout, don't try to rm/touch/stcat it
    case "$output_file" in
      "-"|/dev/stdout|/dev/fd/1|/proc/self/fd/1)
        output_is_stdout="true"
        ;;
    esac
  fi

  if [ "$output_is_stdout" != "true" ]; then
    safe-rm -f -- "$output_file"
    touch -- "$output_file"
  fi

  args=( "$@" )
  url="${args[$((${#args[@]} - 1))]}"

  [[ -v curl_run_no_encode ]] || curl_run_no_encode=""

  if [ "$curl_run_no_encode" = "true" ]; then
    encoded_url="$url"
  else
    encoded_url="$(mw-urlencode "$url")"
  fi

  curl_exit_code=0

  ## Rebuild args: exclude last param (url), then append encoded url.
  ## If we created a temp output, inject --output <temp> so we can capture it.
  if [ "$created_temp_output" = "true" ]; then
    args=("${@:1:$#-1}" "--output" "$output_file" "$encoded_url")
  else
    args=("${@:1:$#-1}" "$encoded_url")
  fi

  log_run debug "$curl" "${args[@]}" || curl_exit_code="$?"

  if [ "$curl_exit_code" != "0" ]; then
    log error "curl failed with exit code '$curl_exit_code': url: '$encoded_url' output_file: '${output_file-}'"
    if [ "$output_is_stdout" != "true" ] && [ -n "${output_file-}" ]; then
      stcat "$output_file" >&2 || true
    fi
    die 1 'curl failure, cannot continue.'
  fi

  # If caller didn't specify --output, behave like curl and print to stdout
  if [ "$created_temp_output" = "true" ]; then
    cat -- "$output_file"
  fi
}

trap 'exit_handler $?' INT HUP ABRT QUIT EXIT

[[ -v TMPFOLDER ]] || TMPFOLDER="$HOME/mediawiki-shell-temp"
[[ -v USERDOMAIN ]] || USERDOMAIN=""
[[ -v cookie_jar ]] || cookie_jar="$TMPFOLDER/wiki-cookiejar"
[[ -v curl ]] || set_curl_binary_default
[[ -v curl_opts ]] || curl_opts=(
  "--fail"
  "--no-progress-meter"
  "--show-error"
  "--retry-connrefused"
  "--retry" "10"
  "--retry-delay" "5"
  "--cookie" "nocache=true"
  "--user-agent" "mediawiki-shell"
)

mkdir --parents -- "$TMPFOLDER"
chmod og-rw -- "$TMPFOLDER"
