#!/bin/bash

################################################################################
# BaoLife GCP Deployment Script
#
# This script deploys the BaoLife WebSocket backend to Google Cloud Platform
#
# Requirements:
#   - gcloud CLI installed and authenticated
#   - Appropriate GCP permissions
#   - Active GCP project
#
# Usage:
#   ./deploy-gcp.sh [options]
#
# Options:
#   --project PROJECT_ID       GCP project ID (required)
#   --environment ENV          Environment: dev, staging, or production (default: dev)
#   --region REGION            GCP region (default: us-central1)
#   --service-name NAME        Cloud Run service name (auto-set based on environment if not specified)
#   --db-instance NAME         Cloud SQL instance name (auto-set based on environment if not specified)
#   --db-password PASSWORD     Database root password (required)
#   --db-tier TIER             Cloud SQL tier (auto-set based on environment if not specified)
#   --min-instances NUM        Minimum instances (auto-set based on environment if not specified)
#   --max-instances NUM        Maximum instances (auto-set based on environment if not specified)
#   --skip-db                  Skip database creation (if already exists)
#   --skip-secrets             Skip secret creation (if already exist)
#   --ai-provider PROVIDER     AI provider: openai, together, mistral, or openrouter (default: env AI_PROVIDER or openai)
#   --help                     Show this help message
#
# AI provider API keys are read from local environment variables when creating
# secrets. For example:
#   OPENAI_API_KEY=sk-... ./deploy-gcp.sh --project PROJECT_ID --environment dev ...
################################################################################

set -euo pipefail

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

# Default configuration
ENVIRONMENT="dev"
REGION="us-central1"
SERVICE_NAME=""  # Will be set based on environment
DB_INSTANCE_NAME=""  # Will be set based on environment
DB_NAME="lifesim"
DB_USER="baolife"
DB_TIER=""  # Will be set based on environment
MIN_INSTANCES=""  # Will be set based on environment
MAX_INSTANCES=""  # Will be set based on environment
MEMORY=""  # Will be set based on environment
CONCURRENCY=""  # Will be set based on environment
STORAGE_SIZE=""  # Will be set based on environment
SKIP_DB=false
SKIP_SECRETS=false
PROJECT_ID=""
DB_PASSWORD=""
AI_PROVIDER="${AI_PROVIDER:-openai}"
OPENAI_MODEL="${OPENAI_MODEL:-gpt-4o-mini}"
TOGETHER_MODEL="${TOGETHER_MODEL:-Qwen/Qwen3-235B-A22B-Instruct-2507-tput}"
MISTRAL_MODEL="${MISTRAL_MODEL:-mistral-small-latest}"
OPENROUTER_MODEL="${OPENROUTER_MODEL:-mistralai/mistral-small-3.1-24b-instruct}"
IMAGE_GENERATION_PROVIDER="${IMAGE_GENERATION_PROVIDER:-imagen4}"

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        --project)
            PROJECT_ID="$2"
            shift 2
            ;;
        --environment)
            ENVIRONMENT="$2"
            if [[ ! "$ENVIRONMENT" =~ ^(dev|staging|production)$ ]]; then
                echo -e "${RED}Error: --environment must be dev, staging, or production${NC}"
                exit 1
            fi
            shift 2
            ;;
        --region)
            REGION="$2"
            shift 2
            ;;
        --service-name)
            SERVICE_NAME="$2"
            shift 2
            ;;
        --db-instance)
            DB_INSTANCE_NAME="$2"
            shift 2
            ;;
        --db-password)
            DB_PASSWORD="$2"
            shift 2
            ;;
        --db-tier)
            DB_TIER="$2"
            shift 2
            ;;
        --min-instances)
            MIN_INSTANCES="$2"
            shift 2
            ;;
        --max-instances)
            MAX_INSTANCES="$2"
            shift 2
            ;;
        --skip-db)
            SKIP_DB=true
            shift
            ;;
        --skip-secrets)
            SKIP_SECRETS=true
            shift
            ;;
        --ai-provider)
            AI_PROVIDER="$2"
            if [[ ! "$AI_PROVIDER" =~ ^(openai|together|mistral|openrouter)$ ]]; then
                echo -e "${RED}Error: --ai-provider must be openai, together, mistral, or openrouter${NC}"
                exit 1
            fi
            shift 2
            ;;
        --help)
            grep "^#" "$0" | grep -v "#!/bin/bash" | sed 's/^# //'
            exit 0
            ;;
        *)
            echo -e "${RED}Unknown option: $1${NC}"
            echo "Use --help for usage information"
            exit 1
            ;;
    esac
done

