#!/bin/bash
# ==============================================================================
# RDM RSP API - Linux Server Deployment Script
# ==============================================================================
# Deploys the Docker application to a Linux server via SSH
#
# Prerequisites:
#   - SSH access to the target server
#   - Docker and Docker Compose installed on target server
#   - RSA key authentication configured (recommended)
#
# Usage:
#   ./deploy-to-linux.sh                    # Deploy using defaults
#   ./deploy-to-linux.sh --server 1.2.3.4   # Deploy to specific server
#   ./deploy-to-linux.sh --rollback         # Rollback to previous version
# ==============================================================================

set -e  # Exit on any error

# ==============================================================================
# Configuration - EDIT THESE VALUES
# ==============================================================================
REMOTE_HOST="${DEPLOY_HOST:-vmi2578493}"
REMOTE_USER="${DEPLOY_USER:-timothy}"
REMOTE_PORT="${DEPLOY_PORT:-22}"
REMOTE_PATH="${DEPLOY_PATH:-/var/www/eirs-projects/rdmapi.blouzatech.ng}"
SSH_KEY="${DEPLOY_SSH_KEY:-}"  # Optional: path to SSH key

IMAGE_NAME="rdm-rsp-api"
APP_URL="https://rdmapi.blouzatech.ng"
GIT_REPO="https://gitlab.com/blouza-tech/rdm-rsp-api.git"
BACKUP_COUNT=3  # Number of backups to keep

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

# ==============================================================================
# Functions
# ==============================================================================

print_header() {
    echo -e "${BLUE}"
    echo "=============================================================================="
    echo " RDM RSP API - Production Deployment"
    echo "=============================================================================="
    echo -e "${NC}"
}

print_step() {
    echo -e "${GREEN}[STEP]${NC} $1"
}

print_warning() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

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

print_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

# SSH command wrapper
ssh_cmd() {
    local ssh_opts="-o StrictHostKeyChecking=no -o ConnectTimeout=10"
    if [[ -n "$SSH_KEY" ]]; then
        ssh_opts="$ssh_opts -i $SSH_KEY"
    fi
    ssh $ssh_opts -p "$REMOTE_PORT" "${REMOTE_USER}@${REMOTE_HOST}" "$@"
}

# SCP command wrapper
scp_cmd() {
    local scp_opts="-o StrictHostKeyChecking=no -o ConnectTimeout=10"
    if [[ -n "$SSH_KEY" ]]; then
        scp_opts="$scp_opts -i $SSH_KEY"
    fi
    scp $scp_opts -P "$REMOTE_PORT" "$@"
}

check_prerequisites() {
    print_step "Checking prerequisites..."

    # Check local Docker
    if ! command -v docker &> /dev/null; then
        print_error "Docker is not installed locally"
        exit 1
    fi

    # Check SSH connectivity
    if ! ssh_cmd "echo 'SSH connection successful'" &> /dev/null; then
        print_error "Cannot connect to ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PORT}"
        print_info "Ensure SSH access is configured and the server is reachable"
        exit 1
    fi

    # Check remote Docker
    if ! ssh_cmd "docker --version" &> /dev/null; then
        print_error "Docker is not installed on the remote server"
        exit 1
    fi

    # Check remote Docker Compose
    if ! ssh_cmd "docker compose version" &> /dev/null; then
        print_error "Docker Compose is not available on the remote server"
        exit 1
    fi

    print_info "All prerequisites met"
}

check_env_file() {
    if [[ ! -f ".env" ]]; then
        print_error ".env file not found"
        print_info "Create .env from .env.example and configure it:"
        print_info "  cp .env.example .env"
        print_info "  # Edit .env with production values"
        exit 1
    fi

    # Check for placeholder values
    if grep -q "your-server-ip" .env || grep -q "your-database" .env; then
        print_error ".env contains placeholder values"
        print_info "Please update DB_CONNECTION in .env file"
        exit 1
    fi
}

build_image() {
    print_step "Building Docker image locally..."

    docker build -t "${IMAGE_NAME}:latest" .

    print_info "Image built successfully"
}

