#!/usr/bin/env bash

# Test Suite for Kubernetes Manifests
# Validates all templates and example manifests

set -euo pipefail

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

# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
TEMPLATE_DIR="${PROJECT_DIR}/templates"
VALIDATOR="${PROJECT_DIR}/scripts/validate-k8s.sh"

# Test counters
TESTS_RUN=0
TESTS_PASSED=0
TESTS_FAILED=0

# Helper functions
print_header() {
    echo -e "\n${BLUE}========================================${NC}"
    echo -e "${BLUE}$1${NC}"
    echo -e "${BLUE}========================================${NC}\n"
}

print_success() {
    echo -e "${GREEN}✓ $1${NC}"
}

print_error() {
    echo -e "${RED}✗ $1${NC}"
}

print_info() {
    echo -e "${BLUE}ℹ $1${NC}"
}

# Test a single file
test_file() {
    local file="$1"
    local test_name="$2"

    ((TESTS_RUN++))

    echo ""
    print_info "Test: $test_name"
    echo "  File: $file"

    if [ ! -f "$file" ]; then
        print_error "File not found: $file"
        ((TESTS_FAILED++))
        return 1
    fi

    # Test 1: YAML syntax
    if ! kubectl apply --dry-run=client -f "$file" >/dev/null 2>&1; then
        print_error "YAML syntax validation failed"
        ((TESTS_FAILED++))
        return 1
    fi

    # Test 2: Kubernetes API validation
    if ! kubectl apply --dry-run=server -f "$file" >/dev/null 2>&1; then
        print_error "Kubernetes API validation failed"
        kubectl apply --dry-run=server -f "$file" 2>&1 | tail -5
        ((TESTS_FAILED++))
        return 1
    fi

    print_success "Test passed: $test_name"
    ((TESTS_PASSED++))
    return 0
}

# Test security context
test_security_context() {
    local file="$1"
    local test_name="$2 - Security Context"

    ((TESTS_RUN++))

    print_info "Test: $test_name"

    local errors=0

    # Check for required security settings (for Deployments/StatefulSets)
    if grep -q "kind: Deployment\|kind: StatefulSet" "$file"; then
        if ! grep -q "runAsNonRoot.*true" "$file"; then
            print_error "Missing: runAsNonRoot: true"
            ((errors++))
        fi

        if ! grep -q "readOnlyRootFilesystem.*true" "$file"; then
            print_error "Missing: readOnlyRootFilesystem: true"
            ((errors++))
        fi

        if ! grep -q "allowPrivilegeEscalation.*false" "$file"; then
            print_error "Missing: allowPrivilegeEscalation: false"
            ((errors++))
        fi

        if ! grep -q "drop:" "$file" || ! grep -q "- ALL" "$file"; then
            print_error "Missing: capabilities drop ALL"
            ((errors++))
        fi
    fi

    if [ $errors -eq 0 ]; then
        print_success "Test passed: $test_name"
        ((TESTS_PASSED++))
        return 0
    else
        print_error "Test failed: $test_name ($errors issues)"
        ((TESTS_FAILED++))
        return 1
    fi
}

# Test resource limits
test_resource_limits() {
    local file="$1"
    local test_name="$2 - Resource Limits"

    ((TESTS_RUN++))

    print_info "Test: $test_name"

    # Check for resource limits (for Deployments/StatefulSets)
    if grep -q "kind: Deployment\|kind: StatefulSet" "$file"; then
        if ! grep -q "resources:" "$file"; then
            print_error "Missing: resources definition"
            ((TESTS_FAILED++))
            return 1
        fi

        if ! grep -q "requests:" "$file"; then
            print_error "Missing: resource requests"
            ((TESTS_FAILED++))
            return 1
        fi

        if ! grep -q "limits:" "$file"; then
            print_error "Missing: resource limits"
            ((TESTS_FAILED++))
            return 1
        fi
    fi

    print_success "Test passed: $test_name"
    ((TESTS_PASSED++))
    return 0
}

# Test health probes
test_health_probes() {
    local file="$1"
    local test_name="$2 - Health Probes"

    ((TESTS_RUN++))

    print_info "Test: $test_name"

    local warnings=0

    # Check for health probes (for Deployments/StatefulSets)
    if grep -q "kind: Deployment\|kind: StatefulSet" "$file"; then
        if ! grep -q "livenessProbe:" "$file"; then
            print_error "Missing: livenessProbe"
            ((warnings++))
        fi

        if ! grep -q "readinessProbe:" "$file"; then
            print_error "Missing: readinessProbe"
            ((warnings++))
        fi
    fi

    if [ $warnings -eq 0 ]; then
        print_success "Test passed: $test_name"
        ((TESTS_PASSED++))
        return 0
    else
        print_error "Test failed: $test_name"
        ((TESTS_FAILED++))
        return 1
    fi
}