# Validate required parameters
if [[ -z "$PROJECT_ID" ]]; then
    echo -e "${RED}Error: --project is required${NC}"
    exit 1
fi

if [[ -z "$DB_PASSWORD" ]] && ([[ "$SKIP_DB" == false ]] || [[ "$SKIP_SECRETS" == false ]]); then
    echo -e "${RED}Error: --db-password is required unless both --skip-db and --skip-secrets are used${NC}"
    exit 1
fi

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

# Set environment-specific defaults
log_info "Configuring for $ENVIRONMENT environment..."

case "$ENVIRONMENT" in
    dev)
        SERVICE_NAME="${SERVICE_NAME:-baolife-backend-dev}"
        DB_INSTANCE_NAME="${DB_INSTANCE_NAME:-baolife-db-dev}"
        DB_TIER="${DB_TIER:-db-f1-micro}"
        MIN_INSTANCES="${MIN_INSTANCES:-0}"
        MAX_INSTANCES="${MAX_INSTANCES:-3}"
        MEMORY="${MEMORY:-512Mi}"
        CONCURRENCY="${CONCURRENCY:-40}"
        STORAGE_SIZE="${STORAGE_SIZE:-10GB}"
        ;;
    staging)
        SERVICE_NAME="${SERVICE_NAME:-baolife-backend-staging}"
        DB_INSTANCE_NAME="${DB_INSTANCE_NAME:-baolife-db-staging}"
        DB_TIER="${DB_TIER:-db-g1-small}"
        MIN_INSTANCES="${MIN_INSTANCES:-0}"
        MAX_INSTANCES="${MAX_INSTANCES:-5}"
        MEMORY="${MEMORY:-1Gi}"
        CONCURRENCY="${CONCURRENCY:-60}"
        STORAGE_SIZE="${STORAGE_SIZE:-10GB}"
        ;;
    production)
        SERVICE_NAME="${SERVICE_NAME:-baolife-backend-prod}"
        DB_INSTANCE_NAME="${DB_INSTANCE_NAME:-baolife-db-prod}"
        DB_TIER="${DB_TIER:-db-g1-small}"
        MIN_INSTANCES="${MIN_INSTANCES:-1}"
        MAX_INSTANCES="${MAX_INSTANCES:-10}"
        MEMORY="${MEMORY:-1Gi}"
        CONCURRENCY="${CONCURRENCY:-80}"
        STORAGE_SIZE="${STORAGE_SIZE:-20GB}"
        ;;
esac

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

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

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

secret_exists() {
    local secret_name="$1"
    gcloud secrets describe "$secret_name" --project="$PROJECT_ID" &>/dev/null
}

upsert_secret_from_env() {
    local env_var_name="$1"
    local secret_name="$2"
    local secret_value="${!env_var_name:-}"

    if [[ -z "$secret_value" ]]; then
        return 0
    fi

    log_info "Storing $env_var_name in Secret Manager as $secret_name"
    echo -n "$secret_value" | gcloud secrets create "$secret_name" \
        --data-file=- \
        --replication-policy="automatic" \
        --project="$PROJECT_ID" 2>/dev/null || \
    echo -n "$secret_value" | gcloud secrets versions add "$secret_name" \
        --data-file=- \
        --project="$PROJECT_ID"
}

add_secret_binding_if_available() {
    local cloud_run_env_var="$1"
    local secret_name="$2"

    if secret_exists "$secret_name"; then
        SECRET_BINDINGS="${SECRET_BINDINGS},${cloud_run_env_var}=${secret_name}:latest"
        return 0
    fi

    return 1
}

require_secret_binding() {
    local cloud_run_env_var="$1"
    local secret_name="$2"
    local local_env_hint="$3"

    if ! add_secret_binding_if_available "$cloud_run_env_var" "$secret_name"; then
        log_error "Missing required secret: $secret_name"
        log_error "Create it first, or export $local_env_hint and run without --skip-secrets."
        exit 1
    fi
}

# Set the GCP project
log_info "Setting GCP project to: $PROJECT_ID"
gcloud config set project "$PROJECT_ID"

################################################################################
# 1. Enable Required APIs
################################################################################
log_info "Enabling required GCP APIs..."
gcloud services enable \
    cloudbuild.googleapis.com \
    run.googleapis.com \
    sqladmin.googleapis.com \
    secretmanager.googleapis.com \
    vpcaccess.googleapis.com \
    servicenetworking.googleapis.com \
    compute.googleapis.com

log_success "APIs enabled"

