#!/bin/bash
# DC-039 follow-up — regression test for start.sh image-layer migration step.
# Validates: idempotency, partial files, missing files, sentinel creation,
# set -e doesn't kill the script on a single per-file failure.

set -u
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FAILURES=0

pass() { echo "  ✓ $1"; }
fail() { echo "  ✗ $1"; FAILURES=$((FAILURES + 1)); }

# ---- Setup helpers ----------------------------------------------------------
# Source only the migration function out of start.sh — don't run the whole
# script (it would try to bind to port 3001 + manage docker). Use the same
# sh-extraction pattern as test-dashcaddy-update-backup.sh.

fresh_data_dir() {
  local d
  d="$(mktemp -d /tmp/dashcaddy-migration-test.XXXXXX)"
  echo "${d}"
}

clean_data_dir() {
  rm -rf "$1" 2>/dev/null || true
}

# Extract just the migration logic — it's the only block we want to test.
extract_migration() {
  sed -n '/^MIGRATION_SENTINEL=/,/^run_image_layer_migration$/p' "${SCRIPT_DIR}/../start.sh"
}

# Test 1: Sentinel file present → migration skips entirely
echo "Test 1: sentinel exists → no copies"
DATA_DIR="$(fresh_data_dir)"
touch "${DATA_DIR}/.migrated-from-image-layer"
extract_migration > /tmp/_migration_extract.sh
# Override DATA_DIR to point at our test dir
# Strip the actual call (the trailing 'run_image_layer_migration') so we
# control invocation; in tests we re-define DATA_DIR first.
{
  echo "DATA_DIR='${DATA_DIR}'"
  echo "MIGRATION_SENTINEL=\"\${DATA_DIR}/.migrated-from-image-layer\""
  sed -n '/^IMAGE_LAYER_ZOMBIES=(/,/^)$/p' "${SCRIPT_DIR}/../start.sh"
  sed -n '/^run_image_layer_migration()/,/^}$/p' "${SCRIPT_DIR}/../start.sh"
} > /tmp/_migration_block.sh
# shellcheck disable=SC1091
source /tmp/_migration_block.sh
# Plant a fake zombie that should NOT be migrated because the sentinel exists
ZOMBIE_DIR="$(mktemp -d /tmp/dashcaddy-zombie.XXXXXX)"
mkdir -p "${ZOMBIE_DIR}/security"
echo '{"data":"should not be migrated"}' > "${ZOMBIE_DIR}/security/audit-log.json"
run_image_layer_migration
if [ -f "${DATA_DIR}/migrated-audit-log.json" ]; then
  fail "test 1: sentinel existed, migration should have skipped but a file appeared"
else
  pass "sentinel skipped migration cleanly"
fi
rm -rf "${ZOMBIE_DIR}"
clean_data_dir "${DATA_DIR}"

# Test 2: No sentinel + non-empty zombie → migration copies file
echo "Test 2: zombie file present → migration copies to bind mount"
DATA_DIR="$(fresh_data_dir)"
ZOMBIE_DIR="$(mktemp -d /tmp/dashcaddy-zombie.XXXXXX)"
mkdir -p "${ZOMBIE_DIR}/security" "${ZOMBIE_DIR}/managers"
echo '{"audit":"prod data"}' > "${ZOMBIE_DIR}/security/audit-log.json"
echo "license-secret-blob" > "${ZOMBIE_DIR}/managers/.license-secret"
{
  echo "DATA_DIR='${DATA_DIR}'"
  echo "MIGRATION_SENTINEL=\"\${DATA_DIR}/.migrated-from-image-layer\""
  sed -n '/^IMAGE_LAYER_ZOMBIES=(/,/^)$/p' "${SCRIPT_DIR}/../start.sh"
  sed -n '/^run_image_layer_migration()/,/^}$/p' "${SCRIPT_DIR}/../start.sh"
} > /tmp/_migration_block2.sh
# Stub out the real zombie paths to point at our temp zombie
sed -i "s|/opt/dashcaddy/dashcaddy-api/src/security/audit-log.json|${ZOMBIE_DIR}/security/audit-log.json|g" /tmp/_migration_block2.sh
sed -i "s|/opt/dashcaddy/dashcaddy-api/src/managers/.license-secret|${ZOMBIE_DIR}/managers/.license-secret|g" /tmp/_migration_block2.sh
# shellcheck disable=SC1091
source /tmp/_migration_block2.sh
run_image_layer_migration
if [ ! -f "${DATA_DIR}/migrated-audit-log.json" ]; then
  fail "test 2: audit-log.json not migrated"
elif ! grep -q "audit.*prod data" "${DATA_DIR}/migrated-audit-log.json"; then
  fail "test 2: audit-log.json migrated but content corrupt"
else
  pass "audit-log.json migrated with correct content"
fi
if [ ! -f "${DATA_DIR}/migrated-.license-secret" ]; then
  fail "test 2: .license-secret not migrated"
else
  pass ".license-secret migrated"
fi
if [ ! -f "${DATA_DIR}/.migrated-from-image-layer" ]; then
  fail "test 2: sentinel file was not written"
else
  pass "sentinel file written"
fi
rm -rf "${ZOMBIE_DIR}"
clean_data_dir "${DATA_DIR}"

