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

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/artifact_contract.sh"

SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
BASELINE_RUN=""
TARGET_RUN=""
CYCLE_DECISION_FILE=""
RUNS_DIR="${ARTIFACT_RUNS_DIR}"
OUTPUT_DIR="${ARTIFACT_BENCHMARK_DIR}"
GENERATOR=()

log_stage() {
  printf '%s [stage] %s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "$1"
}

die() {
  local code="$1"
  shift
  printf 'ERROR: %s\n' "$*" >&2
  exit "$code"
}

usage() {
  cat <<USAGE
Usage: ${SCRIPT_NAME} --baseline-run ID --target-run ID [--runs-dir DIR]

Runs baseline->target delta generation smoke check.

Options:
  --baseline-run ID   Baseline run id (required)
  --target-run ID     Target run id (required)
  --cycle-decision-file PATH  Optional specific cycle decision markdown
  --runs-dir DIR      Directory containing run folders (default: ${RUNS_DIR})
  -h, --help         Show this help and exit
USAGE
}

run_dir_for() {
  local run_id="$1"
  if [[ "${RUNS_DIR}" == "${ARTIFACT_RUNS_DIR}" ]]; then
    artifact_run_dir "${run_id}"
  else
    printf '%s/%s' "${RUNS_DIR}" "${run_id}"
  fi
}

