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

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
PROFILE="${PROFILE:-release}"
OUT_DIR="${OUT_DIR:-$REPO_ROOT/target/portable-soak}"
PACKAGE_PREFIX="${PACKAGE_PREFIX:-portable-soak}"
PACKAGE_DIR_NAME="${PACKAGE_DIR_NAME:-portable-soak}"

usage() {
  cat <<'USAGE'
Usage:
  scripts/soak/build_portable_soak_package.sh [--out-dir <path>] [--profile <profile>]

Requires release binaries to already exist. Build them first, for example:
  cargo build --release --bin rpki --bin rpki_daemon --bin db_stats --bin rpki_artifact_metrics --bin rpki_query_service --bin rpki_query_indexer --bin verification_ccr_compare
USAGE
}

die() {
  echo "error: $*" >&2
  exit 2
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --out-dir)
      shift
      OUT_DIR="${1:?--out-dir requires a value}"
      ;;
    --profile)
      shift
      PROFILE="${1:?--profile requires a value}"
      ;;
    --help|-h)
      usage
      exit 0
      ;;
    *)
      die "unknown argument: $1"
      ;;
  esac
  shift
done

command -v python3 >/dev/null 2>&1 || die "python3 is required"
command -v tar >/dev/null 2>&1 || die "tar is required"

if [[ "$PROFILE" == "release" ]]; then
  TARGET_BIN_DIR="$REPO_ROOT/target/release"
else
  TARGET_BIN_DIR="$REPO_ROOT/target/$PROFILE"
fi

REQUIRED_BINS=(rpki rpki_daemon db_stats rpki_artifact_metrics rpki_query_service rpki_query_indexer verification_ccr_compare)
OPTIONAL_BINS=(
  ccr_dump
  ccr_state_compare
  ccr_to_compare_views
  ccr_to_routinator_csv
  ccr_verify
  cir_drop_report
  cir_dump_reject_list
  cir_extract_inputs
  cir_materialize
  cir_probe_rpki_client_cache
  cir_state_compare
  rrdp_state_dump
)

for binary_name in "${REQUIRED_BINS[@]}"; do
  [[ -x "$TARGET_BIN_DIR/$binary_name" ]] || die "missing required binary: $TARGET_BIN_DIR/$binary_name"
done

mkdir -p "$OUT_DIR"
GIT_SHA="$(git -C "$REPO_ROOT" rev-parse --short HEAD 2>/dev/null || printf 'unknown')"
TIMESTAMP="$(date -u +%Y%m%dT%H%M%SZ)"
PACKAGE_NAME="${PACKAGE_PREFIX}-${TIMESTAMP}-${GIT_SHA}"
BUILD_ROOT="$REPO_ROOT/target/portable-soak-build"
STAGE_DIR="$BUILD_ROOT/$PACKAGE_DIR_NAME"
ARCHIVE_PATH="$OUT_DIR/$PACKAGE_NAME.tar.gz"

rm -rf "$STAGE_DIR" "$ARCHIVE_PATH"
mkdir -p "$STAGE_DIR/bin" "$STAGE_DIR/fixtures" "$STAGE_DIR/scripts" "$STAGE_DIR/scripts/soak" "$STAGE_DIR/scripts/verification" \
  "$STAGE_DIR/runs" "$STAGE_DIR/state" "$STAGE_DIR/logs" "$STAGE_DIR/tmp"

install -m 0755 "$SCRIPT_DIR/run_soak.sh" "$STAGE_DIR/run_soak.sh"
install -m 0755 "$SCRIPT_DIR/run_24h_soak_with_metrics.sh" "$STAGE_DIR/run_24h_soak_with_metrics.sh"
install -m 0755 "$SCRIPT_DIR/run_cache_ablation_experiment.sh" "$STAGE_DIR/scripts/soak/run_cache_ablation_experiment.sh"
install -m 0755 "$SCRIPT_DIR/fixed_phase_loop.sh" "$STAGE_DIR/scripts/soak/fixed_phase_loop.sh"
install -m 0755 "$SCRIPT_DIR/hourly_soak_report.py" "$STAGE_DIR/scripts/soak/hourly_soak_report.py"
install -m 0755 "$SCRIPT_DIR/publish_remote231.sh" "$STAGE_DIR/scripts/soak/publish_remote231.sh"
install -m 0755 "$SCRIPT_DIR/publish_remote231_full.sh" "$STAGE_DIR/scripts/soak/publish_remote231_full.sh"
install -m 0755 "$REPO_ROOT/scripts/verification/run_verification_only.sh" "$STAGE_DIR/scripts/verification/run_verification_only.sh"
install -m 0644 "$REPO_ROOT/scripts/verification/README.md" "$STAGE_DIR/scripts/verification/README.md"
install -m 0644 "$SCRIPT_DIR/portable-soak.env.example" "$STAGE_DIR/.env"
install -m 0644 "$SCRIPT_DIR/portable-soak.env.example" "$STAGE_DIR/portable-soak.env.example"

