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

# Brief: Focused integration test for CrowdSec startup in Charon container
# This test verifies that CrowdSec can start successfully without the fatal
# "no datasource enabled" error, which indicates a missing or empty acquis.yaml.
#
# Steps:
# 1. Build charon:local image if not present
# 2. Start container with CERBERUS_SECURITY_CROWDSEC_MODE=local
# 3. Wait for initialization (30 seconds)
# 4. Check for fatal errors
# 5. Check LAPI health
# 6. Check acquisition config
# 7. Check installed parsers/scenarios
# 8. Output clear PASS/FAIL results
# 9. Clean up container

# Ensure we operate from repo root
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$PROJECT_ROOT"

# ============================================================================
# Configuration
# ============================================================================
CONTAINER_NAME="charon-crowdsec-startup-test"
INIT_WAIT_SECONDS=30

# Use unique ports to avoid conflicts with running Charon
API_PORT=8580
HTTP_PORT=8480
HTTPS_PORT=8443

# ============================================================================
# Colors for output
# ============================================================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_test() { echo -e "${BLUE}[TEST]${NC} $1"; }

# ============================================================================
# Test counters
# ============================================================================
PASSED=0
FAILED=0
CRITICAL_FAILURE=false

pass_test() {
    PASSED=$((PASSED + 1))
    echo -e "  ${GREEN}✓ PASS${NC}"
}

fail_test() {
    FAILED=$((FAILED + 1))
    echo -e "  ${RED}✗ FAIL${NC}: $1"
}

critical_fail() {
    FAILED=$((FAILED + 1))
    CRITICAL_FAILURE=true
    echo -e "  ${RED}✗ CRITICAL FAIL${NC}: $1"
}

# ============================================================================
# Cleanup function
# ============================================================================
cleanup() {
    log_info "Cleaning up test resources..."
    docker rm -f ${CONTAINER_NAME} 2>/dev/null || true
    # Clean up test volumes
    docker volume rm charon_crowdsec_startup_data 2>/dev/null || true
    docker volume rm caddy_crowdsec_startup_data 2>/dev/null || true
    docker volume rm caddy_crowdsec_startup_config 2>/dev/null || true
    log_info "Cleanup complete"
}

# Set up trap for cleanup on exit (success or failure)
trap cleanup EXIT

echo "=============================================="
echo "=== CrowdSec Startup Integration Test ==="
echo "=============================================="
echo ""

# ============================================================================
# Step 1: Check dependencies
# ============================================================================
log_info "Checking dependencies..."

if ! command -v docker >/dev/null 2>&1; then
    log_error "docker is not available; aborting"
    exit 1
fi

# ============================================================================
# Step 2: Build image if needed
# ============================================================================
if ! docker image inspect charon:local >/dev/null 2>&1; then
    log_info "Building charon:local image..."
    docker build -t charon:local .
else
    log_info "Using existing charon:local image"
fi

# ============================================================================
# Step 3: Clean up any existing container
# ============================================================================
log_info "Stopping any existing test containers..."
docker rm -f ${CONTAINER_NAME} 2>/dev/null || true

# ============================================================================
# Step 4: Start container with CrowdSec enabled
# ============================================================================
log_info "Starting Charon container with CERBERUS_SECURITY_CROWDSEC_MODE=local..."

docker run -d --name ${CONTAINER_NAME} \
    -p ${HTTP_PORT}:80 \
    -p ${HTTPS_PORT}:443 \
    -p ${API_PORT}:8080 \
    -e CHARON_ENV=development \
    -e CHARON_DEBUG=1 \
    -e FEATURE_CERBERUS_ENABLED=true \
    -e CERBERUS_SECURITY_CROWDSEC_MODE=local \
    -v charon_crowdsec_startup_data:/app/data \
    -v caddy_crowdsec_startup_data:/data \
    -v caddy_crowdsec_startup_config:/config \
    charon:local

log_info "Waiting ${INIT_WAIT_SECONDS} seconds for CrowdSec to initialize..."
sleep ${INIT_WAIT_SECONDS}

