#!/usr/bin/env bash
#
# Unit tests for resolve-file-refs.sh password resolution
#
# Usage: bash test_resolve_file_refs.sh
#

set -euo pipefail

# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m' # No Color

TESTS_PASSED=0
TESTS_FAILED=0
TESTS_TOTAL=0

# Setup test directory
TEST_DIR="/tmp/resolve-file-refs-test-$$"
mkdir -p "$TEST_DIR"

# Source the script under test
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "$SCRIPT_DIR/resolve-file-refs.sh"

# Test helper functions
pass() {
  echo -e "${GREEN}✓ PASS${NC}: $1"
  TESTS_PASSED=$((TESTS_PASSED + 1))
  TESTS_TOTAL=$((TESTS_TOTAL + 1))
  return 0
}

fail() {
  echo -e "${RED}✗ FAIL${NC}: $1"
  echo -e "  ${RED}Expected:${NC} $2"
  echo -e "  ${RED}Got:${NC} $3"
  TESTS_FAILED=$((TESTS_FAILED + 1))
  TESTS_TOTAL=$((TESTS_TOTAL + 1))
  return 0
}

cleanup() {
  rm -rf "$TEST_DIR"
}

trap cleanup EXIT

# ============================================================================
# TEST SUITE: Success Cases
# ============================================================================

test_resolve_password_basic() {
  local test_name="Basic password resolution"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  echo "jksPassword=mySecret123" > "$pwd_file"

  # Test
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  result=$(resolve_file_password "$config" 2>&1 | tail -1)

  # Assert
  if [[ "$result" == "keystorePassword=mySecret123" ]]; then
    pass "$test_name"
  else
    fail "$test_name" "keystorePassword=mySecret123" "$result"
  fi
}

test_resolve_password_with_special_chars() {
  local test_name="Password with special characters"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  echo "jksPassword=P@ssw0rd!#\$%^&*()_+-={}[]|:;<>,.?/~\`" > "$pwd_file"

  # Test
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  result=$(resolve_file_password "$config" 2>&1 | tail -1)

  # Assert
  if [[ "$result" == "keystorePassword=P@ssw0rd!#\$%^&*()_+-={}[]|:;<>,.?/~\`" ]]; then
    pass "$test_name"
  else
    fail "$test_name" "keystorePassword=P@ssw0rd!#\$%^&*()_+-={}[]|:;<>,.?/~\`" "$result"
  fi
}

test_resolve_password_in_full_jolokia_config() {
  local test_name="Password resolution in full Jolokia config string"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  echo "jksPassword=actualpass123" > "$pwd_file"

  # Test
  local config="protocol=https,useSslClientAuthentication=true,keystore=/vault/secrets/keystore.jks,keystorePassword=\${file:${pwd_file}:jksPassword},sslProtocol.1=TLSv1.2,sslProtocol.2=TLSv1.3"
  local result
  result=$(resolve_file_password "$config" 2>&1 | tail -1)

  # Assert
  if [[ "$result" == *"keystorePassword=actualpass123"* ]] && \
     [[ "$result" == *"sslProtocol.1=TLSv1.2"* ]]; then
    pass "$test_name"
  else
    fail "$test_name" "Full config with resolved password" "$result"
  fi
}

test_no_resolution_when_no_file_reference() {
  local test_name="No resolution when no file reference present"

  # Test - config without ${file:...} syntax
  local config="keystorePassword=mystorepassword"
  local result
  result=$(resolve_file_password "$config" 2>&1 | tail -1)

  # Assert - should return unchanged
  if [[ "$result" == "keystorePassword=mystorepassword" ]]; then
    pass "$test_name"
  else
    fail "$test_name" "keystorePassword=mystorepassword" "$result"
  fi
}

test_resolve_password_with_multiple_equals() {
  local test_name="Password containing equals sign"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  echo "jksPassword=key=value=test" > "$pwd_file"

  # Test
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  result=$(resolve_file_password "$config" 2>&1 | tail -1)

  # Assert - should preserve everything after first =
  if [[ "$result" == "keystorePassword=key=value=test" ]]; then
    pass "$test_name"
  else
    fail "$test_name" "keystorePassword=key=value=test" "$result"
  fi
}

