#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<'EOF'
Usage:
  HYPERTWIST_REMOTE_WINDOWS_PASSWORD=... \
    scripts/run-hypertwist-remote-windows-file-pull.sh \
      --map "C:\HyperTwist_worktrees\phase10validate\docs\generated\higher_dimensional_training_maps\phase6c_dedicated_family_package_validation_report.json::docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_package_validation_report.json"

Options:
  --map <remote_windows_path>::<local_repo_path>
      Copy one remote Windows file back into the local repo. May be repeated.

  --dry-run
      Print the pull plan without transferring files.

Environment:
  HYPERTWIST_REMOTE_WINDOWS_PASSWORD   Required password for the reverse-SSH Windows user.
  HYPERTWIST_REMOTE_TUNNEL_PORT        Optional, defaults to 22022.
  HYPERTWIST_REMOTE_WINDOWS_USER       Optional, defaults to "anthracite ace".
  HYPERTWIST_REMOTE_TUNNEL_HOST        Optional, defaults to "localhost".
EOF
}

if ! command -v python3 >/dev/null 2>&1; then
  echo "python3 is required but was not found on PATH." >&2
  exit 1
fi

if ! command -v sha256sum >/dev/null 2>&1; then
  echo "sha256sum is required but was not found on PATH." >&2
  exit 1
fi

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
remote_ps_wrapper="${repo_root}/scripts/run-hypertwist-remote-windows-powershell.sh"

if [[ ! -x "$remote_ps_wrapper" ]]; then
  echo "Expected executable wrapper at $remote_ps_wrapper" >&2
  exit 1
fi

dry_run="false"
maps=()

while [[ $# -gt 0 ]]; do
  case "$1" in
    --map)
      maps+=("${2:-}")
      shift 2
      ;;
    --dry-run)
      dry_run="true"
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      usage >&2
      exit 1
      ;;
  esac
done

if [[ ${#maps[@]} -eq 0 ]]; then
  echo "Provide at least one --map." >&2
  exit 1
fi

ps_single_quote() {
  printf "'%s'" "${1//\'/\'\'}"
}

write_base64_to_file() {
  local destination_path="$1"

  python3 -c '
import base64
import pathlib
import sys

destination = pathlib.Path(sys.argv[1])
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_bytes(base64.b64decode(sys.stdin.buffer.read()))
' "$destination_path"
}

for mapping in "${maps[@]}"; do
  if [[ "$mapping" != *"::"* ]]; then
    echo "Map must use <remote_windows_path>::<local_repo_path>: $mapping" >&2
    exit 1
  fi

  remote_path="${mapping%%::*}"
  local_path="${mapping#*::}"

  if [[ -z "$remote_path" || -z "$local_path" ]]; then
    echo "Map must include both remote and local paths: $mapping" >&2
    exit 1
  fi

  if [[ "$local_path" = /* ]]; then
    local_destination="$local_path"
  else
    local_destination="${repo_root}/${local_path}"
  fi

  if [[ "$dry_run" == "true" ]]; then
    printf '%s -> %s\n' "$remote_path" "$local_destination"
    continue
  fi

  remote_payload="$(
    cat <<EOF
\$Path = $(ps_single_quote "$remote_path")
if (-not (Test-Path -LiteralPath \$Path)) {
  throw "Remote file was not found at '\$Path'."
}
\$Bytes = [System.IO.File]::ReadAllBytes(\$Path)
\$Hash = (Get-FileHash -LiteralPath \$Path -Algorithm SHA256).Hash.ToLowerInvariant()
Write-Output ('REMOTE_HASH=' + \$Hash)
Write-Output 'REMOTE_BASE64_BEGIN'
[Console]::Out.Write([Convert]::ToBase64String(\$Bytes))
Write-Output ''
Write-Output 'REMOTE_BASE64_END'
EOF
  )"

  remote_output="$("$remote_ps_wrapper" --command "$remote_payload" | tr -d '\r')"
  remote_hash="$(printf '%s\n' "$remote_output" | sed -n 's/^REMOTE_HASH=//p' | head -n 1)"

  if [[ -z "$remote_hash" ]]; then
    echo "Did not receive REMOTE_HASH for $remote_path" >&2
    exit 1
  fi

  base64_payload="$(
    printf '%s\n' "$remote_output" \
      | awk '/^REMOTE_BASE64_BEGIN$/{flag=1; next} /^REMOTE_BASE64_END$/{flag=0} flag' \
      | tr -d '\n'
  )"

  printf '%s' "$base64_payload" | write_base64_to_file "$local_destination"

  local_hash="$(sha256sum "$local_destination" | awk '{print tolower($1)}')"
  if [[ "$local_hash" != "$remote_hash" ]]; then
    echo "Hash mismatch for $remote_path" >&2
    echo "  remote: $remote_hash" >&2
    echo "  local : $local_hash" >&2
    exit 1
  fi

  printf 'Pulled %s -> %s (%s)\n' "$remote_path" "$local_destination" "$local_hash"
done
