#!/bin/bash

#############################################################################
# CF Deployer - Simple Chunked Upload Deployment Script (Through Java proxy)
#
# This script deploys a Java application to Cloud Foundry using chunked
# uploads to bypass nginx size restrictions and async deployment to avoid
# timeout issues.
#
# USE THIS SCRIPT WHEN:
#   - You deploy through a Java proxy that adds certificates/headers
#   - The proxy reads request body as @RequestBody String
#   - You need to send chunks as Base64-encoded text
#
# For direct nginx deployments with cert/key, use: deploy-chunked.sh
# For detailed documentation, see: DEPLOYMENT_SCRIPTS.md
#
# TECHNICAL NOTES:
#   - Chunks are Base64-encoded to prevent corruption in the Java proxy
#   - Query parameters are sent in URL (not form fields)
#   - Uses Spring Boot endpoint: POST /upload/chunk (Content-Type: text/plain)
#
# Usage:
#   ./deploy-chunked-simple.sh
#
# Configuration:
#   Edit the variables below to match your environment
#############################################################################

set -e  # Exit on error

#############################################################################
# CONFIGURATION - Update these values for your deployment
#############################################################################

# API endpoint
API_BASE="http://localhost:8080/api/cf"

# Files to deploy
JAR_FILE="./app.jar"
MANIFEST_FILE="./manifest.yml"

# Chunk size (bytes)
# Recommended: 1MB (1048576) for Tanzu with memory constraints
# Options: 512KB (524288), 1MB (1048576), 2MB (2097152), 5MB (5242880)
CHUNK_SIZE=1048576  # 1MB

# Cloud Foundry configuration
CF_API_ENDPOINT="https://api.cf.example.com"
CF_USERNAME="your-username"
CF_PASSWORD="your-password"
CF_ORGANIZATION="your-org"
CF_SPACE="your-space"
CF_APP_NAME="your-app"
CF_SKIP_SSL="false"  # Use "true" for self-signed certificates

# Polling configuration
POLL_INTERVAL=5   # seconds between status checks
MAX_WAIT=600      # maximum wait time in seconds (10 minutes)

# Debug mode (set to "true" to see curl commands and responses)
DEBUG_MODE="false"

#############################################################################
# SCRIPT - Do not modify below this line
#############################################################################

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

# Helper functions
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

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

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

# Check if files exist
if [ ! -f "$JAR_FILE" ]; then
    log_error "JAR file not found: $JAR_FILE"
    exit 1
fi

if [ ! -f "$MANIFEST_FILE" ]; then
    log_error "Manifest file not found: $MANIFEST_FILE"
    exit 1
fi

# Check if curl is available
if ! command -v curl &> /dev/null; then
    log_error "curl is not installed. Please install curl to use this script."
    exit 1
fi

# Build CF configuration JSON
CF_CONFIG=$(cat <<EOF
{
  "apiEndpoint": "$CF_API_ENDPOINT",
  "username": "$CF_USERNAME",
  "password": "$CF_PASSWORD",
  "organization": "$CF_ORGANIZATION",
  "space": "$CF_SPACE",
  "appName": "$CF_APP_NAME",
  "skipSslValidation": $CF_SKIP_SSL
}
EOF
)

log_info "Starting deployment of $CF_APP_NAME to Cloud Foundry"
log_info "JAR: $JAR_FILE"
log_info "Manifest: $MANIFEST_FILE"
log_info "Chunk size: $CHUNK_SIZE bytes ($(($CHUNK_SIZE / 1024))KB)"
echo ""

#############################################################################
# STEP 1: Initialize Upload Session
#############################################################################
log_info "Step 1/5: Initializing upload session..."

# Debug mode output
if [ "$DEBUG_MODE" = "true" ]; then
    echo "DEBUG: API_BASE = $API_BASE"
    echo "DEBUG: Request JSON:"
    echo "$CF_CONFIG"
fi

# Write JSON to temporary file to avoid quote escaping issues
TEMP_JSON=$(mktemp)
echo "$CF_CONFIG" > "$TEMP_JSON"