log_stage "Starting argument parsing"
while [[ $# -gt 0 ]]; do
  case "$1" in
    --baseline-run)
      if [[ $# -lt 2 ]]; then
        echo "Missing value for --baseline-run" >&2
        usage >&2
        exit 1
      fi
      BASELINE_RUN="$2"
      shift 2
      ;;
    --target-run)
      if [[ $# -lt 2 ]]; then
        echo "Missing value for --target-run" >&2
        usage >&2
        exit 1
      fi
      TARGET_RUN="$2"
      shift 2
      ;;
    --cycle-decision-file)
      if [[ $# -lt 2 ]]; then
        echo "Missing value for --cycle-decision-file" >&2
        usage >&2
        exit 1
      fi
      CYCLE_DECISION_FILE="$2"
      shift 2
      ;;
    --runs-dir)
      if [[ $# -lt 2 ]]; then
        echo "Missing value for --runs-dir" >&2
        usage >&2
        exit 1
      fi
      RUNS_DIR="$2"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    --*)
      echo "Unknown option: $1" >&2
      usage >&2
      exit 1
      ;;
    *)
      echo "Unexpected positional argument (use flags only): $1" >&2
      usage >&2
      exit 1
      ;;
  esac
done

log_stage "Arguments parsed"
if [[ -z "${BASELINE_RUN}" || -z "${TARGET_RUN}" ]]; then
  echo "Both --baseline-run and --target-run are required" >&2
  usage >&2
  exit 1
fi

log_stage "Resolved contract defaults | runs-dir=${RUNS_DIR} output-dir=${OUTPUT_DIR}"

if [[ -x "${SCRIPT_DIR}/generate_benchmark_delta.sh" ]]; then
  GENERATOR=("${SCRIPT_DIR}/generate_benchmark_delta.sh")
elif [[ -f "${SCRIPT_DIR}/generate_benchmark_delta.py" ]]; then
  GENERATOR=(python3 "${SCRIPT_DIR}/generate_benchmark_delta.py")
else
  die 1 "No delta generator found in ${SCRIPT_DIR}"
fi

baseline_dir="$(run_dir_for "${BASELINE_RUN}")"
target_dir="$(run_dir_for "${TARGET_RUN}")"

log_stage "Checking run directories exist"
if [[ ! -d "${baseline_dir}" ]]; then
  die 2 "Baseline run missing: ${baseline_dir}"
fi
if [[ ! -d "${target_dir}" ]]; then
  die 2 "Target run missing: ${target_dir}"
fi

baseline_summary="${baseline_dir}/${ARTIFACT_SUMMARY_NAME}"
target_summary="${target_dir}/${ARTIFACT_SUMMARY_NAME}"

log_stage "Checking summary artifacts"
for p in "${baseline_summary}" "${target_summary}"; do
  if [[ ! -f "${p}" ]]; then
    die 2 "Summary artifact missing: ${p}"
  fi
done

log_stage "Validating summary artifact shape"
if python3 - "$baseline_summary" "$target_summary" <<'PY'
import json
import pathlib
import sys

required = {"generated_at", "run_id", "benchmarks"}
for path in sys.argv[1:]:
    payload = json.loads(pathlib.Path(path).read_text(encoding="utf-8"))
    if not isinstance(payload, dict):
        print(f"Invalid summary JSON top-level type in {path}: {type(payload).__name__}", file=sys.stderr)
        raise SystemExit(1)
    missing = sorted(required - payload.keys())
    if missing:
        print(f"Summary JSON missing required keys in {path}: {', '.join(missing)}", file=sys.stderr)
        raise SystemExit(1)
print("Summary artifacts parse OK")
PY
then
  :
else
  die 2 "Summary artifact schema validation failed"
fi

md_file="${OUTPUT_DIR}/DELTA_${TARGET_RUN}.md"
json_file="${OUTPUT_DIR}/DELTA_${TARGET_RUN}.json"

log_stage "Cleaning deterministic outputs for target ${TARGET_RUN}"
rm -f "${md_file}" "${json_file}"

log_stage "Running delta generator"
if ! "${GENERATOR[@]}" --baseline-run "${BASELINE_RUN}" --target-run "${TARGET_RUN}" --runs-dir "${RUNS_DIR}" --output-dir "${OUTPUT_DIR}"; then
  die 3 "Delta generator failed for ${BASELINE_RUN} -> ${TARGET_RUN}"
fi

log_stage "Validating generated markdown artifact"
if [[ ! -f "${md_file}" ]]; then
  die 4 "Missing expected delta markdown artifact: ${md_file}"
fi
if [[ ! -s "${md_file}" ]]; then
  die 4 "Delta markdown artifact is empty: ${md_file}"
fi

log_stage "Validating generated JSON artifact"
if [[ ! -f "${json_file}" ]]; then
  die 5 "Missing expected delta json artifact: ${json_file}"
fi
if [[ ! -s "${json_file}" ]]; then
  die 5 "Delta json artifact is empty: ${json_file}"
fi

if ! grep -q "Baseline run: \`${BASELINE_RUN}\`" "${md_file}"; then
  die 7 "Delta markdown artifact does not match baseline id: ${md_file}"
fi
if ! grep -q "Target run: \`${TARGET_RUN}\`" "${md_file}"; then
  die 7 "Delta markdown artifact does not match target id: ${md_file}"
fi

log_stage "Validating delta json schema"
if python3 - "$json_file" "$BASELINE_RUN" "$TARGET_RUN" <<'PY'
import json
import pathlib
import sys

path = pathlib.Path(sys.argv[1])
baseline = sys.argv[2]
target = sys.argv[3]

obj = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(obj, dict):
    print(f"Invalid top-level JSON type: {type(obj).__name__}", file=sys.stderr)
    raise SystemExit(1)

required_keys = {"generated_at", "baseline_run_id", "target_run_id", "totals", "benchmarks"}
missing = sorted(required_keys - set(obj.keys()))
if missing:
    print(f"Missing required keys in delta JSON: {', '.join(missing)}", file=sys.stderr)
    raise SystemExit(1)
if str(obj.get("baseline_run_id")) != baseline:
    print(
        f"Baseline run id mismatch: expected {baseline}, got {obj.get('baseline_run_id')}",
        file=sys.stderr,
    )
    raise SystemExit(1)
if str(obj.get("target_run_id")) != target:
    print(
        f"Target run id mismatch: expected {target}, got {obj.get('target_run_id')}",
        file=sys.stderr,
    )
    raise SystemExit(1)

totals = obj.get("totals")
if not isinstance(totals, dict):
    print("Delta JSON key 'totals' must be an object", file=sys.stderr)
    raise SystemExit(1)
for key in ("baseline_benchmarks", "target_benchmarks", "compared_benchmarks"):
    if key not in totals:
        print(f"Delta JSON totals missing required key: {key}", file=sys.stderr)
        raise SystemExit(1)

benchmarks = obj.get("benchmarks")
if not isinstance(benchmarks, list):
    print("Delta JSON key 'benchmarks' must be a list", file=sys.stderr)
    raise SystemExit(1)

print(f"JSON artifact OK: {path}")
PY
then
  :
else
  die 6 "Invalid or mismatched JSON for ${json_file}"
fi


log_stage "Resolving cycle decision artifact"
if [[ -z "${CYCLE_DECISION_FILE}" ]]; then
  shopt -s nullglob
  candidates=("${OUTPUT_DIR}/CYCLE_DECISION_${TARGET_RUN}.md" "${OUTPUT_DIR}/CYCLE_DECISION_${TARGET_RUN}-*.md")
  shopt -u nullglob
  if [[ ${#candidates[@]} -eq 0 ]]; then
    die 8 "Missing cycle decision artifact for target run ${TARGET_RUN} in ${OUTPUT_DIR}"
  fi
  CYCLE_DECISION_FILE="${candidates[0]}"
fi

log_stage "Running cycle-decision completeness gate"
if ! python3 "${SCRIPT_DIR}/check_cycle_decision.py" --cycle-decision-file "${CYCLE_DECISION_FILE}" --baseline-run "${BASELINE_RUN}" --target-run "${TARGET_RUN}"; then
  die 8 "Cycle decision gate failed for ${CYCLE_DECISION_FILE}"
fi
log_stage "Smoke delta check complete"
echo "PASS: baseline=${BASELINE_RUN} target=${TARGET_RUN}"
echo "markdown: ${md_file}"
echo "json: ${json_file}"