################################################################################
# 2. Create Cloud SQL Instance
################################################################################
if [[ "$SKIP_DB" == false ]]; then
    log_info "Creating Cloud SQL MySQL instance: $DB_INSTANCE_NAME"

    # Check if instance already exists
    if gcloud sql instances describe "$DB_INSTANCE_NAME" --project="$PROJECT_ID" &>/dev/null; then
        log_warning "Cloud SQL instance $DB_INSTANCE_NAME already exists, skipping creation"
    else
        gcloud sql instances create "$DB_INSTANCE_NAME" \
            --database-version=MYSQL_8_0 \
            --tier="$DB_TIER" \
            --region="$REGION" \
            --root-password="$DB_PASSWORD" \
            --storage-type=SSD \
            --storage-size="$STORAGE_SIZE" \
            --storage-auto-increase \
            --backup-start-time=03:00 \
            --maintenance-window-day=SUN \
            --maintenance-window-hour=04 \
            --enable-bin-log \
            --project="$PROJECT_ID"

        log_success "Cloud SQL instance created"
    fi

    # Create database
    log_info "Creating database: $DB_NAME"
    gcloud sql databases create "$DB_NAME" \
        --instance="$DB_INSTANCE_NAME" \
        --project="$PROJECT_ID" || log_warning "Database may already exist"

    # Create database user
    log_info "Creating database user: $DB_USER"
    gcloud sql users create "$DB_USER" \
        --instance="$DB_INSTANCE_NAME" \
        --password="$DB_PASSWORD" \
        --project="$PROJECT_ID" || log_warning "User may already exist"

    log_success "Database setup complete"
else
    log_info "Skipping database creation (--skip-db specified)"
fi

################################################################################
# 3. Store Secrets in Secret Manager
################################################################################
if [[ "$SKIP_SECRETS" == false ]]; then
    log_info "Creating secrets in Secret Manager..."

    # DB Password
    echo -n "$DB_PASSWORD" | gcloud secrets create "${ENVIRONMENT}-db-password" \
        --data-file=- \
        --replication-policy="automatic" \
        --project="$PROJECT_ID" 2>/dev/null || \
    echo -n "$DB_PASSWORD" | gcloud secrets versions add "${ENVIRONMENT}-db-password" \
        --data-file=- \
        --project="$PROJECT_ID"

    # Generate JWT secret
    JWT_SECRET=$(openssl rand -base64 32)
    echo -n "$JWT_SECRET" | gcloud secrets create "${ENVIRONMENT}-jwt-secret" \
        --data-file=- \
        --replication-policy="automatic" \
        --project="$PROJECT_ID" 2>/dev/null || \
    echo -n "$JWT_SECRET" | gcloud secrets versions add "${ENVIRONMENT}-jwt-secret" \
        --data-file=- \
        --project="$PROJECT_ID"

    # AI provider and optional media provider keys. Only non-empty local env vars
    # are written; existing secrets are reused below when --skip-secrets is used.
    upsert_secret_from_env "OPENAI_API_KEY" "${ENVIRONMENT}-openai-api-key"
    upsert_secret_from_env "TOGETHER_API_KEY" "${ENVIRONMENT}-together-api-key"
    upsert_secret_from_env "MISTRAL_API_KEY" "${ENVIRONMENT}-mistral-api-key"
    upsert_secret_from_env "OPENROUTER_API_KEY" "${ENVIRONMENT}-openrouter-api-key"
    upsert_secret_from_env "FAL_AI_KEY" "${ENVIRONMENT}-fal-ai-key"
    upsert_secret_from_env "REPLICATE_API_TOKEN" "${ENVIRONMENT}-replicate-api-token"

    log_success "Secrets created"
else
    log_info "Skipping secret creation (--skip-secrets specified)"
fi

################################################################################
# 4. Build and Push Docker Image
################################################################################
log_info "Building Docker image..."

# Get the Cloud SQL connection name
DB_CONNECTION_NAME=$(gcloud sql instances describe "$DB_INSTANCE_NAME" \
    --project="$PROJECT_ID" \
    --format="value(connectionName)")

log_info "Cloud SQL connection name: $DB_CONNECTION_NAME"

# Build the active TypeScript backend using Cloud Build
IMAGE_NAME="gcr.io/$PROJECT_ID/$SERVICE_NAME"
gcloud builds submit ./server \
    --tag="$IMAGE_NAME" \
    --project="$PROJECT_ID"

log_success "Docker image built and pushed: $IMAGE_NAME"

################################################################################
# 5. Deploy to Cloud Run
################################################################################
log_info "Deploying to Cloud Run..."