test_resolve_password_strips_newlines() {
  local test_name="Strip trailing newlines from password"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  printf "jksPassword=testpass\n\n" > "$pwd_file"

  # Test
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  result=$(resolve_file_password "$config" 2>&1 | tail -1)

  # Assert - should not have trailing newline
  if [[ "$result" == "keystorePassword=testpass" ]]; then
    pass "$test_name"
  else
    fail "$test_name" "keystorePassword=testpass (no newline)" "$result"
  fi
}

test_resolve_password_strips_carriage_returns() {
  local test_name="Strip carriage returns from password"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  printf "jksPassword=testpass\r\n" > "$pwd_file"

  # Test
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  result=$(resolve_file_password "$config" 2>&1 | tail -1)

  # Assert
  if [[ "$result" == "keystorePassword=testpass" ]]; then
    pass "$test_name"
  else
    fail "$test_name" "keystorePassword=testpass (no CR/LF)" "$result"
  fi
}

# ============================================================================
# TEST SUITE: Error Handling - File Missing (Graceful) vs Malformed (Fail-Fast)
# ============================================================================

test_error_when_file_not_found() {
  local test_name="Fallback to default password when file does not exist"

  # Test
  local config="keystorePassword=\${file:/nonexistent/path/jksPassword.txt:jksPassword}"
  local result
  local exit_code=0
  result=$(resolve_file_password "$config" 2>&1) || exit_code=$?

  # Assert - should return default password with warning, not exit with error
  if [[ $exit_code -eq 0 ]] && [[ "$result" == *"WARN"* ]] && [[ "$result" == *"not found"* ]] && [[ "$result" == *"keystorePassword=mystorepassword"* ]]; then
    pass "$test_name"
  else
    fail "$test_name" "Exit code 0 with WARN message and default password" "Exit code: $exit_code, Output: $result"
  fi
}

test_error_when_key_not_found() {
  local test_name="Error when key not found in password file (fail-fast)"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  echo "wrongKey=password123" > "$pwd_file"

  # Test
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  local exit_code=0
  result=$(resolve_file_password "$config" 2>&1) || exit_code=$?

  # Assert - file exists but key is wrong, should fail fast
  if [[ $exit_code -ne 0 ]] && [[ "$result" == *"ERROR"* ]] && [[ "$result" == *"not found"* ]]; then
    pass "$test_name"
  else
    fail "$test_name" "Exit code 1 with ERROR message" "Exit code: $exit_code, Output: $result"
  fi
}

test_error_when_password_value_empty() {
  local test_name="Error when password value is empty (fail-fast)"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  echo "jksPassword=" > "$pwd_file"

  # Test
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  local exit_code=0
  result=$(resolve_file_password "$config" 2>&1) || exit_code=$?

  # Assert - file exists but password is empty, should fail fast
  if [[ $exit_code -ne 0 ]] && [[ "$result" == *"ERROR"* ]] && [[ "$result" == *"is empty"* ]]; then
    pass "$test_name"
  else
    fail "$test_name" "Exit code 1 with ERROR message" "Exit code: $exit_code, Output: $result"
  fi
}

test_error_when_file_empty() {
  local test_name="Error when password file is empty (fail-fast)"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  touch "$pwd_file"  # Create empty file

  # Test
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  local exit_code=0
  result=$(resolve_file_password "$config" 2>&1) || exit_code=$?

  # Assert - file exists but is empty, should fail fast
  if [[ $exit_code -ne 0 ]] && [[ "$result" == *"ERROR"* ]]; then
    pass "$test_name"
  else
    fail "$test_name" "Exit code 1 with ERROR message" "Exit code: $exit_code, Output: $result"
  fi
}

