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

usage() {
  cat <<'EOF'
Usage:
  ./scripts/cir/run_cir_record_sequence_remote.sh \
    --rir <name> \
    --remote-root <path> \
    [--ssh-target <user@host>] \
    [--out-subdir <path>] \
    [--delta-count <n>] \
    [--sleep-secs <n>] \
    [--full-repo] \
    [--max-depth <n>] \
    [--max-instances <n>]
EOF
}

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
SSH_TARGET="${SSH_TARGET:-root@47.77.183.68}"
RIR=""
REMOTE_ROOT=""
OUT_SUBDIR=""
DELTA_COUNT=2
SLEEP_SECS=30
FULL_REPO=0
MAX_DEPTH=0
MAX_INSTANCES=1

while [[ $# -gt 0 ]]; do
  case "$1" in
    --rir) RIR="$2"; shift 2 ;;
    --remote-root) REMOTE_ROOT="$2"; shift 2 ;;
    --ssh-target) SSH_TARGET="$2"; shift 2 ;;
    --out-subdir) OUT_SUBDIR="$2"; shift 2 ;;
    --delta-count) DELTA_COUNT="$2"; shift 2 ;;
    --sleep-secs) SLEEP_SECS="$2"; shift 2 ;;
    --full-repo) FULL_REPO=1; shift 1 ;;
    --max-depth) MAX_DEPTH="$2"; shift 2 ;;
    --max-instances) MAX_INSTANCES="$2"; shift 2 ;;
    -h|--help) usage; exit 0 ;;
    *) echo "unknown argument: $1" >&2; usage; exit 2 ;;
  esac
done

[[ -n "$RIR" && -n "$REMOTE_ROOT" ]] || { usage >&2; exit 2; }

case "$RIR" in
  afrinic) TAL_REL="tests/fixtures/tal/afrinic.tal"; TA_REL="tests/fixtures/ta/afrinic-ta.cer" ;;
  apnic) TAL_REL="tests/fixtures/tal/apnic-rfc7730-https.tal"; TA_REL="tests/fixtures/ta/apnic-ta.cer" ;;
  arin) TAL_REL="tests/fixtures/tal/arin.tal"; TA_REL="tests/fixtures/ta/arin-ta.cer" ;;
  lacnic) TAL_REL="tests/fixtures/tal/lacnic.tal"; TA_REL="tests/fixtures/ta/lacnic-ta.cer" ;;
  ripe) TAL_REL="tests/fixtures/tal/ripe-ncc.tal"; TA_REL="tests/fixtures/ta/ripe-ncc-ta.cer" ;;
  *) echo "unsupported rir: $RIR" >&2; exit 2 ;;
esac

rsync -a --delete \
  --exclude target \
  --exclude .git \
  "$ROOT_DIR/" "$SSH_TARGET:$REMOTE_ROOT/"
ssh "$SSH_TARGET" "mkdir -p '$REMOTE_ROOT/target/release'"
rsync -a "$ROOT_DIR/target/release/rpki" "$SSH_TARGET:$REMOTE_ROOT/target/release/"

ssh "$SSH_TARGET" \
  RIR="$RIR" \
  REMOTE_ROOT="$REMOTE_ROOT" \
  OUT_SUBDIR="$OUT_SUBDIR" \
  DELTA_COUNT="$DELTA_COUNT" \
  SLEEP_SECS="$SLEEP_SECS" \
  FULL_REPO="$FULL_REPO" \
  MAX_DEPTH="$MAX_DEPTH" \
  MAX_INSTANCES="$MAX_INSTANCES" \
  TAL_REL="$TAL_REL" \
  TA_REL="$TA_REL" \
  'bash -s' <<'EOS'
set -euo pipefail

cd "$REMOTE_ROOT"

if [[ -n "${OUT_SUBDIR}" ]]; then
  OUT="${OUT_SUBDIR}"
else
  OUT="target/replay/cir_sequence_remote_${RIR}_$(date -u +%Y%m%dT%H%M%SZ)"
fi

mkdir -p "$OUT"
DB="$OUT/work-db"
RAW_STORE_DB="$OUT/raw-store.db"
REPO_BYTES_DB="$OUT/repo-bytes.db"
ROWS="$OUT/.sequence_rows.tsv"
: > "$ROWS"

write_step_timing() {
  local path="$1"
  local start_ms="$2"
  local end_ms="$3"
  local started_at="$4"
  local finished_at="$5"
  python3 - <<'PY' "$path" "$start_ms" "$end_ms" "$started_at" "$finished_at"
import json, sys
path, start_ms, end_ms, started_at, finished_at = sys.argv[1:]
start_ms = int(start_ms)
end_ms = int(end_ms)
with open(path, "w", encoding="utf-8") as fh:
    json.dump(
        {
            "durationMs": end_ms - start_ms,
            "startedAt": started_at,
            "finishedAt": finished_at,
        },
        fh,
        indent=2,
    )
PY
}