# Test 3: Idempotency — running migration twice does NOT clobber first copy
echo "Test 3: idempotency"
DATA_DIR="$(fresh_data_dir)"
ZOMBIE_DIR="$(mktemp -d /tmp/dashcaddy-zombie.XXXXXX)"
mkdir -p "${ZOMBIE_DIR}/security"
echo '{"first":true}' > "${ZOMBIE_DIR}/security/audit-log.json"
{
  echo "DATA_DIR='${DATA_DIR}'"
  echo "MIGRATION_SENTINEL=\"\${DATA_DIR}/.migrated-from-image-layer\""
  sed -n '/^IMAGE_LAYER_ZOMBIES=(/,/^)$/p' "${SCRIPT_DIR}/../start.sh"
  sed -n '/^run_image_layer_migration()/,/^}$/p' "${SCRIPT_DIR}/../start.sh"
} > /tmp/_migration_block3.sh
sed -i "s|/opt/dashcaddy/dashcaddy-api/src/security/audit-log.json|${ZOMBIE_DIR}/security/audit-log.json|g" /tmp/_migration_block3.sh
# shellcheck disable=SC1091
source /tmp/_migration_block3.sh
run_image_layer_migration
echo '{"second":true}' > "${ZOMBIE_DIR}/security/audit-log.json"  # mutate the source after migration
run_image_layer_migration
if grep -q "first.*true" "${DATA_DIR}/migrated-audit-log.json"; then
  pass "second run did not overwrite first migrated content"
else
  fail "second run overwrote the migrated file"
fi
rm -rf "${ZOMBIE_DIR}"
clean_data_dir "${DATA_DIR}"

# Test 4: Zero-byte zombie (empty file) → NOT migrated
echo "Test 4: empty file is not migrated"
DATA_DIR="$(fresh_data_dir)"
ZOMBIE_DIR="$(mktemp -d /tmp/dashcaddy-zombie.XXXXXX)"
mkdir -p "${ZOMBIE_DIR}/security"
touch "${ZOMBIE_DIR}/security/audit-log.json"  # zero bytes
{
  echo "DATA_DIR='${DATA_DIR}'"
  echo "MIGRATION_SENTINEL=\"\${DATA_DIR}/.migrated-from-image-layer\""
  sed -n '/^IMAGE_LAYER_ZOMBIES=(/,/^)$/p' "${SCRIPT_DIR}/../start.sh"
  sed -n '/^run_image_layer_migration()/,/^}$/p' "${SCRIPT_DIR}/../start.sh"
} > /tmp/_migration_block4.sh
sed -i "s|/opt/dashcaddy/dashcaddy-api/src/security/audit-log.json|${ZOMBIE_DIR}/security/audit-log.json|g" /tmp/_migration_block4.sh
# shellcheck disable=SC1091
source /tmp/_migration_block4.sh
run_image_layer_migration
if [ -f "${DATA_DIR}/migrated-audit-log.json" ]; then
  fail "test 4: empty file should not be migrated"
else
  pass "empty file correctly skipped"
fi
if [ -f "${DATA_DIR}/.migrated-from-image-layer" ]; then
  pass "sentinel still written even with zero zombies"
else
  fail "sentinel should still be written even with no zombies"
fi
rm -rf "${ZOMBIE_DIR}"
clean_data_dir "${DATA_DIR}"

# Test 5: set -e present + all per-file failures → script doesn't take down container
echo "Test 5: a single per-file failure does not bring down the container"
DATA_DIR="$(fresh_data_dir)"
ZOMBIE_DIR="$(mktemp -d /tmp/dashcaddy-zombie.XXXXXX)"
mkdir -p "${ZOMBIE_DIR}/security"
echo "x" > "${ZOMBIE_DIR}/security/audit-log.json"
chmod 000 "${ZOMBIE_DIR}/security/audit-log.json"   # make it unreadable so cp -a fails
{
  set -e  # NOW we need to verify the inner guard prevents set -e from killing us
  echo "DATA_DIR='${DATA_DIR}'"
  echo "MIGRATION_SENTINEL=\"\${DATA_DIR}/.migrated-from-image-layer\""
  sed -n '/^IMAGE_LAYER_ZOMBIES=(/,/^)$/p' "${SCRIPT_DIR}/../start.sh"
  sed -n '/^run_image_layer_migration()/,/^}$/p' "${SCRIPT_DIR}/../start.sh"
} > /tmp/_migration_block5.sh
sed -i "s|/opt/dashcaddy/dashcaddy-api/src/security/audit-log.json|${ZOMBIE_DIR}/security/audit-log.json|g" /tmp/_migration_block5.sh
EXIT=0
# shellcheck disable=SC1091
source /tmp/_migration_block5.sh && run_image_layer_migration || EXIT=$?
chmod 644 "${ZOMBIE_DIR}/security/audit-log.json" 2>/dev/null || true
rm -rf "${ZOMBIE_DIR}"
clean_data_dir "${DATA_DIR}"
if [ "$EXIT" -eq 0 ]; then
  pass "script survived a per-file cp failure"
else
  fail "set -e propagated a per-file failure (exit ${EXIT}); container would not boot"
fi

# ---- Cleanup ----------------------------------------------------------------
rm -f /tmp/_migration_extract.sh /tmp/_migration_block*.sh

echo
if [ "$FAILURES" -eq 0 ]; then
  echo "All migration regression tests passed."
  exit 0
fi
echo "${FAILURES} test(s) failed."
exit 1
