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

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
# shellcheck source=../lib/component-receipts.sh
source "$ROOT/packaging/lib/component-receipts.sh"

fails=0
check() {
  if (( $1 == 0 )); then
    printf 'ok - %s\n' "$2"
  else
    printf 'FAIL - %s\n' "$2"
    fails=$((fails + 1))
  fi
}

TESTROOT="${XDG_CACHE_HOME:-$HOME/.cache}/overdeck/tests/component-receipts/run-$$-$RANDOM"
DEPLOY="$TESTROOT/repo"
COMPONENT_RECEIPT_DIR="$TESTROOT/receipts"
mkdir -p "$DEPLOY"
trap 'rm -rf "$TESTROOT"' EXIT

git -C "$DEPLOY" init -q
git -C "$DEPLOY" config user.name fixture
git -C "$DEPLOY" config user.email fixture@example.invalid
printf a >"$DEPLOY/value"
git -C "$DEPLOY" add value
git -C "$DEPLOY" commit -qm a
A=$(git -C "$DEPLOY" rev-parse HEAD)
printf b >"$DEPLOY/value"
git -C "$DEPLOY" commit -qam b
B=$(git -C "$DEPLOY" rev-parse HEAD)
printf c >"$DEPLOY/value"
git -C "$DEPLOY" commit -qam c
C=$(git -C "$DEPLOY" rev-parse HEAD)
TREE=$(git -C "$DEPLOY" rev-parse "$A^{tree}")
D=$(git -C "$DEPLOY" commit-tree "$TREE" -m unrelated)
M=$(git -C "$DEPLOY" commit-tree "$(git -C "$DEPLOY" rev-parse "$C^{tree}")" -p "$C" -p "$D" -m merged)

OVERDECK_COMPONENT_RECEIPT_NOW=2026-08-17T00:00:00Z \
  publish_component_receipt collector "$B"
check $? 'publishes a component receipt atomically'
[[ "$(component_receipt_sha collector)" == "$B" ]] \
  && grep -qx "{\"schema\":1,\"component\":\"collector\",\"target_sha\":\"$B\",\"converged_at\":\"2026-08-17T00:00:00Z\"}" \
    "$COMPONENT_RECEIPT_DIR/collector.json" \
  && ! compgen -G "$COMPONENT_RECEIPT_DIR/.collector.json.*" >/dev/null
rc=$?; check "$rc" 'reads only the complete schema-1 receipt'

if [[ "$(component_convergence_base collector "$A" "$C")" == "$B" ]]; then rc=0; else rc=1; fi
check "$rc" 'newer component receipt supersedes the global stamp'
OVERDECK_COMPONENT_RECEIPT_NOW=2026-08-17T00:00:01Z \
  publish_component_receipt collector "$A"
if [[ "$(component_convergence_base collector "$B" "$C")" == "$B" ]]; then rc=0; else rc=1; fi
check "$rc" 'newer global success supersedes an older component receipt'

printf '{"schema":1' >"$COMPONENT_RECEIPT_DIR/collector.json"
if [[ "$(component_convergence_base collector "$A" "$C")" == "$A" ]]; then rc=0; else rc=1; fi
check "$rc" 'torn receipt fails closed to a valid global stamp'
printf '{"schema":1,"component":"collector","target_sha":"%040d","converged_at":"x"}\n' 0 \
  >"$COMPONENT_RECEIPT_DIR/collector.json"
if [[ "$(component_convergence_base collector "$A" "$C")" == "$A" ]]; then rc=0; else rc=1; fi
check "$rc" 'unknown receipt commit fails closed to a valid global stamp'
OVERDECK_COMPONENT_RECEIPT_NOW=2026-08-17T00:00:02Z \
  publish_component_receipt collector "$D"
[[ "$(component_convergence_base collector "$A" "$C")" == "$A" ]]
rc=$?; check "$rc" 'non-ancestor receipt cannot suppress target work'
! component_convergence_base collector "$C" "$M" >/dev/null
rc=$?; check "$rc" 'incomparable valid bases force work instead of guessing'

rm -f "$COMPONENT_RECEIPT_DIR/collector.json"
ln -s "$TESTROOT/missing" "$COMPONENT_RECEIPT_DIR/collector.json"
! component_receipt_sha collector >/dev/null 2>&1 \
  && ! publish_component_receipt collector "$C"
rc=$?; check "$rc" 'receipt symlinks are refused for reads and publication'
! publish_component_receipt '../collector' "$C"
rc=$?; check "$rc" 'component names cannot escape the receipt directory'

(( fails == 0 )) || { printf '%s check(s) failed\n' "$fails" >&2; exit 1; }
printf 'component-receipts: all checks passed\n'