save_and_transfer_image() {
    print_step "Saving Docker image..."

    local image_file="/tmp/${IMAGE_NAME}.tar"
    docker save "${IMAGE_NAME}:latest" -o "$image_file"

    print_step "Transferring image to server (this may take a while)..."

    scp_cmd "$image_file" "${REMOTE_USER}@${REMOTE_HOST}:/tmp/"

    print_step "Loading image on server..."

    ssh_cmd "docker load -i /tmp/${IMAGE_NAME}.tar && rm /tmp/${IMAGE_NAME}.tar"

    rm -f "$image_file"

    print_info "Image transferred and loaded"
}

create_remote_directories() {
    print_step "Creating remote directories..."

    ssh_cmd "mkdir -p ${REMOTE_PATH}/{data/logs,backups}"

    print_info "Directories created"
}

backup_current_deployment() {
    print_step "Backing up current deployment..."

    local backup_name="backup-$(date +%Y%m%d-%H%M%S)"

    ssh_cmd "
        if [[ -f ${REMOTE_PATH}/docker-compose.yml ]]; then
            mkdir -p ${REMOTE_PATH}/backups/${backup_name}
            cp ${REMOTE_PATH}/docker-compose.yml ${REMOTE_PATH}/backups/${backup_name}/
            cp ${REMOTE_PATH}/.env ${REMOTE_PATH}/backups/${backup_name}/ 2>/dev/null || true
            docker images ${IMAGE_NAME}:latest --format '{{.ID}}' > ${REMOTE_PATH}/backups/${backup_name}/image-id.txt
            echo '${backup_name}' > ${REMOTE_PATH}/backups/latest

            # Keep only last ${BACKUP_COUNT} backups
            cd ${REMOTE_PATH}/backups
            ls -dt backup-* 2>/dev/null | tail -n +$((${BACKUP_COUNT}+1)) | xargs rm -rf 2>/dev/null || true
        fi
    "

    print_info "Backup created: ${backup_name}"
}

transfer_config_files() {
    print_step "Transferring configuration files..."

    # Transfer docker-compose.yml
    scp_cmd "docker-compose.yml" "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}/"

    # Transfer .env file
    scp_cmd ".env" "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}/"

    # Secure .env file permissions
    ssh_cmd "chmod 600 ${REMOTE_PATH}/.env"

    print_info "Configuration files transferred"
}

deploy_application() {
    print_step "Deploying application..."

    ssh_cmd "
        cd ${REMOTE_PATH}

        # Stop existing container gracefully
        docker compose down --timeout 30 || true

        # Start new container
        docker compose up -d

        # Wait for container to start
        sleep 5

        # Show status
        docker compose ps
    "

    print_info "Application deployed"
}

verify_deployment() {
    print_step "Verifying deployment..."

    local max_attempts=30
    local attempt=1
    local health_url="http://localhost:${API_PORT:-80}/swagger/index.html"

    while [[ $attempt -le $max_attempts ]]; do
        local health_status=$(ssh_cmd "curl -sf ${health_url} 2>/dev/null && echo 'OK' || echo 'UNHEALTHY'")

        if [[ "$health_status" == *"OK"* ]]; then
            print_info "Health check passed!"
            return 0
        fi

        echo -n "."
        sleep 2
        ((attempt++))
    done

    echo ""
    print_error "Health check failed after ${max_attempts} attempts"

    print_step "Showing container logs..."
    ssh_cmd "docker compose -f ${REMOTE_PATH}/docker-compose.yml logs --tail=50 api"

    return 1
}