# Execute curl command
if [ "$DEBUG_MODE" = "true" ]; then
    INIT_RESPONSE=$(curl -v -X POST "$API_BASE/upload/init" \
      -H "Content-Type: application/json" \
      -d @"$TEMP_JSON")
else
    INIT_RESPONSE=$(curl -s -X POST "$API_BASE/upload/init" \
      -H "Content-Type: application/json" \
      -d @"$TEMP_JSON")
fi

# Clean up temporary file
rm -f "$TEMP_JSON"

CURL_EXIT_CODE=$?
if [ "$DEBUG_MODE" = "true" ]; then
    echo "DEBUG: Curl exit code: $CURL_EXIT_CODE"
    echo "DEBUG: Response:"
    echo "$INIT_RESPONSE"
fi

if [ $CURL_EXIT_CODE -ne 0 ]; then
    log_error "Failed to initialize upload session (curl exit code: $CURL_EXIT_CODE)"
    echo "$INIT_RESPONSE"
    exit 1
fi

# Debug output
if [ -z "$INIT_RESPONSE" ]; then
    log_error "Empty response from server"
    exit 1
fi

SESSION_ID=$(echo "$INIT_RESPONSE" | grep -o '"uploadSessionId":"[^"]*' | cut -d'"' -f4)

if [ -z "$SESSION_ID" ]; then
    log_error "Failed to get session ID from response:"
    echo "$INIT_RESPONSE"
    exit 1
fi

log_success "Upload session created: $SESSION_ID"
echo ""

#############################################################################
# FUNCTION: Upload file in chunks
#############################################################################
upload_file_in_chunks() {
  local file_path=$1
  local file_type=$2
  local file_name=$(basename "$file_path")

  # Get file size (cross-platform)
  if [[ "$OSTYPE" == "darwin"* ]]; then
    local file_size=$(stat -f%z "$file_path")
  else
    local file_size=$(stat -c%s "$file_path")
  fi

  local total_chunks=$(( ($file_size + $CHUNK_SIZE - 1) / $CHUNK_SIZE ))
  local file_size_mb=$(awk "BEGIN {printf \"%.2f\", $file_size / 1048576}")

  log_info "Uploading $file_type: $file_name (${file_size_mb}MB, $total_chunks chunks)"

  # Create temporary directory for chunks
  local temp_dir=$(mktemp -d)

  # Split file into chunks
  split -b $CHUNK_SIZE "$file_path" "$temp_dir/chunk_"

  local chunk_index=0
  for chunk_file in "$temp_dir"/chunk_*; do
    printf "  Chunk %3d/%3d... " "$((chunk_index + 1))" "$total_chunks"

    if [ "$DEBUG_MODE" = "true" ]; then
      echo ""
      echo "DEBUG: SESSION_ID='$SESSION_ID'"
      echo "DEBUG: Uploading chunk to: $API_BASE/upload/chunk?uploadSessionId=$SESSION_ID&fileType=$file_type&chunkIndex=$chunk_index&totalChunks=$total_chunks&fileName=$file_name"
    fi

    # Base64 encode the chunk to a temp file so Java proxy can handle it as text/String
    # This prevents corruption when proxy reads binary data as String
    # Use temp file to avoid "Argument list too long" error
    CHUNK_BASE64_FILE=$(mktemp)
    base64 < "$chunk_file" > "$CHUNK_BASE64_FILE"

    RESPONSE=$(curl -s -X POST "$API_BASE/upload/chunk?uploadSessionId=$SESSION_ID&fileType=$file_type&chunkIndex=$chunk_index&totalChunks=$total_chunks&fileName=$file_name" \
      -H "Content-Type: text/plain" \
      -H "X-Chunk-Encoding: base64" \
      -d @"$CHUNK_BASE64_FILE")

    # Clean up temp file
    rm -f "$CHUNK_BASE64_FILE"

    if [ "$DEBUG_MODE" = "true" ]; then
      echo "DEBUG: Chunk response: $RESPONSE"
    fi

    SUCCESS=$(echo "$RESPONSE" | grep -o '"success":[^,}]*' | cut -d':' -f2)

    if [ "$SUCCESS" != "true" ]; then
      echo -e "${RED}FAILED${NC}"
      log_error "Failed to upload chunk $((chunk_index + 1))/$total_chunks"
      echo "DEBUG: SESSION_ID='$SESSION_ID'"
      echo "DEBUG: fileType='$file_type'"
      echo "DEBUG: chunkIndex='$chunk_index'"
      echo "DEBUG: totalChunks='$total_chunks'"
      echo "DEBUG: fileName='$file_name'"
      echo "$RESPONSE"
      rm -rf "$temp_dir"
      exit 1
    fi

    echo -e "${GREEN}OK${NC}"
    chunk_index=$((chunk_index + 1))
  done

  # Cleanup temporary directory
  rm -rf "$temp_dir"
  log_success "$file_type upload completed ($total_chunks chunks)"
  echo ""
}

