#!/bin/bash
# Docker Compose Validation Script
# Validates Docker Compose files before commit to prevent broken deployments

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

# Function to log messages
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Check if Docker is available
if ! command -v docker &> /dev/null; then
    log_warn "Docker not found. Skipping Docker Compose validation."
    exit 0
fi

# Check if docker-compose is available
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
    log_warn "Docker Compose not found. Skipping validation."
    exit 0
fi

# Determine docker-compose command
if command -v docker-compose &> /dev/null; then
    COMPOSE_CMD="docker-compose"
else
    COMPOSE_CMD="docker compose"
fi

# Validation function
validate_compose_file() {
    local file="$1"
    local filename=$(basename "$file")

    # Skip non-Docker Compose files
    if [[ "$file" == *".pre-commit-config.yaml" ]] || \
       [[ "$file" == *".yamllint" ]] || \
       [[ "$file" == *".gitea/workflows/"* ]] || \
       [[ "$file" == *"secret_key.yaml" ]] || \
       [[ "$file" == *"config.yml" ]] || \
       [[ "$file" == *"snmp.yml" ]] || \
       [[ "$file" == *"homeserver.yaml" ]]; then
        log_info "Skipping non-Docker Compose file: $file"
        return 0
    fi

    # Skip files that don't have a 'services:' block (not Docker Compose files)
    if ! grep -q "^services:" "$file" 2>/dev/null; then
        log_info "Skipping non-Docker Compose file: $file"
        return 0
    fi

    # Skip compose files with env_file references to files that don't exist locally
    if grep -q "env_file:" "$file" 2>/dev/null; then
        local compose_dir
        compose_dir=$(dirname "$file")
        local missing_env=0
        while IFS= read -r env_line; do
            local env_file
            env_file=$(echo "$env_line" | sed 's/.*-\s*//' | tr -d ' "')
            if [[ -n "$env_file" ]] && [[ "$env_file" != "~" ]] && \
               [[ ! -f "$compose_dir/$env_file" ]]; then
                missing_env=1
                break
            fi
        done < <(grep -A1 "env_file:" "$file" | grep "^.*-")
        if [[ $missing_env -eq 1 ]]; then
            log_warn "$file: Skipping validation - missing env_file dependencies"
            return 0
        fi
    fi

    log_info "Validating $file"

    # Check if file exists and is readable
    if [[ ! -r "$file" ]]; then
        log_error "Cannot read file: $file"
        return 1
    fi

    # Skip if not a compose file
    if [[ ! "$filename" =~ \.(yml|yaml)$ ]]; then
        log_info "Skipping non-YAML file: $file"
        return 0
    fi

    # Skip certain directories and files
    if [[ "$file" =~ ^(archive/|ansible/|docs/|\.git/) ]]; then
        log_info "Skipping excluded path: $file"
        return 0
    fi

    # Validate Docker Compose syntax
    if ! $COMPOSE_CMD -f "$file" config > /dev/null 2>&1; then
        log_error "Docker Compose validation failed for: $file"
        log_error "Run '$COMPOSE_CMD -f $file config' to see detailed errors"
        return 1
    fi

    # Check for common issues
    local warnings=0

    # Check for missing version (Docker Compose v2 doesn't require it, but good practice)
    if ! grep -q "^version:" "$file" 2>/dev/null; then
        log_warn "$file: Consider adding 'version' field for clarity"
        ((warnings++))
    fi

    # Check for hardcoded localhost references (should use service names)
    if grep -q "localhost\|127\.0\.0\.1" "$file" 2>/dev/null; then
        log_warn "$file: Found localhost references - consider using service names"
        ((warnings++))
    fi

    # Check for missing restart policies on long-running services
    if grep -q "image:" "$file" && ! grep -q "restart:" "$file" 2>/dev/null; then
        log_warn "$file: Consider adding restart policy for production services"
        ((warnings++))
    fi

    if [[ $warnings -eq 0 ]]; then
        log_info "✓ $file passed validation"
    else
        log_info "✓ $file passed validation with $warnings warnings"
    fi

    return 0
}

# Main execution
main() {
    local exit_code=0
    local files_processed=0

    # If no arguments provided, validate all YAML files
    if [[ $# -eq 0 ]]; then
        log_info "No files specified, validating all Docker Compose files..."
        while IFS= read -r -d '' file; do
            ((files_processed++))
            if ! validate_compose_file "$file"; then
                exit_code=1
            fi
        done < <(find . -name "*.yml" -o -name "*.yaml" -print0 | grep -zv -E '^(archive/|ansible/|docs/|\.git/)')
    else
        # Validate specified files
        for file in "$@"; do
            ((files_processed++))
            if ! validate_compose_file "$file"; then
                exit_code=1
            fi
        done
    fi

    if [[ $exit_code -eq 0 ]]; then
        log_info "All $files_processed files passed validation!"
    else
        log_error "Some files failed validation. Please fix the errors before committing."
    fi

    exit $exit_code
}

# Run main function with all arguments
main "$@"
