#!/bin/bash

# BZZZ SLURP Distributed Context Distribution - Deployment Script
# This script automates the deployment of the SLURP system to various environments

set -euo pipefail

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
DEPLOYMENT_DIR="${PROJECT_DIR}/deployments"
VERSION="${VERSION:-latest}"
ENVIRONMENT="${ENVIRONMENT:-development}"
REGISTRY="${REGISTRY:-registry.home.deepblack.cloud}"
NAMESPACE="${NAMESPACE:-bzzz-slurp}"
KUBECONFIG="${KUBECONFIG:-}"

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

# Logging functions
log() {
    echo -e "${BLUE}[INFO]${NC} $1" >&2
}

warn() {
    echo -e "${YELLOW}[WARN]${NC} $1" >&2
}

error() {
    echo -e "${RED}[ERROR]${NC} $1" >&2
    exit 1
}

success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1" >&2
}

# Help function
show_help() {
    cat << EOF
BZZZ SLURP Deployment Script

Usage: $0 [OPTIONS] COMMAND

Commands:
    build           Build Docker images
    push            Push images to registry
    deploy          Deploy to Kubernetes
    dev             Start development environment
    test            Run deployment tests
    cleanup         Clean up resources
    status          Show deployment status
    logs            Show service logs
    help            Show this help

Options:
    -e, --environment   Environment (development, staging, production) [default: development]
    -v, --version       Image version/tag [default: latest]
    -r, --registry      Docker registry [default: registry.home.deepblack.cloud]
    -n, --namespace     Kubernetes namespace [default: bzzz-slurp]
    -c, --kubeconfig    Kubeconfig file path
    -f, --force         Force operation without confirmation
    -h, --help          Show help

Examples:
    $0 build                           # Build images for development
    $0 -e production deploy            # Deploy to production
    $0 -v v1.2.3 push                  # Push specific version
    $0 dev                             # Start development environment
    $0 cleanup -e staging              # Cleanup staging environment

EOF
}

# Parse command line arguments
parse_args() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            -e|--environment)
                ENVIRONMENT="$2"
                shift 2
                ;;
            -v|--version)
                VERSION="$2"
                shift 2
                ;;
            -r|--registry)
                REGISTRY="$2"
                shift 2
                ;;
            -n|--namespace)
                NAMESPACE="$2"
                shift 2
                ;;
            -c|--kubeconfig)
                KUBECONFIG="$2"
                shift 2
                ;;
            -f|--force)
                FORCE=true
                shift
                ;;
            -h|--help)
                show_help
                exit 0
                ;;
            build|push|deploy|dev|test|cleanup|status|logs|help)
                COMMAND="$1"
                shift
                ;;
            *)
                error "Unknown option: $1"
                ;;
        esac
    done

    if [[ -z "${COMMAND:-}" ]]; then
        error "No command specified. Use --help for usage information."
    fi
}

# Environment validation
validate_environment() {
    case $ENVIRONMENT in
        development|staging|production)
            log "Environment: $ENVIRONMENT"
            ;;
        *)
            error "Invalid environment: $ENVIRONMENT. Must be development, staging, or production."
            ;;
    esac
}

