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

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

fail() {
  echo "ERROR: $*" >&2
  exit 1
}

source "$repo_root/scripts/backup/lib/common.sh"
source "$repo_root/scripts/backup/lib/manifest.sh"
source "$repo_root/scripts/backup/lib/report.sh"

assert_eq() {
  local expected="$1"
  local actual="$2"
  local message="$3"
  [[ "$actual" == "$expected" ]] || fail "$message: expected '$expected', got '$actual'"
}

all_services="$(normalize_service_filter "all")"
assert_eq "postgres ory-postgres clickhouse ory-clickhouse config" "$all_services" "all must expand to every supported service"

selected_services="$(normalize_service_filter "postgres,config")"
assert_eq "postgres config" "$selected_services" "comma-separated services must be normalized in input order"

ory_services="$(normalize_service_filter "ory-postgres,ory-clickhouse")"
assert_eq "ory-postgres ory-clickhouse" "$ory_services" "ory service filter must not expand to Baron services"

if service_enabled "postgres" "$ory_services"; then
  fail "service_enabled must not match postgres inside ory-postgres"
fi

if service_enabled "clickhouse" "$ory_services"; then
  fail "service_enabled must not match clickhouse inside ory-clickhouse"
fi

service_enabled "ory-postgres" "$ory_services" || fail "service_enabled must match exact ory-postgres token"
service_enabled "ory-clickhouse" "$ory_services" || fail "service_enabled must match exact ory-clickhouse token"

grep -Fq "drop database if exists" "$repo_root/scripts/backup/lib/clickhouse.sh" \
  || fail "ClickHouse restore must drop restored databases before replaying schema/data to avoid duplicate rows or init-table conflicts."
grep -Fq "FORMAT RawBLOB" "$repo_root/scripts/backup/lib/clickhouse.sh" \
  || fail "ClickHouse dump must store SHOW CREATE TABLE as raw SQL, not escaped TSV."
grep -Fq "render_clickhouse_schema" "$repo_root/scripts/backup/lib/clickhouse.sh" \
  || fail "ClickHouse restore must route schema files through the compatibility decoder."
grep -Fq "s{\\\\n}" "$repo_root/scripts/backup/lib/clickhouse.sh" \
  || fail "ClickHouse restore must decode escaped newlines from older schema dumps."
grep -Fq "x27" "$repo_root/scripts/backup/lib/clickhouse.sh" \
  || fail "ClickHouse restore must decode escaped single quotes from older schema dumps."
grep -Fq "filter_clickhouse_stable_row_counts" "$repo_root/scripts/backup/restore.sh" \
  || fail "restore verification must not fail on unstable ClickHouse aggregate/view physical row counts."
grep -Fq "collect_clickhouse_native_stable_row_counts" "$repo_root/scripts/backup/restore.sh" \
  || fail "restore verification must derive ClickHouse expected counts from Native data files."

if normalize_service_filter "postgres,unknown" >/tmp/baron-sso-service-filter.out 2>&1; then
  fail "unknown backup service must be rejected"
fi

if ! grep -Fq "unknown backup service" /tmp/baron-sso-service-filter.out; then
  fail "unknown service rejection must explain the service filter problem"
fi

tmp_dir="$(mktemp -d /tmp/baron-sso-backup-policy.XXXXXX)"
trap 'rm -rf "$tmp_dir"' EXIT INT TERM

mkdir -p "$tmp_dir/reports"
create_manifest "$tmp_dir" "maintenance" "postgres config"

manifest="$tmp_dir/manifest.json"
[[ -f "$manifest" ]] || fail "create_manifest must write manifest.json"
grep -Fq '"format_version": "1"' "$manifest" || fail "manifest must include format_version"
grep -Fq '"mode": "maintenance"' "$manifest" || fail "manifest must include backup mode"
grep -Fq '"services": [' "$manifest" || fail "manifest must include service list"
grep -Fq '"git_commit":' "$manifest" || fail "manifest must include git commit"

