#!/bin/bash
# Automated deployment for Remote Access API + Guacamole
# with automatic secure administrator generation

set -e  # Exit on error

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"

echo "=========================================="
echo "   Remote Access API Deployment"
echo "=========================================="
echo ""

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

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

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

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

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

# Check required commands
check_requirements() {
    log_info "Checking requirements..."
    
    if ! command -v docker &> /dev/null; then
        log_error "Docker not found! Please install Docker first."
        exit 1
    fi
    
    if ! command -v python3 &> /dev/null; then
        log_error "Python 3 not found! Please install Python 3."
        exit 1
    fi
    
    if ! docker compose version &> /dev/null; then
        log_error "Docker Compose V2 not found! Please install Docker Compose V2."
        exit 1
    fi
    
    log_success "All requirements met"
}

# Load environment variables
load_env() {
    log_info "Loading environment variables..."
    
    if [ ! -f ".env" ] && [ ! -f "production.env" ]; then
        log_error "No .env or production.env file found!"
        log_error "Please create one from encryption.env.example or production.env"
        exit 1
    fi
    
    # Use production.env by default
    ENV_FILE=".env"
    if [ -f "production.env" ]; then
        ENV_FILE="production.env"
        log_info "Using production.env"
    fi
    
    # Load variables
    set -a
    source "$ENV_FILE"
    set +a
    
    log_success "Environment loaded from $ENV_FILE"
}

# Check critical passwords
check_critical_passwords() {
    log_info "Checking critical passwords..."
    
    local has_issues=0
    
    # Check REDIS_PASSWORD
    if [ -z "$REDIS_PASSWORD" ] || [ "$REDIS_PASSWORD" == "redis_pass" ]; then
        log_error "REDIS_PASSWORD is not set or using default value!"
        log_error "Set a secure password in $ENV_FILE"
        has_issues=1
    fi
    
    # Check POSTGRES_PASSWORD
    if [ -z "$POSTGRES_PASSWORD" ] || [ "$POSTGRES_PASSWORD" == "guacamole_pass" ]; then
        log_error "POSTGRES_PASSWORD is not set or using default value!"
        log_error "Set a secure password in $ENV_FILE"
        has_issues=1
    fi
    
    # Check SYSTEM_ADMIN credentials
    if [ -z "$SYSTEM_ADMIN_USERNAME" ] || [ -z "$SYSTEM_ADMIN_PASSWORD" ]; then
        log_error "SYSTEM_ADMIN_USERNAME and SYSTEM_ADMIN_PASSWORD must be set!"
        log_error "Please update your $ENV_FILE file"
        has_issues=1
    fi
    
    if [ $has_issues -eq 1 ]; then
        log_error ""
        log_error "Critical passwords are missing or insecure!"
        log_error "Update the following in $ENV_FILE:"
        log_error "  - REDIS_PASSWORD=<secure_random_password>"
        log_error "  - POSTGRES_PASSWORD=<secure_random_password>"
        log_error "  - SYSTEM_ADMIN_PASSWORD=<secure_random_password>"
        log_error ""
        log_error "Generate secure passwords:"
        log_error "  openssl rand -base64 32"
        exit 1
    fi
    
    log_success "All critical passwords are set"
}