# Run all tests for a file
test_manifest() {
    local file="$1"
    local name="$2"

    print_header "Testing: $name"

    test_file "$file" "$name"
    test_security_context "$file" "$name"
    test_resource_limits "$file" "$name"
    test_health_probes "$file" "$name"
}

# Run all template tests
run_template_tests() {
    print_header "Testing Templates"

    # Deployment templates
    if [ -d "${TEMPLATE_DIR}/deployment" ]; then
        for file in "${TEMPLATE_DIR}/deployment"/*.yaml; do
            [ -f "$file" ] || continue
            test_manifest "$file" "Deployment: $(basename "$file")"
        done
    fi

    # Service templates
    if [ -d "${TEMPLATE_DIR}/service" ]; then
        for file in "${TEMPLATE_DIR}/service"/*.yaml; do
            [ -f "$file" ] || continue
            test_file "$file" "Service: $(basename "$file")"
        done
    fi

    # Ingress templates
    if [ -d "${TEMPLATE_DIR}/ingress" ]; then
        for file in "${TEMPLATE_DIR}/ingress"/*.yaml; do
            [ -f "$file" ] || continue
            test_file "$file" "Ingress: $(basename "$file")"
        done
    fi

    # ConfigMap templates
    if [ -d "${TEMPLATE_DIR}/configmap" ]; then
        for file in "${TEMPLATE_DIR}/configmap"/*.yaml; do
            [ -f "$file" ] || continue
            test_file "$file" "ConfigMap: $(basename "$file")"
        done
    fi

    # StatefulSet templates
    if [ -d "${TEMPLATE_DIR}/statefulset" ]; then
        for file in "${TEMPLATE_DIR}/statefulset"/*.yaml; do
            [ -f "$file" ] || continue
            test_manifest "$file" "StatefulSet: $(basename "$file")"
        done
    fi

    # Full app example
    if [ -d "${TEMPLATE_DIR}/full-app-example" ]; then
        for file in "${TEMPLATE_DIR}/full-app-example"/*.yaml; do
            [ -f "$file" ] || continue
            test_file "$file" "Full App: $(basename "$file")"
        done
    fi
}

# Test script functionality
test_scripts() {
    print_header "Testing Scripts"

    # Test validator script
    if [ -x "$VALIDATOR" ]; then
        print_info "Testing validator script..."
        if "$VALIDATOR" "${TEMPLATE_DIR}/deployment/web-app-deployment.yaml" >/dev/null 2>&1; then
            print_success "Validator script works"
            ((TESTS_PASSED++))
        else
            print_error "Validator script failed"
            ((TESTS_FAILED++))
        fi
        ((TESTS_RUN++))
    else
        print_error "Validator script not found or not executable"
        ((TESTS_FAILED++))
        ((TESTS_RUN++))
    fi
}

# Print summary
print_summary() {
    print_header "Test Summary"

    echo "Total tests: $TESTS_RUN"
    echo -e "${GREEN}Passed: $TESTS_PASSED${NC}"

    if [ $TESTS_FAILED -gt 0 ]; then
        echo -e "${RED}Failed: $TESTS_FAILED${NC}"
        echo ""
        print_error "Some tests failed"
        return 1
    else
        echo ""
        print_success "All tests passed!"
        return 0
    fi
}

# Check prerequisites
check_prerequisites() {
    print_header "Checking Prerequisites"

    if ! command -v kubectl >/dev/null 2>&1; then
        print_error "kubectl is not installed"
        exit 1
    fi

    print_success "kubectl is installed"

    # Try to connect to cluster (optional)
    if kubectl cluster-info >/dev/null 2>&1; then
        print_success "Connected to Kubernetes cluster"
    else
        print_info "Not connected to cluster (server-side validation will be skipped)"
    fi

    echo ""
}

# Main function
main() {
    print_header "Kubernetes Manifest Test Suite"

    check_prerequisites

    if [ $# -eq 0 ]; then
        # Run all tests
        run_template_tests
        test_scripts
    else
        # Run specific test
        case "$1" in
            deployment)
                for file in "${TEMPLATE_DIR}/deployment"/*.yaml; do
                    test_manifest "$file" "$(basename "$file")"
                done
                ;;
            service)
                for file in "${TEMPLATE_DIR}/service"/*.yaml; do
                    test_file "$file" "$(basename "$file")"
                done
                ;;
            statefulset)
                for file in "${TEMPLATE_DIR}/statefulset"/*.yaml; do
                    test_manifest "$file" "$(basename "$file")"
                done
                ;;
            *)
                print_error "Unknown test category: $1"
                echo "Available: deployment, service, statefulset"
                exit 1
                ;;
        esac
    fi

    print_summary
}

# Run main function
main "$@"