test_error_messages_are_helpful() {
  local test_name="Warning messages contain helpful information"

  # Test
  local pwd_file="$TEST_DIR/missing.txt"
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  result=$(resolve_file_password "$config" 2>&1) || true

  # Assert - warning message should mention the file path and default password fallback
  if [[ "$result" == *"${pwd_file}"* ]] && [[ "$result" == *"WARN"* ]] && [[ "$result" == *"not found"* ]] && [[ "$result" == *"default password"* ]]; then
    pass "$test_name"
  else
    fail "$test_name" "Warning with file path and default password fallback" "$result"
  fi
}

# ============================================================================
# TEST SUITE: Edge Cases
# ============================================================================

test_multiple_keys_in_same_file() {
  local test_name="Multiple keys in same password file"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  cat > "$pwd_file" <<EOF
# Comments are ignored
otherKey=wrongvalue
jksPassword=correctvalue
anotherKey=alsoignored
EOF

  # Test
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  result=$(resolve_file_password "$config" 2>&1 | tail -1)

  # Assert - should pick the correct key
  if [[ "$result" == "keystorePassword=correctvalue" ]]; then
    pass "$test_name"
  else
    fail "$test_name" "keystorePassword=correctvalue" "$result"
  fi
}

test_duplicate_key_uses_first() {
  local test_name="Duplicate keys - uses first occurrence"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  cat > "$pwd_file" <<EOF
jksPassword=firstvalue
jksPassword=secondvalue
EOF

  # Test
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  result=$(resolve_file_password "$config" 2>&1 | tail -1)

  # Assert - should use first occurrence
  if [[ "$result" == "keystorePassword=firstvalue" ]]; then
    pass "$test_name"
  else
    fail "$test_name" "keystorePassword=firstvalue" "$result"
  fi
}

test_password_with_spaces() {
  local test_name="Password containing spaces"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  echo "jksPassword=my password with spaces" > "$pwd_file"

  # Test
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  result=$(resolve_file_password "$config" 2>&1 | tail -1)

  # Assert
  if [[ "$result" == "keystorePassword=my password with spaces" ]]; then
    pass "$test_name"
  else
    fail "$test_name" "keystorePassword=my password with spaces" "$result"
  fi
}

test_absolute_vs_relative_paths() {
  local test_name="Absolute vs relative paths"

  # Setup
  local pwd_file="$TEST_DIR/jksPassword.txt"
  echo "jksPassword=testpass" > "$pwd_file"

  # Test with absolute path
  local config="keystorePassword=\${file:${pwd_file}:jksPassword}"
  local result
  result=$(resolve_file_password "$config" 2>&1 | tail -1)

  # Assert
  if [[ "$result" == "keystorePassword=testpass" ]]; then
    pass "$test_name"
  else
    fail "$test_name" "keystorePassword=testpass" "$result"
  fi
}

# ============================================================================
# RUN ALL TESTS
# ============================================================================

echo ""
echo "=========================================="
echo "  resolve-file-refs.sh Unit Test Suite"
echo "=========================================="
echo ""

echo "Running Success Cases..."
test_resolve_password_basic
test_resolve_password_with_special_chars
test_resolve_password_in_full_jolokia_config
test_no_resolution_when_no_file_reference
test_resolve_password_with_multiple_equals
test_resolve_password_strips_newlines
test_resolve_password_strips_carriage_returns

echo ""
echo "Running Error Handling Cases..."
test_error_when_file_not_found
test_error_when_key_not_found
test_error_when_password_value_empty
test_error_when_file_empty
test_error_messages_are_helpful

echo ""
echo "Running Edge Cases..."
test_multiple_keys_in_same_file
test_duplicate_key_uses_first
test_password_with_spaces
test_absolute_vs_relative_paths

# ============================================================================
# SUMMARY
# ============================================================================

echo ""
echo "=========================================="
echo "  Test Results"
echo "=========================================="
echo -e "Total:  $TESTS_TOTAL"
echo -e "${GREEN}Passed: $TESTS_PASSED${NC}"
if [ $TESTS_FAILED -gt 0 ]; then
  echo -e "${RED}Failed: $TESTS_FAILED${NC}"
else
  echo -e "Failed: $TESTS_FAILED"
fi
echo "=========================================="

if [ $TESTS_FAILED -gt 0 ]; then
  exit 1
fi

exit 0