# Auto-generate admin if password is not default
generate_admin_sql() {
    log_info "Checking admin credentials..."
    
    # Check if default password is used
    if [ "$SYSTEM_ADMIN_PASSWORD" == "guacadmin" ] || \
       [ "$SYSTEM_ADMIN_PASSWORD" == "guacadmin_change_in_production" ] || \
       [[ "$SYSTEM_ADMIN_PASSWORD" == *"CHANGE_ME"* ]]; then
        log_warning "Default or placeholder password detected!"
        log_warning "Username: $SYSTEM_ADMIN_USERNAME"
        log_warning "Password: $SYSTEM_ADMIN_PASSWORD"
        log_warning ""
        log_warning "This is INSECURE for production!"
        log_warning "Using default 002-create-admin-user.sql"
        log_warning ""
        read -p "Continue anyway? (y/N): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            log_info "Deployment cancelled. Please update your credentials."
            exit 1
        fi
        return
    fi
    
    log_success "Custom password detected - generating secure admin SQL"
    log_info "Username: $SYSTEM_ADMIN_USERNAME"
    log_info "Password length: ${#SYSTEM_ADMIN_PASSWORD} characters"
    
    # Create backup of original SQL (if not already created)
    if [ -f "002-create-admin-user.sql" ] && [ ! -f "002-create-admin-user-DEFAULT-BACKUP.sql" ]; then
        log_info "Creating backup of default SQL..."
        cp 002-create-admin-user.sql 002-create-admin-user-DEFAULT-BACKUP.sql
        log_success "Backup created: 002-create-admin-user-DEFAULT-BACKUP.sql"
    fi
    
    # Generate new SQL
    log_info "Generating SQL with custom password..."
    python3 generate_guacamole_user.py \
        --username "$SYSTEM_ADMIN_USERNAME" \
        --password "$SYSTEM_ADMIN_PASSWORD" \
        --admin \
        --verify \
        > 002-create-admin-user-GENERATED.sql
    
    if [ $? -ne 0 ]; then
        log_error "Failed to generate SQL!"
        exit 1
    fi
    
    # Replace SQL
    mv 002-create-admin-user-GENERATED.sql 002-create-admin-user.sql
    log_success "Admin SQL generated and applied"
    log_info "File: 002-create-admin-user.sql (auto-generated)"
}

# Validate docker-compose.yml
check_compose_file() {
    log_info "Validating docker-compose.yml..."
    
    if docker compose config > /dev/null 2>&1; then
        log_success "docker-compose.yml is valid"
    else
        log_error "Invalid docker-compose.yml!"
        docker compose config
        exit 1
    fi
}

# Start containers
start_containers() {
    log_info "Starting containers..."
    
    # Stop existing containers (if any)
    docker compose down 2>/dev/null || true
    
    # Start
    docker compose up -d
    
    if [ $? -eq 0 ]; then
        log_success "Containers started successfully"
    else
        log_error "Failed to start containers!"
        exit 1
    fi
}

# Wait for services to be ready
wait_for_services() {
    log_info "Waiting for services to be ready..."
    
    # Wait for PostgreSQL
    log_info "Waiting for PostgreSQL..."
    for i in {1..30}; do
        if docker compose exec -T postgres pg_isready -U guacamole_user &>/dev/null; then
            log_success "PostgreSQL is ready"
            break
        fi
        if [ $i -eq 30 ]; then
            log_error "PostgreSQL failed to start!"
            docker compose logs postgres
            exit 1
        fi
        sleep 1
    done
    
    # Wait for Guacamole
    log_info "Waiting for Guacamole..."
    local guacamole_ready=0
    for i in {1..60}; do
        if curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/guacamole/ | grep -q "200\|302"; then
            log_success "Guacamole is ready"
            guacamole_ready=1
            break
        fi
        sleep 2
    done
    
    if [ $guacamole_ready -eq 0 ]; then
        log_warning "Guacamole might not be ready yet (timeout after 120s)"
        log_info "Check logs: docker compose logs guacamole"
    fi
    
    # Wait for Redis
    log_info "Waiting for Redis..."
    local redis_ready=0
    for i in {1..20}; do
        if docker compose exec -T redis redis-cli -a "$REDIS_PASSWORD" ping &>/dev/null | grep -q "PONG"; then
            log_success "Redis is ready"
            redis_ready=1
            break
        fi
        sleep 1
    done
    
    if [ $redis_ready -eq 0 ]; then
        log_warning "Redis might not be ready yet (timeout after 20s)"
    fi
    
    # Wait for API
    log_info "Waiting for API..."
    local api_ready=0
    for i in {1..45}; do
        if docker compose logs remote_access_api 2>&1 | grep -q "Application startup complete"; then
            log_info "API startup detected, checking health endpoint..."
            sleep 2  # Give it a moment to fully initialize
            
            # Check health endpoint
            if curl -s http://localhost:8000/api/health | grep -q '"overall_status":"ok"'; then
                log_success "API is ready and healthy"
                api_ready=1
                break
            elif curl -s http://localhost:8000/api/health | grep -q '"overall_status"'; then
                log_warning "API is running but some components have issues"
                log_info "Check: curl http://localhost:8000/api/health | jq"
                api_ready=1
                break
            fi
        fi
        sleep 2
    done
    
    if [ $api_ready -eq 0 ]; then
        log_error "API failed to start properly (timeout after 90s)"
        log_info "Check logs: docker compose logs remote_access_api"
        log_info "Last 30 lines:"
        docker compose logs --tail=30 remote_access_api
        exit 1
    fi
}