run_step() {
  local step_id="$1"
  local kind="$2"
  local previous_step_id="$3"
  shift 3

  local started_at_iso started_at_ms finished_at_iso finished_at_ms prefix
  started_at_iso="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
  started_at_ms="$(python3 - <<'PY'
import time
print(int(time.time() * 1000))
PY
)"
  prefix="${started_at_iso}-test"

  local cir_out="$OUT/${prefix}.cir"
  local ccr_out="$OUT/${prefix}.ccr"
  local report_out="$OUT/${prefix}.report.json"
  local timing_out="$OUT/${prefix}.timing.json"
  local stdout_out="$OUT/${prefix}.stdout.log"
  local stderr_out="$OUT/${prefix}.stderr.log"

  local -a cmd=(
    target/release/rpki
    --db "$DB"
    --raw-store-db "$RAW_STORE_DB"
    --repo-bytes-db "$REPO_BYTES_DB"
    --tal-path "$TAL_REL"
    --ta-path "$TA_REL"
    --ccr-out "$ccr_out"
    --report-json "$report_out"
    --cir-enable
    --cir-out "$cir_out"
    --cir-tal-uri "https://example.test/${RIR}.tal"
  )
  if [[ "$FULL_REPO" -ne 1 ]]; then
    cmd+=(--max-depth "$MAX_DEPTH" --max-instances "$MAX_INSTANCES")
  fi
  cmd+=("$@")
  env RPKI_PROGRESS_LOG=1 "${cmd[@]}" >"$stdout_out" 2>"$stderr_out"

  finished_at_ms="$(python3 - <<'PY'
import time
print(int(time.time() * 1000))
PY
)"
  finished_at_iso="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
  write_step_timing "$timing_out" "$started_at_ms" "$finished_at_ms" "$started_at_iso" "$finished_at_iso"

  local validation_time
  validation_time="$(python3 - <<'PY' "$report_out"
import json, sys
print(json.load(open(sys.argv[1], 'r', encoding='utf-8'))['meta']['validation_time_rfc3339_utc'])
PY
)"

  printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
    "$step_id" \
    "$kind" \
    "$validation_time" \
    "$(basename "$cir_out")" \
    "$(basename "$ccr_out")" \
    "$(basename "$report_out")" \
    "$(basename "$timing_out")" \
    "$(basename "$stdout_out")" \
    "$(basename "$stderr_out")" >> "$ROWS"
}

run_step "full" "full" "" 

prev="full"
for idx in $(seq 1 "$DELTA_COUNT"); do
  sleep "$SLEEP_SECS"
  step="$(printf 'delta-%03d' "$idx")"
  run_step "$step" "delta" "$prev"
  prev="$step"
done

python3 - <<'PY' "$OUT" "$ROWS" "$RIR"
import json, sys
from pathlib import Path

out = Path(sys.argv[1])
rows = Path(sys.argv[2]).read_text(encoding='utf-8').splitlines()
rir = sys.argv[3]
steps = []
for idx, row in enumerate(rows):
    step_id, kind, validation_time, cir_name, ccr_name, report_name, timing_name, stdout_name, stderr_name = row.split('\t')
    steps.append({
        "stepId": step_id,
        "kind": kind,
        "validationTime": validation_time,
        "cirPath": cir_name,
        "ccrPath": ccr_name,
        "reportPath": report_name,
        "timingPath": timing_name,
        "stdoutLogPath": stdout_name,
        "stderrLogPath": stderr_name,
        "artifactPrefix": cir_name[:-4],  # strip .cir
        "previousStepId": None if idx == 0 else steps[idx - 1]["stepId"],
    })

(out / "sequence.json").write_text(
    json.dumps({"version": 1, "repoBytesDbPath": "repo-bytes.db", "steps": steps}, indent=2),
    encoding="utf-8",
)

summary = {
    "version": 1,
    "rir": rir,
    "stepCount": len(steps),
    "steps": [],
}
for step in steps:
    timing = json.loads((out / step["timingPath"]).read_text(encoding="utf-8"))
    summary["steps"].append({
        "stepId": step["stepId"],
        "kind": step["kind"],
        "validationTime": step["validationTime"],
        "artifactPrefix": step["artifactPrefix"],
        **timing,
    })

(out / "summary.json").write_text(json.dumps(summary, indent=2), encoding="utf-8")
PY

rm -f "$ROWS"
echo "$OUT"
EOS