COPIED_BIN_LIST="$STAGE_DIR/copied-binaries.txt"
MISSING_OPTIONAL_BIN_LIST="$STAGE_DIR/missing-optional-binaries.txt"
: > "$COPIED_BIN_LIST"
: > "$MISSING_OPTIONAL_BIN_LIST"

for binary_name in "${REQUIRED_BINS[@]}"; do
  install -m 0755 "$TARGET_BIN_DIR/$binary_name" "$STAGE_DIR/bin/$binary_name"
  printf '%s\n' "$binary_name" >> "$COPIED_BIN_LIST"
done

for binary_name in "${OPTIONAL_BINS[@]}"; do
  if [[ -x "$TARGET_BIN_DIR/$binary_name" ]]; then
    install -m 0755 "$TARGET_BIN_DIR/$binary_name" "$STAGE_DIR/bin/$binary_name"
    printf '%s\n' "$binary_name" >> "$COPIED_BIN_LIST"
  else
    printf '%s\n' "$binary_name" >> "$MISSING_OPTIONAL_BIN_LIST"
  fi
done

cp -a "$REPO_ROOT/tests/fixtures/tal" "$STAGE_DIR/fixtures/"
cp -a "$REPO_ROOT/tests/fixtures/ta" "$STAGE_DIR/fixtures/"
cp -a "$REPO_ROOT/scripts/periodic" "$STAGE_DIR/scripts/"
cp -a "$REPO_ROOT/scripts/cir" "$STAGE_DIR/scripts/"
cp -a "$REPO_ROOT/scripts/inter_rp" "$STAGE_DIR/scripts/"
cp -a "$REPO_ROOT/monitor" "$STAGE_DIR/"
find "$STAGE_DIR/scripts" -type d -name __pycache__ -prune -exec rm -rf {} +

(cd "$STAGE_DIR" && find fixtures -type f | sort > fixtures.txt)
(cd "$STAGE_DIR" && find scripts -type f | sort > scripts.txt)

GIT_DIRTY="false"
if [[ -n "$(git -C "$REPO_ROOT" status --short 2>/dev/null || true)" ]]; then
  GIT_DIRTY="true"
fi
GIT_STATUS="$(git -C "$REPO_ROOT" status --short 2>/dev/null || true)"

python3 - "$STAGE_DIR/manifest.json" "$PACKAGE_NAME" "$TIMESTAMP" "$REPO_ROOT" "$GIT_SHA" \
  "$GIT_DIRTY" "$PROFILE" "$TARGET_BIN_DIR" "$GIT_STATUS" <<'PY'
import json
import pathlib
import sys

(
    manifest_path,
    package_name,
    created_at,
    repo_root,
    git_sha,
    git_dirty,
    profile,
    target_bin_dir,
    git_status,
) = sys.argv[1:]
stage_dir = pathlib.Path(manifest_path).parent

def read_lines(name):
    path = stage_dir / name
    if not path.exists():
        return []
    return [line for line in path.read_text(encoding="utf-8").splitlines() if line]

manifest = {
    "packageName": package_name,
    "createdAtUtc": created_at,
    "sourceRepo": repo_root,
    "gitCommit": git_sha,
    "gitDirty": git_dirty == "true",
    "gitStatusShort": git_status.splitlines(),
    "rustProfile": profile,
    "targetBinDir": target_bin_dir,
    "copiedBinaries": read_lines("copied-binaries.txt"),
    "missingOptionalBinaries": read_lines("missing-optional-binaries.txt"),
    "fixtures": read_lines("fixtures.txt"),
    "scripts": read_lines("scripts.txt"),
}
pathlib.Path(manifest_path).write_text(
    json.dumps(manifest, indent=2, sort_keys=True) + "\n",
    encoding="utf-8",
)
PY

tar -C "$BUILD_ROOT" -czf "$ARCHIVE_PATH" "$PACKAGE_DIR_NAME"
printf '%s\n' "$ARCHIVE_PATH"
