#!/bin/bash
# tests/perf/test-result-caching.sh
# Phase 6 :: Agent Result Caching Tests (BUG #21 Compliant)
#
# Validates:
# - Cache hit/miss tracking with real Redis
# - Cache key generation
# - TTL enforcement (1 hour)
# - Prometheus metrics integration
# - Cache hit rate target (80%+)

set -euo pipefail

PROJECT_ROOT=$(git rev-parse --show-toplevel)
source "$PROJECT_ROOT/tests/test-utils.sh"

# Test configuration
REDIS_CONTAINER="cfn-redis-cache-test-$$"
REDIS_PORT="6380"

cleanup() {
  log_info "Cleaning up test resources..."
  docker rm -f "$REDIS_CONTAINER" 2>/dev/null || true
  rm -f /tmp/test-cache-*.js 2>/dev/null || true
}
trap cleanup EXIT

test_setup_redis() {
  log_step "GIVEN Redis server"

  # WHEN starting Redis container
  docker run -d \
    --name "$REDIS_CONTAINER" \
    -p "$REDIS_PORT:6379" \
    redis:7-alpine > /dev/null

  # Wait for Redis to be ready
  for i in {1..30}; do
    if docker exec "$REDIS_CONTAINER" redis-cli ping > /dev/null 2>&1; then
      log_success "Redis ready"
      return 0
    fi
    sleep 1
  done

  log_error "Redis failed to start"
  return 1
}

test_cache_key_generation() {
  log_step "GIVEN agent type and task description"

  # WHEN generating cache key
  log_info "Testing cache key generation..."

  # Create test script
  cat > /tmp/test-cache-key.js << 'EOF'
const crypto = require('crypto');

function generateCacheKey(agentType, task) {
  const taskHash = crypto.createHash('sha256').update(task).digest('hex').substring(0, 16);
  return `cfn:agent:result:${agentType}:${taskHash}`;
}

const key1 = generateCacheKey('backend-developer', 'Implement API endpoint');
const key2 = generateCacheKey('backend-developer', 'Implement API endpoint');
const key3 = generateCacheKey('backend-developer', 'Different task');

console.log('KEY1:', key1);
console.log('KEY2:', key2);
console.log('MATCH:', key1 === key2);
console.log('DIFFERENT:', key1 !== key3);
EOF

  # THEN cache keys should be consistent
  local output
  output=$(node /tmp/test-cache-key.js)

  if echo "$output" | grep -q "MATCH: true" && echo "$output" | grep -q "DIFFERENT: true"; then
    log_success "Cache key generation working correctly"
  else
    log_error "Cache key generation failed"
    return 1
  fi
}

test_cache_hit_miss() {
  log_step "GIVEN result cache with real Redis"

  # WHEN caching and retrieving results
  log_info "Testing cache hit/miss behavior..."

  # Test cache miss (key doesn't exist)
  local result_miss
  result_miss=$(docker exec "$REDIS_CONTAINER" redis-cli GET "cfn:agent:result:test:cache-miss-key" || echo "nil")

  if [[ "$result_miss" == "nil" || "$result_miss" == "(nil)" ]]; then
    log_success "Cache miss detected correctly"
  else
    log_error "Cache miss test failed"
    return 1
  fi

  # Test cache hit (set and get)
  docker exec "$REDIS_CONTAINER" redis-cli SET "cfn:agent:result:test:cache-hit-key" "cached-value" EX 3600 > /dev/null

  local result_hit
  result_hit=$(docker exec "$REDIS_CONTAINER" redis-cli GET "cfn:agent:result:test:cache-hit-key")

  if [[ "$result_hit" == "cached-value" ]]; then
    log_success "Cache hit detected correctly"
  else
    log_error "Cache hit test failed (got: $result_hit)"
    return 1
  fi
}

test_ttl_enforcement() {
  log_step "GIVEN cached result with TTL"

  # WHEN setting cache with short TTL
  log_info "Testing TTL enforcement..."

  # Set key with 2 second TTL
  docker exec "$REDIS_CONTAINER" redis-cli SET "cfn:agent:result:test:ttl-key" "expires-soon" EX 2 > /dev/null

  # Verify key exists
  local result_before
  result_before=$(docker exec "$REDIS_CONTAINER" redis-cli GET "cfn:agent:result:test:ttl-key")

  if [[ "$result_before" != "expires-soon" ]]; then
    log_error "TTL test setup failed (key not set)"
    return 1
  fi

  # Wait for TTL to expire
  sleep 3

  # THEN cached result should be invalidated
  local result_after
  result_after=$(docker exec "$REDIS_CONTAINER" redis-cli GET "cfn:agent:result:test:ttl-key" || echo "nil")

  if [[ "$result_after" == "nil" || "$result_after" == "(nil)" ]]; then
    log_success "TTL enforcement working correctly (key expired after 2s)"
  else
    log_error "TTL enforcement failed (key still exists: $result_after)"
    return 1
  fi
}