rollback() {
    print_step "Rolling back to previous version..."

    ssh_cmd "
        cd ${REMOTE_PATH}

        if [[ ! -f backups/latest ]]; then
            echo 'No backup found to rollback to'
            exit 1
        fi

        backup_name=\$(cat backups/latest)
        backup_dir=\"backups/\${backup_name}\"

        if [[ ! -d \"\$backup_dir\" ]]; then
            echo \"Backup directory not found: \$backup_dir\"
            exit 1
        fi

        echo \"Rolling back to: \$backup_name\"

        # Stop current container
        docker compose down --timeout 30 || true

        # Restore configuration
        cp \"\${backup_dir}/docker-compose.yml\" ./ 2>/dev/null || true
        cp \"\${backup_dir}/.env\" ./ 2>/dev/null || true

        # Start with previous configuration
        docker compose up -d

        echo 'Rollback complete'
    "

    verify_deployment
}

cleanup_old_images() {
    print_step "Cleaning up old Docker images on server..."

    ssh_cmd "docker image prune -f"

    print_info "Cleanup complete"
}

show_deployment_info() {
    echo ""
    echo -e "${GREEN}=============================================================================="
    echo " DEPLOYMENT SUCCESSFUL"
    echo "==============================================================================${NC}"
    echo ""
    echo "Server:        ${REMOTE_USER}@${REMOTE_HOST}"
    echo "Path:          ${REMOTE_PATH}"
    echo "API URL:       ${APP_URL}"
    echo "Swagger UI:    ${APP_URL}/swagger"
    echo "Git Repo:      ${GIT_REPO}"
    echo ""
    echo "Commands:"
    echo "  View logs:     ssh ${REMOTE_USER}@${REMOTE_HOST} 'docker compose -f ${REMOTE_PATH}/docker-compose.yml logs -f api'"
    echo "  Restart:       ssh ${REMOTE_USER}@${REMOTE_HOST} 'docker compose -f ${REMOTE_PATH}/docker-compose.yml restart api'"
    echo "  Stop:          ssh ${REMOTE_USER}@${REMOTE_HOST} 'docker compose -f ${REMOTE_PATH}/docker-compose.yml down'"
    echo "  Rollback:      ./deploy-to-linux.sh --rollback"
    echo ""
}

show_usage() {
    echo "Usage: $0 [OPTIONS]"
    echo ""
    echo "Options:"
    echo "  (none)              Full deployment (build, transfer, deploy)"
    echo "  --server IP         Specify target server IP"
    echo "  --user USER         Specify SSH user (default: root)"
    echo "  --port PORT         Specify SSH port (default: 22)"
    echo "  --path PATH         Specify deployment path (default: /opt/rdm-rsp-api)"
    echo "  --key PATH          Specify SSH key path"
    echo "  --rollback          Rollback to previous version"
    echo "  --verify-only       Only verify current deployment"
    echo "  --help              Show this help message"
    echo ""
    echo "Environment Variables:"
    echo "  DEPLOY_HOST         Target server IP"
    echo "  DEPLOY_USER         SSH user"
    echo "  DEPLOY_PORT         SSH port"
    echo "  DEPLOY_PATH         Deployment path"
    echo "  DEPLOY_SSH_KEY      SSH key path"
}

# ==============================================================================
# Argument Parsing
# ==============================================================================

VERIFY_ONLY=false
DO_ROLLBACK=false

while [[ $# -gt 0 ]]; do
    case $1 in
        --server)
            REMOTE_HOST="$2"
            shift 2
            ;;
        --user)
            REMOTE_USER="$2"
            shift 2
            ;;
        --port)
            REMOTE_PORT="$2"
            shift 2
            ;;
        --path)
            REMOTE_PATH="$2"
            shift 2
            ;;
        --key)
            SSH_KEY="$2"
            shift 2
            ;;
        --rollback)
            DO_ROLLBACK=true
            shift
            ;;
        --verify-only)
            VERIFY_ONLY=true
            shift
            ;;
        --help)
            show_usage
            exit 0
            ;;
        *)
            print_error "Unknown option: $1"
            show_usage
            exit 1
            ;;
    esac
done

# ==============================================================================
# Main
# ==============================================================================

print_header

# Validate configuration
if [[ "$REMOTE_HOST" == "your-server-ip" ]]; then
    print_error "Please configure REMOTE_HOST (server IP)"
    print_info "Use --server IP or set DEPLOY_HOST environment variable"
    exit 1
fi

print_info "Target: ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PORT}"
print_info "Path:   ${REMOTE_PATH}"
echo ""

check_prerequisites

if [[ "$DO_ROLLBACK" == true ]]; then
    rollback
    exit 0
fi

if [[ "$VERIFY_ONLY" == true ]]; then
    verify_deployment
    exit 0
fi

check_env_file
build_image
create_remote_directories
backup_current_deployment
save_and_transfer_image
transfer_config_files
deploy_application

if verify_deployment; then
    cleanup_old_images
    show_deployment_info
else
    print_error "Deployment verification failed"
    print_warning "Consider rolling back: ./deploy-to-linux.sh --rollback"
    exit 1
fi