# Check prerequisites
check_prerequisites() {
    local missing=()
    
    if ! command -v docker &> /dev/null; then
        missing+=("docker")
    fi
    
    if ! command -v kubectl &> /dev/null; then
        missing+=("kubectl")
    fi
    
    if ! command -v helm &> /dev/null && [[ "$COMMAND" == "deploy" ]]; then
        missing+=("helm")
    fi
    
    if [[ ${#missing[@]} -ne 0 ]]; then
        error "Missing required tools: ${missing[*]}"
    fi
    
    # Check Docker daemon
    if ! docker info &> /dev/null; then
        error "Docker daemon is not running"
    fi
    
    # Check Kubernetes connectivity for relevant commands
    if [[ "$COMMAND" =~ ^(deploy|status|logs|cleanup)$ ]]; then
        if [[ -n "$KUBECONFIG" ]]; then
            export KUBECONFIG="$KUBECONFIG"
        fi
        
        if ! kubectl cluster-info &> /dev/null; then
            error "Cannot connect to Kubernetes cluster"
        fi
        
        log "Connected to Kubernetes cluster: $(kubectl config current-context)"
    fi
}

# Build Docker images
build_images() {
    log "Building SLURP Docker images..."
    
    local images=(
        "slurp-coordinator:Dockerfile.slurp-coordinator"
        "slurp-distributor:Dockerfile.slurp-distributor"
    )
    
    cd "$PROJECT_DIR"
    
    for image_def in "${images[@]}"; do
        IFS=':' read -r image dockerfile <<< "$image_def"
        local full_image="$REGISTRY/bzzz/$image:$VERSION"
        
        log "Building $full_image..."
        docker build \
            -f "$DEPLOYMENT_DIR/docker/$dockerfile" \
            -t "$full_image" \
            --build-arg VERSION="$VERSION" \
            --build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
            --build-arg VCS_REF="$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')" \
            .
        
        success "Built $full_image"
    done
}

# Push images to registry
push_images() {
    log "Pushing images to registry..."
    
    local images=(
        "$REGISTRY/bzzz/slurp-coordinator:$VERSION"
        "$REGISTRY/bzzz/slurp-distributor:$VERSION"
    )
    
    for image in "${images[@]}"; do
        log "Pushing $image..."
        docker push "$image"
        success "Pushed $image"
    done
}

# Deploy to Kubernetes
deploy_k8s() {
    log "Deploying SLURP to Kubernetes environment: $ENVIRONMENT"
    
    # Create namespace if it doesn't exist
    if ! kubectl get namespace "$NAMESPACE" &> /dev/null; then
        log "Creating namespace $NAMESPACE..."
        kubectl apply -f "$DEPLOYMENT_DIR/kubernetes/namespace.yaml"
    fi
    
    # Apply configurations
    log "Applying configuration..."
    envsubst < "$DEPLOYMENT_DIR/kubernetes/configmap.yaml" | kubectl apply -f -
    
    # Deploy coordinator
    log "Deploying coordinator..."
    envsubst < "$DEPLOYMENT_DIR/kubernetes/coordinator-deployment.yaml" | kubectl apply -f -
    
    # Deploy distributors
    log "Deploying distributors..."
    envsubst < "$DEPLOYMENT_DIR/kubernetes/distributor-statefulset.yaml" | kubectl apply -f -
    
    # Apply ingress
    if [[ "$ENVIRONMENT" != "development" ]]; then
        log "Applying ingress..."
        envsubst < "$DEPLOYMENT_DIR/kubernetes/ingress.yaml" | kubectl apply -f -
    fi
    
    # Wait for deployment to be ready
    log "Waiting for deployments to be ready..."
    kubectl wait --for=condition=available --timeout=300s deployment/slurp-coordinator -n "$NAMESPACE"
    kubectl wait --for=condition=ready --timeout=300s statefulset/slurp-distributor -n "$NAMESPACE"
    
    success "Deployment completed successfully!"
    
    # Show status
    kubectl get pods -n "$NAMESPACE"
}

# Start development environment
start_dev() {
    log "Starting development environment..."
    
    cd "$DEPLOYMENT_DIR/docker"
    
    # Build images if they don't exist
    if ! docker images | grep -q "slurp-coordinator"; then
        log "Building development images..."
        REGISTRY="localhost" VERSION="dev" build_images
    fi
    
    # Start services
    log "Starting Docker Compose services..."
    docker-compose up -d
    
    # Wait for services
    log "Waiting for services to be ready..."
    sleep 10
    
    # Show status
    docker-compose ps
    
    success "Development environment is ready!"
    log "Services available at:"
    log "  - Coordinator API: http://localhost:8080"
    log "  - Distributor APIs: http://localhost:8081, http://localhost:8082, http://localhost:8083"
    log "  - Prometheus: http://localhost:9090"
    log "  - Grafana: http://localhost:3000 (admin/admin123)"
    log "  - Jaeger: http://localhost:16686"
    log "  - Kibana: http://localhost:5601"
}

# Run tests
run_tests() {
    log "Running deployment tests..."
    
    case $ENVIRONMENT in
        development)
            test_docker_compose
            ;;
        staging|production)
            test_kubernetes
            ;;
    esac
}

# Test Docker Compose deployment
test_docker_compose() {
    local services=("slurp-coordinator" "slurp-distributor-01" "slurp-distributor-02" "slurp-distributor-03")
    
    for service in "${services[@]}"; do
        log "Testing $service..."
        
        # Check if container is running
        if ! docker-compose ps | grep -q "$service.*Up"; then
            error "$service is not running"
        fi
        
        # Check health endpoint (assuming port 8080 for coordinator, 8081+ for distributors)
        local port=8080
        if [[ "$service" =~ distributor-0[1-9] ]]; then
            port=$((8080 + ${service: -1}))
        fi
        
        if ! curl -f -s "http://localhost:$port/health" > /dev/null; then
            error "$service health check failed"
        fi
        
        success "$service is healthy"
    done
}

# Test Kubernetes deployment
test_kubernetes() {
    log "Testing Kubernetes deployment..."
    
    # Check pod status
    if ! kubectl get pods -n "$NAMESPACE" | grep -q "Running"; then
        error "No running pods found"
    fi
    
    # Test coordinator endpoint
    log "Testing coordinator endpoint..."
    kubectl port-forward -n "$NAMESPACE" service/slurp-coordinator 8080:8080 &
    local pf_pid=$!
    
    sleep 5
    
    if curl -f -s "http://localhost:8080/health" > /dev/null; then
        success "Coordinator health check passed"
    else
        error "Coordinator health check failed"
    fi
    
    kill $pf_pid 2>/dev/null || true
    
    # Test distributor endpoints
    log "Testing distributor endpoints..."
    kubectl port-forward -n "$NAMESPACE" service/slurp-distributor 8080:8080 &
    pf_pid=$!
    
    sleep 5
    
    if curl -f -s "http://localhost:8080/health" > /dev/null; then
        success "Distributor health check passed"
    else
        error "Distributor health check failed"
    fi
    
    kill $pf_pid 2>/dev/null || true
    
    success "All tests passed!"
}

# Show deployment status
show_status() {
    case $ENVIRONMENT in
        development)
            log "Docker Compose Status:"
            cd "$DEPLOYMENT_DIR/docker"
            docker-compose ps
            ;;
        staging|production)
            log "Kubernetes Status:"
            kubectl get all -n "$NAMESPACE"
            echo
            log "Pod Details:"
            kubectl describe pods -n "$NAMESPACE"
            ;;
    esac
}

