#!/usr/bin/env bash
# Archive extraction only. Requires matching, locally supplied decoder files.
set -euo pipefail
usage() {
  printf '%s\n' 'Usage: bash extract.sh [--no-inhibit] --prefix DIR --tools DIR --work NEW_DIR ARCHIVE...' \
    'Initialize a dedicated Wine prefix and prepare arc.ini / CLS.ini first.' \
    'WINE, WINEPATH and CC may select matching Wine tools and the i686 MinGW compiler.'
}
die() { printf 'Error: %s\n' "$*" >&2; exit 2; }
args=("$@")
prefix= tools= work= inhibit=1
while (($#)); do
  case "$1" in
    --help|-h) usage; exit 0 ;;
    --no-inhibit) inhibit=0; shift ;;
    --prefix|--tools|--work)
      (($# >= 2)) || die "Missing value for $1"
      case "$1" in
        --prefix) prefix=$2 ;; --tools) tools=$2 ;; --work) work=$2 ;;
      esac
      shift 2 ;;
    --) shift; break ;;
    --*) die "Unknown option: $1" ;;
    *) break ;;
  esac
done
[[ -n "$prefix" && -n "$tools" && -n "$work" && $# -gt 0 ]] || { usage >&2; exit 2; }
WINE=${WINE:-wine}
WINEPATH=${WINEPATH:-winepath}
CC=${CC:-i686-w64-mingw32-gcc}
for dependency in "$WINE" "$WINEPATH" "$CC" realpath flock; do
  command -v "$dependency" >/dev/null || die "Missing dependency: $dependency"
done
prefix=$(realpath -e -- "$prefix")
tools=$(realpath -e -- "$tools")
work=$(realpath -m -- "$work")
[[ -f "$prefix/system.reg" ]] || die 'Initialize the dedicated Wine prefix first.'
[[ ! -e "$work" && ! -L "$work" ]] || die 'Work directory must not already exist; partial outputs are not resumable.'
for file in unarc.dll arc.ini CLS.ini CLS-srep.dll; do
  [[ -f "$tools/$file" ]] || die "Missing decoder/configuration: $file"
done
declare -a archives=() names=()
declare -A used=()
for archive in "$@"; do
  archive=$(realpath -e -- "$archive")
  [[ -f "$archive" ]] || die "Not a regular archive: $archive"
  name=$(basename -- "$archive")
  [[ "$name" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]*$ ]] || die 'Use archive filenames containing only letters, digits, dots, dashes and underscores.'
  [[ ! ${used[$name]+yes} ]] || die "Duplicate archive filename: $name"
  used[$name]=1
  archives+=("$archive"); names+=("$name")
done
script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)
if ((inhibit)); then
  command -v systemd-inhibit >/dev/null || die 'systemd-inhibit unavailable; use --no-inhibit and manage sleep yourself.'
  exec systemd-inhibit --what=sleep:idle --mode=block --who='Archive extraction' \
    --why='Release sleep inhibition when extraction exits' \
    bash "$script_dir/extract.sh" --no-inhibit "${args[@]}"
fi
export WINEPREFIX="$prefix" WINEDEBUG="${WINEDEBUG:--all}"
# Cooperating invocations cannot use the shared Init_MapFile_ concurrently.
exec 9>"$prefix/.unarc-extract.lock"
flock -n 9 || die 'Another extractor is using this prefix.'
mkdir -p -- "$(dirname -- "$work")"
mkdir -- "$work"
mkdir -- "$work/temp" "$work/archives" "$work/logs"
trap 'printf "Stopped: inspect %s/logs; keep partial outputs separate from retries.\n" "$work" >&2' ERR
"$CC" -O2 -Wall -Wextra -mwindows -o "$work/unarc-extract.exe" "$script_dir/unarc-extract.c"
winpath() { "$WINEPATH" -w "$1" | tr -d '\r'; }
dll_win=$(winpath "$tools/unarc.dll")
temp_win=$(winpath "$work/temp")
for index in "${!archives[@]}"; do
  name=${names[$index]}
  output="$work/archives/$name"
  mkdir -- "$output"
  printf 'Extracting %s; log: %s/logs/%s.log\n' "$name" "$work" "$name"
  archive_win=$(winpath "${archives[$index]}")
  output_win=$(winpath "$output")
  "$WINE" "$work/unarc-extract.exe" "$dll_win" "$archive_win" "$output_win" "$temp_win" \
    >"$work/logs/$name.log" 2>&1
  touch "$work/logs/$name.complete"
done
printf 'Archives extracted. Reconstruction, final checksums and game launch are separate steps.\n'