cat >"$tmp_dir/reports/baron-postgres-row-counts.txt" <<'EOF'
public.users:228
public.tenants:266
public.relying_parties:1
EOF
cat >"$tmp_dir/reports/baron-postgres-custom-claim-counts.txt" <<'EOF'
public.rp_user_metadata:7
public.users.global_custom_claims:3
public.users.global_custom_claim_types:2
EOF
cat >"$tmp_dir/reports/ory_hydra-row-counts.txt" <<'EOF'
public.hydra_client:5
EOF
write_backup_markdown_report "$tmp_dir" "succeeded" "postgres config" '[{"service":"postgres","duration_seconds":2},{"service":"config","duration_seconds":1}]'
backup_md="$tmp_dir/reports/backup-report.md"
[[ -f "$backup_md" ]] || fail "backup markdown report must be created."
grep -Fq "# Baron SSO Backup Report" "$backup_md" || fail "backup report must have a markdown title."
grep -Fq "| 사용자 | 228 |" "$backup_md" || fail "backup report must include user count."
grep -Fq "| 테넌트 | 266 |" "$backup_md" || fail "backup report must include tenant count."
grep -Fq "| RP | 1 |" "$backup_md" || fail "backup report must include RP count."
grep -Fq "| RP 사용자 custom claim | 7 |" "$backup_md" || fail "backup report must include RP user custom claim count."
grep -Fq "| 전역 custom claim 사용자 | 3 |" "$backup_md" || fail "backup report must include global custom claim user count."
grep -Fq "| postgres | 2 |" "$backup_md" || fail "backup report must include service duration."

grep -Fq "baron-postgres-custom-claim-counts.txt" "$repo_root/scripts/backup/lib/postgres.sh" \
  || fail "Baron Postgres dump must collect custom claim backup verification counts."
grep -Fq "global_custom_claims" "$repo_root/scripts/backup/lib/postgres.sh" \
  || fail "Baron Postgres dump must count users.metadata.global_custom_claims for backup verification."
grep -Fq "rp_user_metadata" "$repo_root/scripts/backup/lib/postgres.sh" \
  || fail "Baron Postgres dump must count rp_user_metadata rows for backup verification."

printf 'original\n' >"$tmp_dir/example.txt"
(cd "$tmp_dir" && sha256sum example.txt > checksums.sha256)
printf 'changed\n' >"$tmp_dir/example.txt"

if BACKUP="$tmp_dir" "$repo_root/scripts/backup/verify-dump.sh" >/tmp/baron-sso-checksum.out 2>&1; then
  fail "verify-dump must fail on checksum mismatch"
fi

if ! grep -Fq "checksum verification failed" /tmp/baron-sso-checksum.out; then
  fail "checksum mismatch output must be explicit"
fi

if BACKUP="$tmp_dir" CONFIRM_RESTORE="baron-sso" RESTORE_TEST_NON_EMPTY=1 "$repo_root/scripts/backup/restore.sh" --dry-run >/tmp/baron-sso-non-empty-restore.out 2>&1; then
  fail "restore must reject non-empty targets by default"
fi

if ! grep -Fq "non-empty restore target is not allowed" /tmp/baron-sso-non-empty-restore.out; then
  fail "restore must explain the non-empty target guard"
fi

archive_source="$tmp_dir/archive-source"
mkdir -p "$archive_source/reports"
create_manifest "$archive_source" "maintenance" "postgres"
printf 'archive fixture\n' >"$archive_source/example.txt"
(cd "$archive_source" && sha256sum manifest.json example.txt > checksums.sha256)
archive_file="$tmp_dir/archive-source.tar.zst"
tar --zstd -cf "$archive_file" -C "$tmp_dir" archive-source
restore_report="$tmp_dir/restore-report.json"

DUMP_FILE="$archive_file" \
CONFIRM_RESTORE="baron-sso" \
RESTORE_REPORT="$restore_report" \
"$repo_root/scripts/backup/restore.sh" --dry-run >/tmp/baron-sso-dump-file-restore.out

[[ -f "$restore_report" ]] || fail "restore dry-run with DUMP_FILE must write RESTORE_REPORT."
jq -e \
  --arg dump_file "$archive_file" \
  '.status == "planned" and .dump_file == $dump_file and .backup_dir != null and (.services | index("postgres"))' \
  "$restore_report" >/dev/null || fail "restore report must describe planned DUMP_FILE restore."

echo "OK: backup scripts enforce parser, manifest, checksum, and restore safety policies"