# Show service logs
show_logs() {
    case $ENVIRONMENT in
        development)
            cd "$DEPLOYMENT_DIR/docker"
            docker-compose logs -f
            ;;
        staging|production)
            kubectl logs -f -l app.kubernetes.io/part-of=bzzz-slurp -n "$NAMESPACE"
            ;;
    esac
}

# Cleanup resources
cleanup() {
    if [[ "${FORCE:-}" != "true" ]]; then
        read -p "Are you sure you want to cleanup $ENVIRONMENT environment? (y/N): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            log "Cleanup cancelled"
            exit 0
        fi
    fi
    
    case $ENVIRONMENT in
        development)
            log "Stopping Docker Compose services..."
            cd "$DEPLOYMENT_DIR/docker"
            docker-compose down -v
            docker-compose rm -f
            success "Development environment cleaned up"
            ;;
        staging|production)
            log "Deleting Kubernetes resources..."
            kubectl delete namespace "$NAMESPACE" --ignore-not-found=true
            success "Kubernetes resources cleaned up"
            ;;
    esac
}

# Export environment variables for envsubst
export_env_vars() {
    export REGISTRY
    export VERSION
    export NAMESPACE
    export ENVIRONMENT
}

# Main function
main() {
    parse_args "$@"
    validate_environment
    check_prerequisites
    export_env_vars
    
    case $COMMAND in
        build)
            build_images
            ;;
        push)
            push_images
            ;;
        deploy)
            if [[ "$ENVIRONMENT" == "development" ]]; then
                error "Use 'dev' command for development deployment"
            fi
            deploy_k8s
            ;;
        dev)
            start_dev
            ;;
        test)
            run_tests
            ;;
        status)
            show_status
            ;;
        logs)
            show_logs
            ;;
        cleanup)
            cleanup
            ;;
        help)
            show_help
            ;;
        *)
            error "Unknown command: $COMMAND"
            ;;
    esac
}

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