#############################################################################
# STEP 2: Upload JAR file
#############################################################################
log_info "Step 2/5: Uploading JAR file..."
upload_file_in_chunks "$JAR_FILE" "jarFile"

#############################################################################
# STEP 3: Upload manifest file
#############################################################################
log_info "Step 3/5: Uploading manifest file..."
upload_file_in_chunks "$MANIFEST_FILE" "manifest"

#############################################################################
# STEP 4: Start async deployment
#############################################################################
log_info "Step 4/5: Starting async deployment..."

FINALIZE_RESPONSE=$(curl -s -X POST "$API_BASE/upload/finalize?uploadSessionId=$SESSION_ID&async=true" \
  -H "Content-Length: 0")

STATUS=$(echo "$FINALIZE_RESPONSE" | grep -o '"status":"[^"]*' | cut -d'"' -f4)

if [ "$STATUS" != "IN_PROGRESS" ]; then
  log_error "Failed to start deployment. Status: $STATUS"
  echo "$FINALIZE_RESPONSE"
  exit 1
fi

log_success "Deployment started successfully"
log_info "Step 5/5: Polling deployment status (max wait: ${MAX_WAIT}s)..."
echo ""

#############################################################################
# STEP 5: Poll deployment status
#############################################################################
elapsed=0
last_message=""

while [ $elapsed -lt $MAX_WAIT ]; do
  sleep $POLL_INTERVAL
  elapsed=$((elapsed + POLL_INTERVAL))

  STATUS_RESPONSE=$(curl -s "$API_BASE/deployment/status/$SESSION_ID" 2>/dev/null)

  if [ $? -ne 0 ]; then
    log_warning "Failed to fetch status, retrying..."
    continue
  fi

  CURRENT_STATUS=$(echo "$STATUS_RESPONSE" | grep -o '"status":"[^"]*' | cut -d'"' -f4)
  MESSAGE=$(echo "$STATUS_RESPONSE" | grep -o '"message":"[^"]*' | cut -d'"' -f4)
  PROGRESS=$(echo "$STATUS_RESPONSE" | grep -o '"progress":[0-9]*' | cut -d':' -f2)

  # Only print if message changed to reduce clutter
  if [ "$MESSAGE" != "$last_message" ]; then
    printf "  [%3ds] Status: %-15s Progress: %3s%% - %s\n" \
      "$elapsed" "$CURRENT_STATUS" "${PROGRESS:-0}" "$MESSAGE"
    last_message="$MESSAGE"
  fi

  # Check if deployment completed
  if [ "$CURRENT_STATUS" = "COMPLETED" ]; then
    echo ""
    log_success "Deployment completed successfully!"
    echo ""
    log_info "Deployment details:"
    echo "$STATUS_RESPONSE" | python -m json.tool 2>/dev/null || echo "$STATUS_RESPONSE"
    exit 0
  fi

  # Check if deployment failed
  if [ "$CURRENT_STATUS" = "FAILED" ]; then
    echo ""
    log_error "Deployment failed!"
    echo ""
    log_info "Error details:"
    echo "$STATUS_RESPONSE" | python -m json.tool 2>/dev/null || echo "$STATUS_RESPONSE"
    exit 1
  fi
done

# Timeout reached
echo ""
log_warning "Deployment timeout reached after ${MAX_WAIT}s"
log_info "The deployment may still be running. Check status manually:"
echo "  curl $API_BASE/deployment/status/$SESSION_ID"
exit 1
