#!/usr/bin/env bats
# Tests for scripts/orca-pull.sh — the C-09 failure contract + C-23
# cluster-wide vs namespace-scoped distinction.

load test_helper

PULL="$SCRIPTS_DIR/orca-pull.sh"
TMP_TXN=""

setup() {
	TMP_TXN="$(mktemp -d)"
	# Minimal apply/verify/rollback scripts that succeed.
	cat >"$TMP_TXN/apply.sh" <<'EOF'
#!/usr/bin/env bash
touch "$TMP_TXN/.applied-marker"
exit 0
EOF
	# A real marker the orca-pull.sh checks for.
	cat >"$TMP_TXN/apply.sh" <<'EOF'
#!/usr/bin/env bash
touch "$(dirname "$0")/.applied"
exit 0
EOF
	cat >"$TMP_TXN/verify.sh" <<'EOF'
#!/usr/bin/env bash
exit 0
EOF
	cat >"$TMP_TXN/rollback.sh" <<'EOF'
#!/usr/bin/env bash
rm -f "$(dirname "$0")/.applied"
exit 0
EOF
	chmod +x "$TMP_TXN"/*.sh
}

teardown() {
	[ -n "$TMP_TXN" ] && rm -rf "$TMP_TXN"
}

@test "orca-pull.sh exists and is executable" {
	[ -f "$PULL" ]
	[ -x "$PULL" ]
}

@test "orca-pull.sh refuses without --txn-dir (exit 4)" {
	run "$PULL" --force --i-understand-the-risk
	assert_status 4 "$status"
}

@test "orca-pull.sh cluster-wide without --force exits 4 (C-23)" {
	run "$PULL" --txn-dir "$TMP_TXN"
	assert_status 4 "$status"
	assert_contains "$output" "requires --force"
}

@test "orca-pull.sh cluster-wide with --force but no ack exits 4 (C-23)" {
	run "$PULL" --txn-dir "$TMP_TXN" --force
	assert_status 4 "$status"
	assert_contains "$output" "--i-understand-the-risk"
}

@test "orca-pull.sh cluster-wide with --force --i-understand-the-risk applies" {
	run "$PULL" --txn-dir "$TMP_TXN" --force --i-understand-the-risk
	assert_status 0 "$status"
	assert_contains "$output" "applied"
	[ -f "$TMP_TXN/.applied" ]
}

@test "orca-pull.sh namespace-scoped applies without --force (C-23)" {
	run "$PULL" --txn-dir "$TMP_TXN" --namespace default
	assert_status 0 "$status"
	assert_contains "$output" "applied"
	[ -f "$TMP_TXN/.applied" ]
}

@test "orca-pull.sh idempotent re-run exits 5 (already-applied)" {
	# First apply.
	run "$PULL" --txn-dir "$TMP_TXN" --namespace default
	assert_status 0 "$status"
	# Re-run: should be a no-op (exit 5).
	run "$PULL" --txn-dir "$TMP_TXN" --namespace default
	assert_status 5 "$status"
	assert_contains "$output" "already-applied"
}

@test "orca-pull.sh apply failure runs rollback and exits 1" {
	# Make apply.sh fail.
	cat >"$TMP_TXN/apply.sh" <<'EOF'
#!/usr/bin/env bash
exit 1
EOF
	chmod +x "$TMP_TXN/apply.sh"
	run "$PULL" --txn-dir "$TMP_TXN" --namespace default
	[ "$status" -eq 1 ]
}

@test "orca-pull.sh verify failure runs rollback and exits 2" {
	# apply succeeds, verify fails.
	cat >"$TMP_TXN/verify.sh" <<'EOF'
#!/usr/bin/env bash
exit 1
EOF
	chmod +x "$TMP_TXN/verify.sh"
	run "$PULL" --txn-dir "$TMP_TXN" --namespace default
	[ "$status" -eq 2 ]
}

@test "orca-pull.sh missing bundle file exits 4" {
	rm -f "$TMP_TXN/verify.sh"
	run "$PULL" --txn-dir "$TMP_TXN" --namespace default
	assert_status 4 "$status"
}

@test "orca-pull.sh drift gate refuses with exit 6 when drift detected (R-020)" {
	# Create a drift-events-aggregated.json with confirmed drift.
	mkdir -p "$TMP_TXN/state"
	DRIFT_JSON="$TMP_TXN/state/drift-events-aggregated.json"
	cat >"$DRIFT_JSON" <<EOF
{"ts":"2026-01-01T00:00:00Z","events":[{"event_id":"E1","host":"p","path":"/etc/orca/actual/default/x","status":"modified","drift_confirmed":true}]}
EOF
	ORCA_DRIFT_AGG_JSON="$DRIFT_JSON" run "$PULL" --txn-dir "$TMP_TXN" --namespace default
	assert_status 6 "$status"
	assert_contains "$output" "drift detected"
}

@test "orca-pull.sh drift gate passes when no drift" {
	# Empty aggregated doc -> no drift -> applies.
	mkdir -p "$TMP_TXN/state"
	DRIFT_JSON="$TMP_TXN/state/drift-events-aggregated.json"
	echo '{"ts":"2026-01-01T00:00:00Z","events":[]}' >"$DRIFT_JSON"
	ORCA_DRIFT_AGG_JSON="$DRIFT_JSON" run "$PULL" --txn-dir "$TMP_TXN" --namespace default
	assert_status 0 "$status"
}

@test "orca-pull.sh drift gate --force overrides (R-020)" {
	# Create drift, then apply with --force --i-understand-the-risk.
	mkdir -p "$TMP_TXN/state"
	DRIFT_JSON="$TMP_TXN/state/drift-events-aggregated.json"
	cat >"$DRIFT_JSON" <<EOF
{"ts":"2026-01-01T00:00:00Z","events":[{"event_id":"E1","host":"p","path":"/etc/orca/actual/default/x","status":"modified","drift_confirmed":true}]}
EOF
	ORCA_DRIFT_AGG_JSON="$DRIFT_JSON" run "$PULL" --txn-dir "$TMP_TXN" --namespace default --force --i-understand-the-risk
	assert_status 0 "$status"
}

@test "orca-pull.sh drift gate per-namespace scoping (ns-A drift does not block ns-B)" {
	# Drift in ns-A; apply to ns-B should succeed.
	mkdir -p "$TMP_TXN/state"
	DRIFT_JSON="$TMP_TXN/state/drift-events-aggregated.json"
	cat >"$DRIFT_JSON" <<EOF
{"ts":"2026-01-01T00:00:00Z","events":[{"event_id":"E1","host":"p","path":"/etc/orca/actual/ns-a/x","status":"modified","drift_confirmed":true}]}
EOF
	ORCA_DRIFT_AGG_JSON="$DRIFT_JSON" run "$PULL" --txn-dir "$TMP_TXN" --namespace ns-b
	assert_status 0 "$status"
}

@test "orca-pull.sh drift gate cluster-wide checks all confirmed drift" {
	# No --namespace; cluster-wide requires --force. When --force given
	# AND drift present, gate is skipped (force bypasses drift too).
	mkdir -p "$TMP_TXN/state"
	DRIFT_JSON="$TMP_TXN/state/drift-events-aggregated.json"
	cat >"$DRIFT_JSON" <<EOF
{"ts":"2026-01-01T00:00:00Z","events":[{"event_id":"E1","host":"p","path":"/etc/traefik/dynamic/orca.yml","status":"modified","drift_confirmed":true}]}
EOF
	ORCA_DRIFT_AGG_JSON="$DRIFT_JSON" run "$PULL" --txn-dir "$TMP_TXN" --force --i-understand-the-risk
	assert_status 0 "$status"
}