# Verify deployment
verify_deployment() {
    log_info "Verifying deployment..."
    
    # Check that admin user was created
    ADMIN_CHECK=$(docker compose exec -T postgres psql -U guacamole_user -d guacamole_db -t -c \
        "SELECT COUNT(*) FROM guacamole_user u 
         JOIN guacamole_entity e ON u.entity_id = e.entity_id 
         WHERE e.name = '$SYSTEM_ADMIN_USERNAME';" 2>/dev/null | tr -d ' ')
    
    if [ "$ADMIN_CHECK" == "1" ]; then
        log_success "Admin user '$SYSTEM_ADMIN_USERNAME' exists in database"
    else
        log_warning "Could not verify admin user in database"
    fi
    
    # Check API health endpoint
    log_info "Checking API health endpoint..."
    HEALTH_RESPONSE=$(curl -s http://localhost:8000/api/health)
    
    if echo "$HEALTH_RESPONSE" | grep -q '"overall_status":"ok"'; then
        log_success "API health check: OK"
        
        # Parse component statuses (if jq is available)
        if command -v jq &> /dev/null; then
            echo "$HEALTH_RESPONSE" | jq -r '.components | to_entries[] | "  - \(.key): \(.value.status)"' 2>/dev/null || true
        fi
    elif echo "$HEALTH_RESPONSE" | grep -q '"overall_status"'; then
        local status=$(echo "$HEALTH_RESPONSE" | grep -o '"overall_status":"[^"]*"' | cut -d'"' -f4)
        log_warning "API health check: $status (some components have issues)"
        
        if command -v jq &> /dev/null; then
            echo "$HEALTH_RESPONSE" | jq -r '.components | to_entries[] | "  - \(.key): \(.value.status)"' 2>/dev/null || true
        else
            log_info "Install 'jq' for detailed component status"
        fi
    else
        log_error "API health check failed!"
        log_info "Response: $HEALTH_RESPONSE"
        exit 1
    fi
    
    # Check API logs for authentication
    if docker compose logs remote_access_api 2>&1 | grep -q "System token refreshed successfully\|authenticated with system credentials"; then
        log_success "API successfully authenticated with system credentials"
    else
        log_warning "Could not verify API system authentication in logs"
        log_info "This may be normal if using cached tokens"
    fi
}

# Print deployment summary
print_summary() {
    echo ""
    echo "=========================================="
    echo "   Deployment Complete!"
    echo "=========================================="
    echo ""
    log_success "Services are running"
    echo ""
    echo "Access URLs:"
    echo "  - Guacamole UI: http://localhost:8080/guacamole/"
    echo "  - API Health: http://localhost:8000/api/health"
    echo "  - API Docs: http://localhost:8000/docs (if enabled)"
    echo ""
    echo "Admin Credentials:"
    echo "  - Username: $SYSTEM_ADMIN_USERNAME"
    echo "  - Password: ${SYSTEM_ADMIN_PASSWORD:0:3}***${SYSTEM_ADMIN_PASSWORD: -3} (length: ${#SYSTEM_ADMIN_PASSWORD})"
    echo ""
    echo "Useful Commands:"
    echo "  - View logs: docker compose logs -f"
    echo "  - API logs: docker compose logs -f remote_access_api"
    echo "  - Check health: curl http://localhost:8000/api/health | jq"
    echo "  - Stop: docker compose down"
    echo "  - Restart: docker compose restart"
    echo ""
    
    if [ -f "002-create-admin-user-DEFAULT-BACKUP.sql" ]; then
        log_info "Original SQL backed up to: 002-create-admin-user-DEFAULT-BACKUP.sql"
    fi
    
    echo ""
}

# Main deployment flow
main() {
    check_requirements
    load_env
    check_critical_passwords
    generate_admin_sql
    check_compose_file
    start_containers
    wait_for_services
    verify_deployment
    print_summary
}

# Run
main

