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

usage() {
    cat <<'EOF'
Usage:
  scripts/update_readme_bench.sh [--check | --check-structure]

Reads Criterion outputs from target/criterion generated by:
  cargo bench --bench compare

and updates the README benchmark table block delimited by:
  <!-- BENCH_TABLES:BEGIN -->
  <!-- BENCH_TABLES:END -->

README benchmark numbers are published from CI.
Dispatch the Bench Readme workflow on the branch that should receive them:

  gh workflow run bench-readme.yml --ref <branch>

That workflow_dispatch job runs this script on a GitHub-hosted runner, then
runs `--check`, and opens a pull request from bench-readme-update when
README.md changes.

Each competitor is a time column plus a × column. The printed ratio is
competitor/bitflagset from the printed times (one decimal, or an integer
at 100 or above). The script exits non-zero if a printed ratio does not
match those times, or if a declared benchmark has no Criterion result.

  --check            Byte-for-byte compare against the Criterion data in
                     `target/criterion`. Keeps the README date.
  --check-structure  Host-independent check. The date is preserved, but only
                     tables, row and column sets, and ratio consistency are
                     compared. Printed times may differ. Exits 1 on a
                     structural mismatch and 2 when a measurement is missing.
EOF
}

CHECK_MODE=0
STRUCTURE_MODE=0
if [[ "${1-}" == "--check" ]]; then
    CHECK_MODE=1
elif [[ "${1-}" == "--check-structure" ]]; then
    CHECK_MODE=1
    STRUCTURE_MODE=1
elif [[ $# -gt 0 ]]; then
    usage
    exit 1
fi

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
README_PATH="${REPO_ROOT}/README.md"
START_MARKER="<!-- BENCH_TABLES:BEGIN -->"
END_MARKER="<!-- BENCH_TABLES:END -->"

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

existing_bench_date() {
    awk -v start="${START_MARKER}" -v end="${END_MARKER}" '
        $0 == start {
            in_block = 1
            next
        }
        $0 == end {
            in_block = 0
        }
        in_block && match($0, /\*\*[0-9]{4}-[0-9]{2}-[0-9]{2}\*\*/) {
            print substr($0, RSTART + 2, RLENGTH - 4)
            exit
        }
    ' "${README_PATH}"
}

block_date() {
    if [[ "${CHECK_MODE}" -eq 1 ]]; then
        local existing
        existing="$(existing_bench_date || true)"
        if [[ -n "${existing}" ]]; then
            printf '%s\n' "${existing}"
            return
        fi
    fi
    date +%F
}

replace_block() {
    local input="$1"
    local output="$2"
    local block_file="$3"
    awk -v start="${START_MARKER}" -v end="${END_MARKER}" -v block_file="${block_file}" '
        BEGIN {
            in_block = 0;
            seen_start = 0;
            seen_end = 0;
        }
        $0 == start {
            print;
            while ((getline line < block_file) > 0) {
                print line;
            }
            close(block_file);
            in_block = 1;
            seen_start = 1;
            next;
        }
        $0 == end {
            in_block = 0;
            seen_end = 1;
            print;
            next;
        }
        !in_block {
            print;
        }
        END {
            if (!seen_start || !seen_end) {
                print "Missing benchmark markers in README.md" > "/dev/stderr";
                exit 1;
            }
        }
    ' "${input}" > "${output}"
}

if [[ ! -f "${README_PATH}" ]]; then
    echo "README not found: ${README_PATH}" >&2
    exit 1
fi

block_tmp="$(mktemp)"
readme_tmp="$(mktemp)"
readme_block_tmp="$(mktemp)"
trap 'rm -f "${block_tmp}" "${readme_tmp}" "${readme_block_tmp}"' EXIT

BENCH_DATE="$(block_date)"
export REPO_ROOT BENCH_DATE
python3 "${SCRIPT_DIR}/readme_bench_tables.py" > "${block_tmp}"
replace_block "${README_PATH}" "${readme_tmp}" "${block_tmp}"

if [[ "${STRUCTURE_MODE}" -eq 1 ]]; then
    awk -v start="${START_MARKER}" -v end="${END_MARKER}" '
        $0 == start { in_block = 1; next }
        $0 == end { in_block = 0 }
        in_block { print }
    ' "${README_PATH}" > "${readme_block_tmp}"
    python3 "${SCRIPT_DIR}/readme_bench_tables.py" --structural-diff "${readme_block_tmp}" "${block_tmp}"
    exit 0
fi

if [[ "${CHECK_MODE}" -eq 1 ]]; then
    if cmp -s "${README_PATH}" "${readme_tmp}"; then
        echo "README benchmark tables are up to date."
        exit 0
    fi
    echo "README benchmark tables do not match the Criterion data in target/criterion." >&2
    echo "Dispatch the Bench Readme workflow (workflow_dispatch) to regenerate README.md." >&2
    diff -u "${README_PATH}" "${readme_tmp}" || true
    exit 1
fi

mv "${readme_tmp}" "${README_PATH}"
echo "Updated README benchmark tables from target/criterion."
