#!/bin/bash

# Planner MCP Staging Deployment Script
# Production parity deployment for staging environment

set -euo pipefail

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
LOG_FILE="$PROJECT_ROOT/staging-deploy.log"

# Default values
DRY_RUN=false
SKIP_TESTS=false
SKIP_TERRAFORM=false
FORCE_DEPLOY=false
IMAGE_TAG=""
HEALTH_CHECK_TIMEOUT=300

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

# Logging functions
log() {
    echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE"
}

warn() {
    echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1" | tee -a "$LOG_FILE"
}

error() {
    echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" | tee -a "$LOG_FILE"
}

info() {
    echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] INFO:${NC} $1" | tee -a "$LOG_FILE"
}

check_prerequisites() {
    log "Checking staging deployment prerequisites..."
    
    local required_commands=("terraform" "kubectl" "aws" "docker" "kustomize" "jq")
    for cmd in "${required_commands[@]}"; do
        if ! command -v "$cmd" >/dev/null 2>&1; then
            error "Required command not found: $cmd"
            exit 1
        fi
    done
    
    # Check AWS credentials
    if ! aws sts get-caller-identity >/dev/null 2>&1; then
        error "AWS credentials not configured"
        exit 1
    fi
    
    # Verify staging context
    local current_context=$(kubectl config current-context 2>/dev/null || echo "none")
    if [[ ! "$current_context" =~ staging ]]; then
        warn "Current kubectl context '$current_context' doesn't appear to be staging"
    fi
    
    log "Prerequisites check passed ✓"
}

parse_arguments() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            --dry-run)
                DRY_RUN=true
                shift
                ;;
            --skip-tests)
                SKIP_TESTS=true
                shift
                ;;
            --skip-terraform)
                SKIP_TERRAFORM=true
                shift
                ;;
            --force)
                FORCE_DEPLOY=true
                shift
                ;;
            --image-tag)
                IMAGE_TAG="$2"
                shift 2
                ;;
            --health-timeout)
                HEALTH_CHECK_TIMEOUT="$2"
                shift 2
                ;;
            -h|--help)
                cat << EOF
Usage: $0 [OPTIONS]

Deploy Planner MCP to staging environment with production parity

Options:
    --dry-run              Show what would be deployed
    --skip-tests          Skip running tests
    --skip-terraform      Skip Terraform infrastructure deployment
    --force               Force deployment without confirmation
    --image-tag TAG       Specific image tag to deploy
    --health-timeout SEC  Health check timeout [default: 300]
    -h, --help            Show this help message

Examples:
    $0                        # Deploy staging with all checks
    $0 --dry-run              # Show deployment plan
    $0 --image-tag staging-v1.2.3  # Deploy specific image
    $0 --skip-terraform       # Deploy only application changes
EOF
                exit 0
                ;;
            *)
                error "Unknown option: $1"
                exit 1
                ;;
        esac
    done
    
    if [ -z "$IMAGE_TAG" ]; then
        IMAGE_TAG="staging-$(date +%Y%m%d-%H%M%S)-$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')"
        info "Generated image tag: $IMAGE_TAG"
    fi
}

run_staging_tests() {
    if [ "$SKIP_TESTS" = true ]; then
        warn "Skipping tests as requested"
        return
    fi
    
    log "Running staging deployment tests..."
    
    cd "$PROJECT_ROOT"
    
    # Install dependencies
    npm ci --production=false
    
    # Run linting with staging-specific rules
    info "Running code linting..."
    npm run lint
    
    # Run type checking
    info "Running type checking..."
    npm run typecheck
    
    # Validate staging configuration
    info "Validating staging configuration..."
    npm run validate-config:staging
    
    # Run unit tests
    info "Running unit tests..."
    npm test
    
    log "Staging tests completed ✓"
}

deploy_staging_infrastructure() {
    if [ "$SKIP_TERRAFORM" = true ]; then
        warn "Skipping Terraform infrastructure deployment"
        return
    fi
    
    log "Deploying staging infrastructure with production parity..."
    
    cd "$PROJECT_ROOT/infrastructure/terraform"
    
    # Initialize Terraform with staging backend
    info "Initializing Terraform for staging..."
    if [ "$DRY_RUN" = false ]; then
        terraform init -reconfigure \
            -backend-config="key=staging/terraform.tfstate"
        
        # Select staging workspace
        terraform workspace select staging 2>/dev/null || \
            terraform workspace new staging
    fi
    
    # Plan with staging variables
    info "Planning staging infrastructure..."
    local plan_file="/tmp/terraform-staging-plan"
    
    if [ "$DRY_RUN" = false ]; then
        terraform plan \
            -var-file="environments/staging.tfvars" \
            -var="image_tag=$IMAGE_TAG" \
            -out="$plan_file"
        
        # Show plan summary
        terraform show -no-color "$plan_file" | head -50
        
        # Confirm deployment unless forced
        if [ "$FORCE_DEPLOY" = false ]; then
            echo
            read -p "Apply staging infrastructure changes? (y/N): " -n 1 -r
            echo
            if [[ ! $REPLY =~ ^[Yy]$ ]]; then
                info "Infrastructure deployment cancelled by user"
                return
            fi
        fi
        
        # Apply changes
        info "Applying staging infrastructure..."
        terraform apply "$plan_file"
        
        # Update kubectl config for staging
        local cluster_name=$(terraform output -raw cluster_id)
        local region=$(terraform output -raw region)
        aws eks update-kubeconfig --region "$region" --name "$cluster_name" --alias staging
        
    else
        info "DRY RUN: Would deploy staging infrastructure"
    fi
    
    log "Staging infrastructure deployment completed ✓"
}