CLOUD_RUN_ENV_VARS="ENVIRONMENT=$ENVIRONMENT,DB_NAME=$DB_NAME,DB_USER=$DB_USER,DB_HOST=/cloudsql/$DB_CONNECTION_NAME,AI_PROVIDER=$AI_PROVIDER,OPENAI_MODEL=$OPENAI_MODEL,TOGETHER_MODEL=$TOGETHER_MODEL,MISTRAL_MODEL=$MISTRAL_MODEL,OPENROUTER_MODEL=$OPENROUTER_MODEL,IMAGE_GENERATION_PROVIDER=$IMAGE_GENERATION_PROVIDER"
SECRET_BINDINGS="DB_PASSWORD=${ENVIRONMENT}-db-password:latest,JWT_SECRET=${ENVIRONMENT}-jwt-secret:latest"

case "$AI_PROVIDER" in
    openai)
        require_secret_binding "OPENAI_API_KEY" "${ENVIRONMENT}-openai-api-key" "OPENAI_API_KEY"
        ;;
    together)
        require_secret_binding "TOGETHER_API_KEY" "${ENVIRONMENT}-together-api-key" "TOGETHER_API_KEY"
        add_secret_binding_if_available "OPENAI_API_KEY" "${ENVIRONMENT}-openai-api-key" || true
        ;;
    mistral)
        require_secret_binding "MISTRAL_API_KEY" "${ENVIRONMENT}-mistral-api-key" "MISTRAL_API_KEY"
        add_secret_binding_if_available "OPENAI_API_KEY" "${ENVIRONMENT}-openai-api-key" || true
        ;;
    openrouter)
        require_secret_binding "OPENROUTER_API_KEY" "${ENVIRONMENT}-openrouter-api-key" "OPENROUTER_API_KEY"
        add_secret_binding_if_available "OPENAI_API_KEY" "${ENVIRONMENT}-openai-api-key" || true
        ;;
esac

add_secret_binding_if_available "FAL_AI_KEY" "${ENVIRONMENT}-fal-ai-key" || true
add_secret_binding_if_available "REPLICATE_API_TOKEN" "${ENVIRONMENT}-replicate-api-token" || true

# Deploy the service
gcloud run deploy "$SERVICE_NAME" \
    --image="$IMAGE_NAME" \
    --platform=managed \
    --region="$REGION" \
    --allow-unauthenticated \
    --port=8001 \
    --min-instances="$MIN_INSTANCES" \
    --max-instances="$MAX_INSTANCES" \
    --memory="$MEMORY" \
    --cpu=1 \
    --timeout=3600 \
    --concurrency="$CONCURRENCY" \
    --add-cloudsql-instances="$DB_CONNECTION_NAME" \
    --set-env-vars="$CLOUD_RUN_ENV_VARS" \
    --set-secrets="$SECRET_BINDINGS" \
    --project="$PROJECT_ID"

# Get the service URL
SERVICE_URL=$(gcloud run services describe "$SERVICE_NAME" \
    --platform=managed \
    --region="$REGION" \
    --project="$PROJECT_ID" \
    --format="value(status.url)")

log_success "Service deployed successfully!"

################################################################################
# 6. Configure Custom Domain (Optional)
################################################################################
log_info "To add a custom domain, run:"
echo "  gcloud run domain-mappings create --service=$SERVICE_NAME --domain=wss.lichun.app --region=$REGION"

################################################################################
# 7. Summary
################################################################################
echo ""
echo "=========================================="
echo -e "${GREEN}Deployment Complete!${NC}"
echo "=========================================="
echo ""
echo "Environment: $ENVIRONMENT"
echo "Service URL: $SERVICE_URL"
echo "WebSocket Endpoint: ${SERVICE_URL/https/wss}"
echo ""
echo "Cloud SQL Instance: $DB_INSTANCE_NAME"
echo "Database: $DB_NAME"
echo "Connection Name: $DB_CONNECTION_NAME"
echo "Tier: $DB_TIER"
echo ""
echo "Cloud Run Configuration:"
echo "  Memory: $MEMORY"
echo "  Min Instances: $MIN_INSTANCES"
echo "  Max Instances: $MAX_INSTANCES"
echo "  Concurrency: $CONCURRENCY"
echo ""
echo "To view logs:"
echo "  gcloud run logs read $SERVICE_NAME --region=$REGION --project=$PROJECT_ID"
echo ""
echo "To scale instances:"
echo "  gcloud run services update $SERVICE_NAME --min-instances=N --max-instances=M --region=$REGION"
echo ""
echo "To update the service (code changes only):"
echo "  ./deploy-gcp.sh --project=$PROJECT_ID --environment=$ENVIRONMENT --region=$REGION --skip-db --skip-secrets"
echo ""
echo "=========================================="