echo ""
echo "=============================================="
echo "=== Running CrowdSec Startup Checks ==="
echo "=============================================="
echo ""

# ============================================================================
# Test 1: Check for fatal "no datasource enabled" error
# ============================================================================
log_test "Check 1: No fatal 'no datasource enabled' error"

FATAL_ERROR_COUNT=$(docker logs ${CONTAINER_NAME} 2>&1 | grep -c "no datasource enabled" || echo "0")

if [ "$FATAL_ERROR_COUNT" -ge 1 ]; then
    critical_fail "Found fatal 'no datasource enabled' error - acquis.yaml is missing or empty"
    echo ""
    echo "=== Relevant Container Logs ==="
    docker logs ${CONTAINER_NAME} 2>&1 | grep -i "crowdsec\|acquis\|datasource\|fatal" | tail -20
    echo ""
else
    log_info "  No 'no datasource enabled' fatal error found"
    pass_test
fi

# ============================================================================
# Test 2: Check LAPI health endpoint
# ============================================================================
log_test "Check 2: CrowdSec LAPI health (127.0.0.1:8085/health)"

# Use docker exec to check LAPI health from inside the container
LAPI_HEALTH=$(docker exec ${CONTAINER_NAME} wget -q -O- http://127.0.0.1:8085/health 2>/dev/null || echo "FAILED")

if [ "$LAPI_HEALTH" != "FAILED" ] && [ -n "$LAPI_HEALTH" ]; then
    log_info "  LAPI is healthy"
    log_info "  Response: $LAPI_HEALTH"
    pass_test
else
    fail_test "LAPI health check failed (port 8085 not responding)"
    # This could be expected if CrowdSec binary is not in the image
    log_warn "  This may be expected if CrowdSec binary is not installed"
fi

# ============================================================================
# Test 3: Check acquisition config exists and has datasource
# ============================================================================
log_test "Check 3: Acquisition config exists and has 'source:' definition"

ACQUIS_CONTENT=$(docker exec ${CONTAINER_NAME} cat /etc/crowdsec/acquis.yaml 2>/dev/null || echo "")

if [ -z "$ACQUIS_CONTENT" ]; then
    critical_fail "acquis.yaml does not exist or is empty"
else
    SOURCE_COUNT=$(echo "$ACQUIS_CONTENT" | grep -c "source:" || echo "0")
    if [ "$SOURCE_COUNT" -ge 1 ]; then
        log_info "  acquis.yaml found with $SOURCE_COUNT datasource definition(s)"
        echo ""
        echo "  --- acquis.yaml content ---"
        echo "$ACQUIS_CONTENT" | head -15 | sed 's/^/  /'
        echo "  ---"
        echo ""
        pass_test
    else
        critical_fail "acquis.yaml exists but has no 'source:' definition"
        echo "  Content:"
        echo "$ACQUIS_CONTENT" | head -10 | sed 's/^/    /'
    fi
fi

# ============================================================================
# Test 4: Check for installed parsers
# ============================================================================
log_test "Check 4: Installed parsers (at least one expected)"

PARSERS_OUTPUT=$(docker exec ${CONTAINER_NAME} cscli parsers list 2>&1 || echo "CSCLI_NOT_AVAILABLE")

if [ "$PARSERS_OUTPUT" = "CSCLI_NOT_AVAILABLE" ]; then
    log_warn "  cscli command not available - cannot check parsers"
    # Not a failure - cscli may not be in the image
    pass_test
elif echo "$PARSERS_OUTPUT" | grep -q "PARSERS"; then
    # cscli output includes "PARSERS" header
    PARSER_COUNT=$(echo "$PARSERS_OUTPUT" | grep -c "✔" || echo "0")
    if [ "$PARSER_COUNT" -ge 1 ]; then
        log_info "  Found $PARSER_COUNT installed parser(s)"
        echo "$PARSERS_OUTPUT" | head -10 | sed 's/^/    /'
        pass_test
    else
        log_warn "  No parsers installed (CrowdSec may not parse logs correctly)"
        pass_test
    fi
else
    log_warn "  Unexpected cscli output"
    echo "$PARSERS_OUTPUT" | head -5 | sed 's/^/    /'
    pass_test
fi

# ============================================================================
# Test 5: Check for installed scenarios
# ============================================================================
log_test "Check 5: Installed scenarios (at least one expected)"

SCENARIOS_OUTPUT=$(docker exec ${CONTAINER_NAME} cscli scenarios list 2>&1 || echo "CSCLI_NOT_AVAILABLE")

if [ "$SCENARIOS_OUTPUT" = "CSCLI_NOT_AVAILABLE" ]; then
    log_warn "  cscli command not available - cannot check scenarios"
    pass_test
elif echo "$SCENARIOS_OUTPUT" | grep -q "SCENARIOS"; then
    SCENARIO_COUNT=$(echo "$SCENARIOS_OUTPUT" | grep -c "✔" || echo "0")
    if [ "$SCENARIO_COUNT" -ge 1 ]; then
        log_info "  Found $SCENARIO_COUNT installed scenario(s)"
        echo "$SCENARIOS_OUTPUT" | head -10 | sed 's/^/    /'
        pass_test
    else
        log_warn "  No scenarios installed (CrowdSec may not detect attacks)"
        pass_test
    fi
else
    log_warn "  Unexpected cscli output"
    echo "$SCENARIOS_OUTPUT" | head -5 | sed 's/^/    /'
    pass_test
fi

# ============================================================================
# Test 6: Check CrowdSec process is running (if expected)
# ============================================================================
log_test "Check 6: CrowdSec process running"

CROWDSEC_PID=$(docker exec ${CONTAINER_NAME} pgrep -f "crowdsec" 2>/dev/null || echo "")

if [ -n "$CROWDSEC_PID" ]; then
    log_info "  CrowdSec process is running (PID: $CROWDSEC_PID)"
    pass_test
else
    log_warn "  CrowdSec process not found (may not be installed or may have crashed)"
    # Check if crowdsec binary exists
    CROWDSEC_BIN=$(docker exec ${CONTAINER_NAME} which crowdsec 2>/dev/null || echo "")
    if [ -z "$CROWDSEC_BIN" ]; then
        log_warn "  crowdsec binary not found in container"
    fi
    pass_test
fi

# ============================================================================
# Show last container logs for debugging
# ============================================================================
echo ""
echo "=== Container Logs (last 30 lines) ==="
docker logs ${CONTAINER_NAME} 2>&1 | tail -30
echo ""

# ============================================================================
# Results Summary
# ============================================================================
echo ""
echo "=============================================="
echo "=== CrowdSec Startup Test Results ==="
echo "=============================================="
echo ""
echo -e "  ${GREEN}Passed:${NC}  $PASSED"
echo -e "  ${RED}Failed:${NC}  $FAILED"
echo ""

if [ "$CRITICAL_FAILURE" = "true" ]; then
    echo -e "${RED}=============================================="
    echo "=== CRITICAL: CrowdSec STARTUP BROKEN ==="
    echo "==============================================${NC}"
    echo ""
    echo "CrowdSec cannot start properly. The 'no datasource enabled' error"
    echo "indicates that acquis.yaml is missing or has no datasource definitions."
    echo ""
    echo "To fix:"
    echo "  1. Ensure configs/crowdsec/acquis.yaml exists with 'source:' definition"
    echo "  2. Ensure Dockerfile copies acquis.yaml to /etc/crowdsec.dist/"
    echo "  3. Ensure docker-entrypoint.sh copies configs to /etc/crowdsec/"
    echo ""
    exit 1
fi

if [ $FAILED -eq 0 ]; then
    echo "=============================================="
    echo "=== ALL CROWDSEC STARTUP TESTS PASSED ==="
    echo "=============================================="
    echo ""
    exit 0
else
    echo "=============================================="
    echo "=== CROWDSEC STARTUP TESTS FAILED ==="
    echo "=============================================="
    echo ""
    exit 1
fi