build_and_push_staging_images() {
    log "Building and pushing staging images..."
    
    cd "$PROJECT_ROOT"
    
    if [ "$DRY_RUN" = false ]; then
        # Build with staging configuration
        info "Building staging application image..."
        docker build \
            --build-arg NODE_ENV=staging \
            --build-arg BUILD_ENV=staging \
            -t "planner-mcp/api:$IMAGE_TAG" \
            -t "planner-mcp/api:staging-latest" \
            -f Dockerfile .
        
        # Build dashboard if exists
        if [ -f "Dockerfile.dashboard" ]; then
            docker build \
                --build-arg NODE_ENV=staging \
                -t "planner-mcp/dashboard:$IMAGE_TAG" \
                -t "planner-mcp/dashboard:staging-latest" \
                -f Dockerfile.dashboard .
        fi
        
        # Push to registry
        local account_id=$(aws sts get-caller-identity --query Account --output text)
        local region=$(aws configure get region || echo "us-east-1")
        local ecr_repo="$account_id.dkr.ecr.$region.amazonaws.com/planner-mcp"
        
        # Login to ECR
        aws ecr get-login-password --region "$region" | \
            docker login --username AWS --password-stdin "$ecr_repo"
        
        # Tag and push staging images
        docker tag "planner-mcp/api:$IMAGE_TAG" "$ecr_repo/api:$IMAGE_TAG"
        docker tag "planner-mcp/api:$IMAGE_TAG" "$ecr_repo/api:staging-latest"
        
        docker push "$ecr_repo/api:$IMAGE_TAG"
        docker push "$ecr_repo/api:staging-latest"
        
        if [ -f "Dockerfile.dashboard" ]; then
            docker tag "planner-mcp/dashboard:$IMAGE_TAG" "$ecr_repo/dashboard:$IMAGE_TAG"
            docker tag "planner-mcp/dashboard:$IMAGE_TAG" "$ecr_repo/dashboard:staging-latest"
            
            docker push "$ecr_repo/dashboard:$IMAGE_TAG"
            docker push "$ecr_repo/dashboard:staging-latest"
        fi
    else
        info "DRY RUN: Would build and push staging images"
    fi
    
    log "Staging image build completed ✓"
}

deploy_staging_application() {
    log "Deploying staging application with Kustomize..."
    
    cd "$PROJECT_ROOT"
    
    if [ "$DRY_RUN" = false ]; then
        # Create staging namespace
        info "Creating staging namespace..."
        kubectl create namespace planner-mcp-staging --dry-run=client -o yaml | kubectl apply -f -
        
        # Apply staging configuration with Kustomize
        info "Deploying staging application..."
        kustomize build infrastructure/kubernetes/staging | \
            sed "s/staging-latest/$IMAGE_TAG/g" | \
            kubectl apply -f -
        
        # Wait for rollout
        info "Waiting for staging deployment rollout..."
        kubectl rollout status deployment/staging-planner-mcp-api \
            --namespace=planner-mcp-staging \
            --timeout=300s
        
        kubectl rollout status deployment/staging-planner-mcp-dashboard \
            --namespace=planner-mcp-staging \
            --timeout=300s
            
    else
        info "DRY RUN: Would deploy staging application"
        kustomize build infrastructure/kubernetes/staging | \
            sed "s/staging-latest/$IMAGE_TAG/g" | \
            kubectl apply --dry-run=client -f -
    fi
    
    log "Staging application deployment completed ✓"
}

run_staging_health_checks() {
    log "Running staging health checks..."
    
    local namespace="planner-mcp-staging"
    local service_name="staging-planner-mcp-api-service"
    
    # Wait for pods to be ready
    info "Waiting for staging pods to be ready..."
    kubectl wait --for=condition=ready pod \
        --selector=app.kubernetes.io/name=planner-mcp-api \
        --namespace="$namespace" \
        --timeout=300s
    
    # Get staging URL
    local staging_url="https://staging.planner-mcp.example.com"
    
    # Wait for ingress to be ready
    info "Waiting for ingress to be ready..."
    sleep 30
    
    # Health check with retries
    local health_check_start=$(date +%s)
    local health_check_passed=false
    
    while [ $(($(date +%s) - health_check_start)) -lt $HEALTH_CHECK_TIMEOUT ]; do
        if curl -sf "$staging_url/health" >/dev/null 2>&1; then
            health_check_passed=true
            break
        fi
        info "Health check failed, retrying in 10 seconds..."
        sleep 10
    done
    
    if [ "$health_check_passed" = false ]; then
        error "Staging health checks failed after $HEALTH_CHECK_TIMEOUT seconds"
        exit 1
    fi
    
    log "Staging health checks passed ✓"
}