test_prometheus_metrics() {
  log_step "GIVEN cache operations"

  # WHEN collecting metrics
  log_info "Testing Prometheus metrics..."

  # Verify metrics are defined in result-cache.ts
  if grep -q "cfn_agent_cache_hits_total" "$PROJECT_ROOT/src/lib/result-cache.ts" && \
     grep -q "cfn_agent_cache_misses_total" "$PROJECT_ROOT/src/lib/result-cache.ts"; then
    log_success "Prometheus metrics configured"
  else
    log_error "Prometheus metrics not found"
    return 1
  fi
}

test_cache_hit_rate() {
  log_step "GIVEN cache statistics"

  # WHEN calculating hit rate
  log_info "Testing cache hit rate calculation..."

  # Create hit rate test script
  cat > /tmp/test-hit-rate.js << 'EOF'
function calculateHitRate(hits, misses) {
  const total = hits + misses;
  return total > 0 ? hits / total : 0;
}

const hitRate1 = calculateHitRate(80, 20); // 80% hit rate
const hitRate2 = calculateHitRate(90, 10); // 90% hit rate
const hitRate3 = calculateHitRate(50, 50); // 50% hit rate

console.log('HIT_RATE_80:', hitRate1);
console.log('HIT_RATE_90:', hitRate2);
console.log('HIT_RATE_50:', hitRate3);
console.log('TARGET_MET_80:', hitRate1 >= 0.8);
console.log('TARGET_MET_90:', hitRate2 >= 0.8);
console.log('TARGET_NOT_MET:', hitRate3 < 0.8);
EOF

  # THEN hit rate should be calculable
  local output
  output=$(node /tmp/test-hit-rate.js)

  if echo "$output" | grep -q "TARGET_MET_80: true" && \
     echo "$output" | grep -q "TARGET_MET_90: true" && \
     echo "$output" | grep -q "TARGET_NOT_MET: true"; then
    log_success "Cache hit rate calculation working correctly"
  else
    log_error "Cache hit rate calculation failed"
    return 1
  fi
}

test_cache_invalidation() {
  log_step "GIVEN cached results"

  # WHEN invalidating cache
  log_info "Testing cache invalidation..."

  # Set multiple cache entries
  docker exec "$REDIS_CONTAINER" redis-cli SET "cfn:agent:result:test:invalidate-1" "value1" > /dev/null
  docker exec "$REDIS_CONTAINER" redis-cli SET "cfn:agent:result:test:invalidate-2" "value2" > /dev/null

  # Verify entries exist
  local count_before
  count_before=$(docker exec "$REDIS_CONTAINER" redis-cli KEYS "cfn:agent:result:test:invalidate-*" | wc -l)

  if [[ "$count_before" -lt 2 ]]; then
    log_error "Cache invalidation test setup failed (entries not created)"
    return 1
  fi

  # Invalidate specific entry
  docker exec "$REDIS_CONTAINER" redis-cli DEL "cfn:agent:result:test:invalidate-1" > /dev/null

  # THEN cache should clear specific entry
  local result_deleted
  result_deleted=$(docker exec "$REDIS_CONTAINER" redis-cli GET "cfn:agent:result:test:invalidate-1" || echo "nil")

  local result_remaining
  result_remaining=$(docker exec "$REDIS_CONTAINER" redis-cli GET "cfn:agent:result:test:invalidate-2")

  if [[ "$result_deleted" == "nil" || "$result_deleted" == "(nil)" ]] && [[ "$result_remaining" == "value2" ]]; then
    log_success "Cache invalidation working correctly (selective deletion)"
  else
    log_error "Cache invalidation failed (deleted: $result_deleted, remaining: $result_remaining)"
    return 1
  fi

  # Cleanup test keys
  docker exec "$REDIS_CONTAINER" redis-cli DEL "cfn:agent:result:test:invalidate-2" > /dev/null
}

test_concurrent_cache_operations() {
  log_step "GIVEN concurrent cache operations"

  # WHEN multiple operations execute simultaneously
  log_info "Testing concurrent cache access..."

  # Perform 20 concurrent SET operations
  for i in {1..20}; do
    docker exec "$REDIS_CONTAINER" redis-cli SET "cfn:agent:result:test:concurrent-$i" "value-$i" EX 60 > /dev/null &
  done
  wait

  # Verify all keys were set
  local key_count
  key_count=$(docker exec "$REDIS_CONTAINER" redis-cli KEYS "cfn:agent:result:test:concurrent-*" | wc -l)

  # THEN all operations should succeed
  if [[ "$key_count" -eq 20 ]]; then
    log_success "Concurrent cache operations working correctly (20/20 keys set)"
  else
    log_error "Concurrent cache operations failed (expected 20, got $key_count)"
    return 1
  fi

  # Cleanup test keys
  docker exec "$REDIS_CONTAINER" redis-cli DEL $(docker exec "$REDIS_CONTAINER" redis-cli KEYS "cfn:agent:result:test:concurrent-*" | tr '\n' ' ') > /dev/null 2>&1 || true
}

# Run all tests
log_section "Agent Result Caching Tests (BUG #21 Compliant - Real Redis)"

test_setup_redis
test_cache_key_generation
test_cache_hit_miss
test_ttl_enforcement
test_prometheus_metrics
test_cache_hit_rate
test_cache_invalidation
test_concurrent_cache_operations

log_section "Result Caching Tests Complete"
log_success "All result caching tests passed"