run_staging_smoke_tests() {
    log "Running staging smoke tests..."
    
    local staging_url="https://staging.planner-mcp.example.com"
    
    # Test basic API endpoints
    info "Testing staging API endpoints..."
    
    # Health endpoint
    if ! curl -sf "$staging_url/health" | jq -e '.status == "healthy"' >/dev/null; then
        error "Staging health endpoint test failed"
        return 1
    fi
    
    # Metrics endpoint
    if ! curl -sf "$staging_url/metrics" | grep -q "nodejs_version_info"; then
        error "Staging metrics endpoint test failed"
        return 1
    fi
    
    # API version endpoint
    if ! curl -sf "$staging_url/api/version" | jq -e '.version' >/dev/null; then
        error "Staging API version endpoint test failed"
        return 1
    fi
    
    # Test staging-specific features
    info "Testing staging-specific features..."
    
    # Debug endpoint (should be available in staging)
    if ! curl -sf "$staging_url/debug/info" >/dev/null 2>&1; then
        warn "Debug endpoint not accessible (expected in staging)"
    fi
    
    log "Staging smoke tests passed ✓"
}

validate_production_parity() {
    log "Validating production parity..."
    
    info "Checking infrastructure parity..."
    
    # Compare Terraform configurations
    cd "$PROJECT_ROOT/infrastructure/terraform"
    
    # Check that staging uses same modules as production
    local staging_modules=$(terraform show -json | jq -r '.values.root_module.child_modules[].address' 2>/dev/null | sort || echo "")
    info "Staging modules: $staging_modules"
    
    # Check Kubernetes resource parity
    info "Checking Kubernetes resource parity..."
    
    local staging_resources=$(kubectl get all -n planner-mcp-staging --no-headers | wc -l)
    info "Staging has $staging_resources Kubernetes resources"
    
    # Validate same security policies
    info "Validating security policy parity..."
    
    if kubectl get networkpolicies -n planner-mcp-staging >/dev/null 2>&1; then
        info "Network policies applied ✓"
    else
        warn "Network policies not found"
    fi
    
    if kubectl get podsecuritypolicy 2>/dev/null | grep -q staging; then
        info "Pod security policies applied ✓"
    else
        warn "Pod security policies not found (may be deprecated)"
    fi
    
    log "Production parity validation completed ✓"
}

print_staging_summary() {
    log "Staging deployment completed successfully!"
    echo
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo -e "${GREEN}Planner MCP Staging Deployment Summary${NC}"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo
    info "Environment: staging"
    info "Image Tag: $IMAGE_TAG"
    info "Deployment Time: $(date)"
    echo
    
    echo "🔗 Access Information:"
    echo "  • Staging URL: https://staging.planner-mcp.example.com"
    echo "  • API Documentation: https://staging.planner-mcp.example.com/api/docs"
    echo "  • Health Check: https://staging.planner-mcp.example.com/health"
    echo "  • Metrics: https://staging.planner-mcp.example.com/metrics"
    echo "  • Dashboard: https://staging.planner-mcp.example.com/dashboard"
    echo "  • Monitoring: https://monitoring.staging.planner-mcp.example.com"
    echo
    
    echo "📊 Staging Environment Info:"
    kubectl get pods -n planner-mcp-staging
    echo
    
    echo "🧪 Testing Information:"
    echo "  • Environment: staging with production parity"
    echo "  • Debug mode: enabled"
    echo "  • Development tools: enabled"
    echo "  • Log level: debug"
    echo "  • Data: isolated from production"
    echo
    
    echo "📋 Next Steps:"
    echo "  1. Run integration tests against staging"
    echo "  2. Validate feature functionality"
    echo "  3. Performance testing"
    echo "  4. User acceptance testing"
    echo "  5. Security validation"
    echo
    echo "🔧 Staging-Specific Features:"
    echo "  • Debug endpoints available"
    echo "  • Extended logging"
    echo "  • Development tools enabled"
    echo "  • Relaxed security for testing"
    echo
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
}

# Main execution
main() {
    echo -e "${BLUE}Planner MCP Staging Deployment${NC}"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    
    echo "Staging deployment started at $(date)" > "$LOG_FILE"
    
    parse_arguments "$@"
    check_prerequisites
    run_staging_tests
    build_and_push_staging_images
    deploy_staging_infrastructure
    deploy_staging_application
    run_staging_health_checks
    run_staging_smoke_tests
    validate_production_parity
    print_staging_summary
    
    log "Staging deployment completed successfully at $(date)"
}

# Error handling
trap 'error "Staging deployment failed on line $LINENO. Check $LOG_FILE for details."; exit 1' ERR

# Run main function
main "$@"